• SDK
  • OIDC

シンプルなクライアントサイドOIDC SDKを実装する

Logtoは、さまざまなプラットフォーム向けの多種多様なSDKを提供しています。 公式のSDKを使用するだけでなく、コミュニティの開発者が自分自身で使いやすいSDKを開発することを推奨しています。この記事では、OIDC用の基本的なクライアントサイドSDKの構築方法を説明します。

Simeng
Simeng
Developer

導入

Logtoは、開発者やビジネスグループに包括的なCustomer Identity and Access Management (CIAM)ソリューションを提供しています。 さまざまなプラットフォームやアプリケーションフレームワークに対応した幅広いすぐに使用できるSDKを提供しています。 Logtoクラウドサービスと組み合わせて、数分であなたのアプリケーションに対するユーザー認可フローを非常に安全に確立することができます。 開発者コミュニティから生まれた企業であるLogtoは、コミュニティ参加を重視し、価値を見いだしています。 公式に開発されたLogto SDKに加えて、コミュニティの開発者がさらに多様で使いやすいSDKを作り出すことで専門知識を貢献することを、我々は常に奨励し、歓迎しています。 これにより、さまざまなプラットフォームやフレームワークの独特のニーズを満たすことができます。 本記事では、OIDC標準認証SDKの実装方法を手順を追って簡単に紹介します。

コンテキスト

OpenID Connect (OIDC)フローは、OAuth 2.0フレームワークを基礎とした認証プロトコルで、IDの確認と一元サインオンの機能を提供します。 それにより、ユーザーはアプリケーションで自身を認証し、プライベートリソースへの更なるアクセスを安全に許可されます。 詳細はOIDC仕様を参照してください。

ワークフロー

標準の認可コードフローには以下のステップが含まれます:

Authentication flow

  1. ユーザーがサインインリクエストを初期化します: 匿名のユーザーがパブリックエントランスからあなたのアプリケーションに来ます。 対象は認証を受け、さらにサードパーティのアプリケーションやサービス上の保護されたリソースへのアクセスをリクエストすることができます。
  2. ユーザー認証: クライアントアプリは認証URIを生成し、認証サーバーにリクエストを送信します。 これにより、ユーザーがそのサインインページにリダイレクトされます。 ユーザーはさまざまなサインイン方法を使用してサインインページと対話し、認証サーバーによって認証されます。
  3. サインインコールバックの処理: 認証が成功すると、ユーザーは認証ステータスとリクエストされた認可データにリンクした関連する許可を含む authorization_codeが付与された状態でアプリケーションにリダイレクトされます。
  4. トークン交換: 上記のリダイレクトアドレスから抽出された authorization_codeを使用してトークン交換をリクエストします。 返信として以下の内容が得られます:
    • id_token:認証済みユーザーに関するID情報を含むデジタル署名付きJWT。
    • access_token:ユーザーの基本情報エンドポイントにアクセスするために使用できる不透明な access_token
    • refresh_token:ユーザーが access_tokenと連続的な交換を維持することを許可する資格トークン。

Authorization flow

  1. ユーザー情報の取得: アプリケーションは初期トークン交換フローから得られた不透明な access_tokenを利用してUserInfoエンドポイントへの追加のリクエストを実施することで、ユーザー情報の詳細を取得できます。 これにより、ユーザーの電子メールアドレスやプロフィール画像などの詳しい情報を取得することが可能になります。
  2. 保護されたリソースへのアクセス権を付与する: 必要に応じて、アプリケーションは refresh_tokenresourcescopeパラメータを組み合わせてトークン交換エンドポイントへの追加のリクエストを実行し、ユーザーが目的のリソースにアクセスするための独自の access_tokenを取得することができます。 このプロセスは、保護されたリソースにアクセスするための必要な認可情報を含むJWTフォーマットの access_tokenを発行する結果となります。

実装

私たちは@logto/client JavaScript SDKの中のいくつかの設計戦略に従って、あなた自身のクライアントアプリケーションのためのシンプルなSDKを実装するプロセスを示します。 あなたが使用しているクライアントフレームワークによって、詳細なコード構造が異なるかもしれないことを覚えておいてください。 自分自身のSDKプロジェクトの例として、任意のLogto公式SDKを選択して自由に使用してください。

プレビュー

Constructor

コンストラクターは、logtoConfigを入力として受け取るべきです。 これにより、このSDKを通じて認証接続を確立するために必要なすべての設定が提供されます。

SDKの使用にあたり、プラットフォームまたはフレームワークによっては、永続的なローカルストレージインスタンスをコンストラクターに渡すことができるかもしれません。 このストレージインスタンスは、認証関連のトークンや秘密を保存するために使用されます。

ユーザー認証の初期化

認証リクエストURLを生成する前に、セキュアなプロセスを確保するためのいくつかの準備ステップを完了することが必要です。

認証サーバーからのOIDC設定の取得

認証サーバーの発見エンドポイントからOIDC設定を取得するためのプライベートメソッド getOidcConfigsを定義します。 OIDC設定のレスポンスには、クライアントが認証サーバーとやり取りできるようにするためのすべてのメタデータ情報、エンドポイントの位置、およびサーバーの機能が含まれています。 (詳細はOAuth OAuth Authorization Server Metadata Specsを参照してください。)

PKCEジェネレータ

PKCE(Proof Key for Code Exchange)検証フローはすべてのパブリッククライアント認可コード交換フローにとって不可欠です。 これにより、authorization_codeの傍受攻撃のリスクを軽減します。 したがって、すべてのパブリッククライアントアプリケーション(例:ネイティブアプリ、SPA)の認可リクエストには code_challengecode_verifierが必要です。

実装方法は使用している言語やフレームワークにより異なるかもしれません。詳細な定義についてはcode_challengecode_verifierの仕様を参照してください。

stateパラメータの生成

認可フローにおいて、state parameterは、クライアントによって送信される認可リクエストに含まれるランダムに生成された値です。 これはクロスサイトリクエストフォージェリ(CSRF)攻撃を防ぐためのセキュリティ策として機能します。

中間セッション情報の保存

ユーザーが認証され、クライアント側にリダイレクトされた後に検証の目的で保存が必要ないくつかのパラメーターがあります。 私たちは、これらの中間パラメーターをストレージに設定する方法を実装していきます。

サインイン

上記で実装したすべてをまとめて、ユーザーサインインURLを生成し、ユーザーを認証サーバーにリダイレクトして認証を行うメソッドを定義します。

ユーザーのサインインコールバックの処理

前のセクションで、ユーザーの認証のためのURLを生成するサインインメソッドを作成しました。 このURLには、クライアントアプリからの認証フローを開始するために必要なすべてのパラメーターが含まれています。 このメソッドはユーザーを認証サーバーのサインインページにリダイレクトし、認証を行います。 サインインが成功すると、エンドユーザーは上記で提供したredirect_uriの場所にリダイレクトされます。 すべての必要なパラメーターはredirect_uriに付随して、次のトークン交換フローを完了します。

コールバックURLの抽出と検証

この検証ステップは、偽造された認可コールバックの攻撃を防ぐために非常に重要です。 コールバックURLは MUST トークン交換リクエストを認証サーバーに送信する前に慎重に検証される必要があります。 まず、アプリストレージから保存したsignInSessionデータを取り出す必要があります。

次に、トークン交換リクエストを送信する前にコールバックURLのパラメータを検証します。

  • 以前に保存した redirectUriを使用して、callbackUriが認証サーバーに送信したものと同じであることを確認します。
  • 以前に保存した stateを使用して、戻された状態が我々が認証サーバーに送信したものと同じであることを確認します。
  • 認証サーバーから返されたエラーが存在するかをチェックします
  • 返された authorization_codeの存在を確認します

トークン交換リクエストの送信

ユーザー認証フローの最終ステップとして、戻された authorization_codeを使用してトークン交換リクエストを送信し、必要な認可トークンを取得します。 リクエストパラメーターの定義についての詳細は、token exchange specificationを参照してください。

  • code: コールバックURIから受け取った authorization_code
  • clientId: アプリケーションID
  • redirectUri: ユーザーに対してサインインURLを生成する際に使用した同じ値。
  • codeVerifier: PKCEコード検証器。 redirectUriと同様に、認証サーバーはこの値と以前に送信した値を比較し、着信トークン交換リクエストの検証を保証します。

サインインコールバックの処理

私たちが持っているすべてをまとめましょう。つまり、signInCallback処理メソッドを構築します:

結果として、トークン交換リクエストは以下のトークンを返します:

  • id_token:OIDC idToken、JSON Web Token (JWT)で認証されたユーザーに関するID情報を含む。 id_tokenはユーザーの認証ステータスのSingle Source of Truth(SSOT)としても使用できます。
  • access_token:認証サーバーがデフォルトで返す認可コード。 認証されたユーザー情報を取得するためにユーザー情報エンドポイントを呼び出すことができます。
  • refresh_token:(認可リクエストにoffline_accessスコープが存在する場合) このリフレッシュトークンにより、クライアントアプリケーションはユーザーに再認証を求めることなく新しいアクセストークンを取得することができ、リソースへの長期間のアクセスを提供します。
  • expires_in:アクセストークンが有効である期間、秒単位。

IDトークンの検証

id_tokenからの主張の検証と抽出は、認証プロセスにおいて重要なステップであり、トークンの真正性と完全性を確保します。 idTokenの検証に関与する主要なステップは以下の通りです。

  • シグネチャ検証: id_tokenは認証サーバーによってそのプライベートキーを使用してデジタルにサインされています。 クライアントアプリケーションは認証サーバーの公開キーを使用して署名を検証する必要があります。 これにより、トークンが改ざんされていないこと、またトークンが確かに正当な認証サーバーによって発行されたことを確認します。
  • 発行者の検証: id_token内の "iss"(issuer)クレームが期待値と一致することを確認し、トークンが正しい認証サーバーによって発行されたことを示します。
  • オーディエンス検証: id_token内の "aud"(audience)クレームがクライアントアプリケーションのクライアントIDと一致することを確認し、トークンがクライアントのために提供されることを確認します。
  • 有効期限のチェック: id_token内の "iat"(issued at)クレームが現在時刻を過ぎていないことを確認し、トークンがまだ有効であることを確認します。 ネットワークトランザクションコストがあるため、受信したトークンのiatクレームを検証する際は、発行時間の許容値を設定する必要があります。

戻されたid_tokenは標準的なJSON Web Token (JWT)です。 使用しているフレームワークにより、トークンの検証とデコードを補助する便利なJWTトークン検証プラグインを多数見つけることができます。 この例では、トークンの検証とデコードを容易にするために、JavaScript SDKでjoseを使用します。

ユーザー情報の取得

ユーザーの認証に成功した後、認証サーバーが発行したOIDC id_tokenから基本的なユーザー情報を取得することができます。 しかし、パフォーマンス上の考慮から、JWTトークンの内容は制限されています。詳細なユーザープロファイル情報を得るためには、OIDC準拠の認証サーバーはユーザー情報エンドポイントを提供します。 このエンドポイントは、特定のユーザープロファイルスコープをリクエストすることで、追加のユーザープロファイルデータを取得することを可能にします。

特定のAPIリソースを示すものなくトークン交換エンドポイントを呼び出すと、認証サーバーはデフォルトで不透明型の access_tokenを発行します。 このaccess_tokenは、基本的なユーザープロファイルデータを取得するためのユーザー情報エンドポイントにアクセスすることができます。

保護リソース認可のためのアクセストークンの取得

ほとんどの場合、クライアントアプリケーションはユーザー認証だけでなく、特定の保護されたリソースやAPIエンドポイントへのユーザー認可も必要とします。 ここでは、ログイン中に取得した refresh_tokenを使用して、特定のリソースを管理するために特別に付与された access_token(s)を取得します。 これにより、保護されたAPIにアクセスすることが可能になります。

まとめ

クライアントサイドアプリのユーザー認証および認可プロセスのための主要なメソッドの実装を提供しました。 あなたの特定のシナリオにより、適切にSDKのロジックを整理および最適化することができます。 異なるプラットフォームおよびフレームワークにより、変動が存在することに注意してください。

詳しい内容は、Logtoが提供するSDKパッケージを探索してください。 私たちは、より多くのユーザーが開発に参加し、私たちとディスカッションに参加することを奨励します。 あなたのフィードバックや貢献は、我々がSDKの機能を強化し、拡大するうえで非常に評価されています。

付録

予約されたスコープ

初期のauthリクエスト中に渡す必要があるLogto予約スコープ。 これらのスコープは、OIDC予約またはLogto予約の基本的なスコープで、成功した認可フローを完成させるためのものです。

Scope nameDescription
openid成功した認証の後に'token`を付与するために必要です。
offline-accessクライアントアプリケーションがスクリーンオフの状態で access_tokenを更新することを許可する refresh_tokenを付与するために必要です。
profile基本ユーザー情報へのアクセスが必要な場合

Logto Config

Property nameTypeRequiredDescriptionDefault Value
appIdstringtrueユニークなアプリケーション識別子。 クライアントアプリケーションを識別するために認証サーバーによって生成されます。
appSecretstringアプリケーションの秘密は、アプリケーションIDとともに、リクエスト者の身元を確認するために使用されます。 それはGo WebやNext.js web appsのような秘密のクライアントにとって必要であり、ネイティブアプリケーションやシングルページアプリケーション(SPA)のような公開クライアントにとってはオプションです。
endpointstringtrue認証サーバールートエンドポイント。 このプロパティは、認可リクエスト.endpointを生成するために幅広く使用されます。
scopesstring listユーザーが特定の保護されたリソースにアクセスするために付与される可能性がある必要なリソーススコープを示します。[reservedScopes]
resourcesstring listユーザーがアクセスをリクエストする可能性があるすべての保護されたリソースインジケータ

ユーティリティメソッド

generateRandomString