OIDC Basics

はじめに

このドキュメントは、Authlete APIs を使用して、認可コードフロー をサポートする OpenID Connect (OIDC) アイデンティティプロバイダー (IdP) サーバーを実装する基本的な使用方法を説明するためのチュートリアルです。

このチュートリアルを完了すると、以下を実施できます:

  • 認可サーバーから Authlete へのリクエストをシミュレーションしながら、Authlete API へのリクエストを送信します。
  • 認可リクエストで追加のクレームを含む発行者識別子の値を Authlete 管理コンソールに設定し、それらが ID トークンからデコードされる様子を確認します。

認可コードフローのコンポーネント

一般的な Authlete の実装では、認可サーバーのミドルウェアが Authlete API へのリクエストの送信およびレスポンスの処理を担当します。このチュートリアルでは、bash/zsh の curl コマンドを使用してこれらのリクエストを直接行います。もちろん、PowerShell や Postman など、別の HTTP クライアントを使用することもできますが、その場合は手順を適宜調整する必要があります。

flowchart LR subgraph EndUser [エンドユーザー] userAgent["ユーザーエージェント (N/A)"] resourceOwner["リソースオーナー (N/A)"] end subgraph APIClient [API クライアント] client["クライアント (N/A)"] end subgraph APIServer [API サーバー] authServer["認可サーバー/IdP (curl)"] resourceServer["リソースサーバー (curl)"] authAdmin["Authlete 管理者"] end subgraph Authlete [Authlete] mgmtConsole["Authlete 管理コンソール"] authAPI["Authlete API"] end resourceOwner --> userAgent userAgent -- "クライアントへのアクセス" --> client userAgent -- "認可リクエスト (ユーザー認証と同意)" --> authServer client -- "トークンリクエスト" --> authServer client -- "API リクエスト" --> resourceServer %% API サーバーの Authlete とのやり取り authAdmin -- "サービス/クライアント管理" --> mgmtConsole mgmtConsole -- "API リクエスト" --> authAPI authServer -- "API リクエスト" --> authAPI resourceServer -- "API リクエスト" --> authAPI

この OAuth フロー内で各コンポーネントがどのように連携するかを理解するために、各コンポーネントの完全修飾ドメイン名 (FQDN) を以下に示します。認可サーバーとクライアントの FQDN は参考用に作成されたものであり、実際の実装では適切な値に置き換える必要があります

コンポーネント FQDN
Authlete API US Cluster us.authlete.com
Authlete 管理コンソール console.authlete.com
認可サーバー as.example.com
クライアント client.example.org
リソースサーバー N/A

環境設定

Authlete API サービスを作成し、サービスにクライアントを登録する方法については、「Authlete のサインアップとサービスの作成」を参照してください。

サービス ID, サービス アクセストークン, そしてクライアントシークレットの値を書き留めるのを忘れないようにしてください。

すでに他の Authlete チュートリアルを完了している場合、既存のサービスを再利用できます。そうでない場合は、以下の値を使用してサービスを作成し、他のすべてのフィールドはデフォルトのままにしてください。

フィールド
API クラスター 🇺🇸 US
サービス名 Demo AS
サービスの詳細情報 Example authorization service

以下の値を使用してクライアントを作成し、他のすべてのフィールドはデフォルトのままにしてください。

フィールド
クライアント名 Demo OIDC Client
クライアントの詳細情報 Example client for OIDC tutorial
クライアントタイプ 機密
クライアント名、詳細、タイプを設定した Authlete クライアント

クライアントを作成したら、クライアント設定 > エンドポイント > 基本設定に移動します。リダイレクト URI セクションで [追加] をクリックし、クライアントが認可レスポンスを受け取る URI を入力して保存します。

以下はクライアントを作成したときに生成または指定されたプロパティの例です。これらの値は、認可コードフローの一環としてリクエストを行う際に必要となります。環境設定セクションで記録した値を使用してください。

項目
サービス ID 自動生成 (例: 10738933707579)
サービスアクセストークン 自動生成 (例: Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ)
クライアント ID 自動生成 (例: 12898884596863)
クライアントシークレット 自動生成 (例: -olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg)
クライアントタイプ 機密
リダイレクト URI https://client.example.org/cb/example.com
クライアント認証方式 CLIENT_SECRET_BASIC

これで、この環境を使用して OIDC 認可コードフローを試す準備が整いました。

ウォークスルー

以下のシーケンス図を提供して、コードフローに関与する各ステップを理解できるようにしています。このウォークスルー内の位置を確認するため、対応する番号を使用してステップを識別できます。

sequenceDiagram autonumber participant RO as リソースオーナー participant UA as ユーザーエージェント participant C as クライアント participant AS as 認可サーバー participant RS as リソースサーバー participant API as Authlete API RO ->> UA: 開始 UA ->> C: リクエストを送信 C -->> UA: 認可リクエスト UA ->> AS: リクエストを転送 AS ->> API: POST /auth/authorization API -->> AS: 処理許可
(チケットを含む) AS -->> UA: ユーザー認証と同意ページ RO <<->> UA: 資格情報を入力 UA ->> AS: ログインと同意 AS ->> API: POST /auth/authorization/issue
(チケットを含む) API -->> AS: 認可レスポンスコンテンツ
(認可コードを含む) AS -->> UA: 認可レスポンス UA ->> C: レスポンスを転送 C ->> AS: トークンリクエスト
(認可コード付き) AS ->> API: POST /auth/token API -->> AS: トークンレスポンスコンテンツ
(ID トークンとアクセストークンを含む) AS -->> C: トークンレスポンス

クライアントから認可サーバーへの認可リクエスト

以下の値を例としてリクエストのパラメータに使用します (前述の通り)。

項目 説明
client_id 12898884596863 登録済みクライアント ID
response_type code OIDC 認可コードフローを示す値 (scopeopenid を含む場合)
redirect_uri https://client.example.org/cb/example.com 登録済みリダイレクト URI の一つ
scope openid OIDC 認証リクエストであることを示す値
nonce n-0S6_WzA2Mj ノンス値 (3.1.2.1. 認証リクエスト - OpenID Connect Core 1.0 を参照)

リソースオーナーがクライアントを介して保護されたリソースにアクセスしようとすると (ステップ #1、#2)、クライアントはユーザーエージェントを介して認可リクエスト (OIDC 認証リクエスト) を認可サーバーに送信します (ステップ #3、#4)。

認可サーバーは、以下に示すように、ユーザーエージェントから HTTP GET クエリ文字列としてデータを受け取ります。

redirect_uri=https://client.example.org/cb/example.com
 &response_type=code
 &client_id=12898884596863
 &scope=openid
 &nonce=n-0S6_WzA2Mj

認可サーバーの役割は、これらのパラメータを評価することです。以下は典型的な評価ルールです:

  • クライアント ID 12898884596863 に関連付けられたクライアントが認可サーバーに登録されているかどうか。scope=openid の場合、このクライアントは OIDC リライングパーティである必要があります。
  • リダイレクト URI https://client.example.org/cb/example.com の値が、クライアントに登録された URI の一つと一致しているかどうか。
  • response_typescope などの他のパラメータの値が、クライアントに対して許可されているかどうか。

その後、scoperesponse_type の値がそれぞれ openidcode であるため、認可サーバーは OIDC 認可コードフローを処理します。

ただし、Authlete アーキテクチャでは、認可サーバーは単に Authlete API によって処理される認可ロジックのプロキシとして機能します。このロジックは /auth/authorization エンドポイントで公開されています。リクエストを受け取ると、Authlete API が認可サーバーに代わって評価プロセスを実行します。

ここから、認可サーバーのリクエストをこの API にシミュレートします。

以下のように curl コマンドを実行してください (メッセージ #5)。前のステップで生成した <サービス ID> (Service ID)、<サービス アクセス トークン> (Service Access Token)、および <クライアント ID> (Client ID) を置き換えて使用します。

curl -s -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/authorization \
-H 'Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
-H 'Content-Type: application/json' \
-d '{ "parameters": "redirect_uri=https://client.example.org/cb/example.com&response_type=code&client_id=<Client ID e.g. 12898884596863>&scope=openid&nonce=n-0S6_WzA2Mj" }'

成功すると、Authlete は次のようなレスポンスを返します (簡略化のため省略されています) (メッセージ #6)。

{
   "resultMessage" : "[A004001] Authlete has successfully issued a ticket to the service (API Key = 10738933707579) for the authorization request from the client (ID = 12898884596863). [response_type=code, openid=true]",
   "resultCode" : "A004001",
   "client" : { [...] },
   "ticket" : "bi2Kxe2WW5mK_GZ_fDFOpK1bnY6xTy40Ap_8nxf-7AU",
   "action" : "INTERACTION",
   [...]
   "service" : {
      [...]
      "supportedClaims" : null,
      "supportedScopes" : null,
   }
}

このレスポンスの resultMessageactionticket の 3 つのキー/値ペアに注意してください。

  • resultMessage: リクエスト処理の結果を人間が読める形式で提供します。openid=true は、リクエストが OIDC プロトコルに従って処理されることを示します。
  • action: 認可サーバーが次に行うべきアクションを示します。
  • ticket: 次のステップで別の API にリクエストを行うために必要です。

Authlete はまた、レスポンス内にサービスおよびクライアント情報を提供します。認可サーバーはこれを使用して、リソースオーナーがクライアントに対してアクセスを許可するかどうかを尋ねます。

ユーザー認証と認証結果の共有確認

リソースオーナーと認可サーバー間の実際のやり取りは、このチュートリアルの範囲外です。通常、認可サーバーは以下のプロセスを実行します:

  • 資格情報 (例: ID/パスワード) を使用してユーザーを認証します。
  • ユーザーのロールや権限を決定します。
  • ユーザーに、認証結果をクライアントと共有するかどうかを確認します。

これらのプロセスは、ステップ #7、#8、#9 に対応します。

認可コードの発行

次に進む前に、認可サーバーが以下の状態にあると仮定します:

  • 認可サーバーがリソースオーナーを認証し、subject パラメータとして Authlete に共有されるリソースオーナーの識別子が testuser01 であることを決定した。
  • 認可サーバーがリソースオーナーの同意を取得した。

認可サーバーは、Authlete の /auth/authorization/issue にリクエストを送信し、認可コードを発行します。このリクエストには、subject/auth/authorization API のレスポンスに含まれる ticket の値が含まれます。

以下の curl コマンドを実行してください (メッセージ #10)。先ほど生成した <Service ID><Service Access Token>、および <Ticket> を置き換えて使用します。

curl -s -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/authorization/issue \
-H 'Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
-H 'Content-Type: application/json' \
-d '{ "ticket": "<Ticket e.g. bi2Kxe2WW5mK_GZ_fDFOpK1bnY6xTy40Ap_8nxf-7AU>", "subject": "testuser01" }'

成功すると、Authlete は次のようなレスポンスを返します (ステップ #11)。

{
   "action" : "LOCATION",
   "resultCode" : "A040001",
   "accessTokenDuration" : 0,
   "accessTokenExpiresAt" : 0,
   "resultMessage" : "[A040001] The authorization request was processed successfully.",
   "responseContent" : "https://client.example.org/cb/example.com?code=GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U",
   "authorizationCode" : "GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U",
   ...
}

このレスポンスの resultMessageactionresponseContent の 3 つのキー/値ペアに注目してください。

  • resultMessage: リクエスト処理の結果を人間が読める形式で提供します。
  • action: 認可サーバーが次に行うべきアクションを示します。このレスポンスの値は LOCATION であり、認可サーバーがユーザーエージェントにリダイレクトレスポンスを返すべきことを示しています。
  • responseContent: 認可サーバーからのレスポンス内容を示します。

認可サーバーは、以下のようなレスポンスをユーザーエージェントに送信します (ステップ #12)。

HTTP/1.1 302 Found
Location: https://client.example.org/cb/example.com
 ?code=GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U

認可コードの発行に失敗した場合

場合によっては、認可サーバーがリソースオーナーから認可を受けられないことがあります。この場合、クライアントにトークンを発行せず、認可フローが終了したことを通知する必要があります。Authlete の /auth/authorization/fail API は、クライアントに送信されるメッセージおよびレスポンスの転送方法の観点から、この終了プロセスをサポートします。

まとめると、通常の状況では、認可サーバーはユーザー認証と同意の結果に応じて、/auth/authorization/issue または /auth/authorization/fail API のいずれかにリクエストを送信します。

トークンリクエスト

ここでは、ユーザーエージェントが認可サーバーからのリダイレクトレスポンスを受け取ったと仮定します。このリダイレクトレスポンスは以下のようにクライアントに転送されます (ステップ #13)。

GET /cb/example.com?code=GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U HTTP/1.1
Host: client.example.org

クライアントは code パラメータの値を抽出し、それを使用してトークンリクエストを構築し、認可サーバーに送信します。以下はその例です (改行を追加して可読性を向上させています)。https://as.example.com/token は、このチュートリアルにおけるトークンエンドポイント URI です (ステップ #14)。

POST /token HTTP/1.1
Host: as.example.com
Authorization: Basic base64(12898884596863:-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg)
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
 &code=GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U
 &redirect_uri=https://client.example.org/cb/example.com

認可サーバーは、リクエストのパラメータを評価し、クライアントにトークンレスポンスを返すために Authlete API にリクエストを送信します。

ここで、このステップをシミュレートするために Authlete の /auth/token API を使用します。この API はリクエストを評価し、レスポンスを生成します。

以下の curl コマンドを実行してください (ステップ #15)。先ほど生成した <Service ID><Service Access Token><Client ID><Client Secret>、および <Code> を置き換えて使用します。

curl -s -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/token \
-H 'Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
-H 'Content-Type: application/json' \
-d '{ "clientId": "<Client ID e.g. 12898884596863>", "clientSecret": "<Client Secret e.g. -olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg>", "parameters": "grant_type=authorization_code&code=<Code e.g. GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U>&redirect_uri=https://client.example.org/cb/example.com" }'

成功すると、Authlete は次のようなレスポンスを返します (メッセージ #16)。

{
   "resultMessage" : "[A050001] The token request (grant_type=authorization_code) was processed successfully.",
   "action" : "OK",
   "clientIdAliasUsed" : false,
   "subject" : "testuser01",
   "resultCode" : "A050001",
   "refreshTokenExpiresAt" : 1730552811449,
   "grantType" : "AUTHORIZATION_CODE",
   "accessToken" : "7FfwOnGjVHwxXhs2Wr67XV1-ZhQaoy3ctKcGkLyKxuY",
   "idToken" : "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTU5MTA2ODE1LCJpYXQiOjE1NTkwMjA0MTUsIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.5uSFMTGnubyvtiExHc9l7HT9UsF8a_Qb0STtWzyclBk",
   "responseContent" : "{\"access_token\":\"7FfwOnGjVHwxXhs2Wr67XV1-ZhQaoy3ctKcGkLyKxuY\",\"refresh_token\":\"T1h7fJ6k55CyipDtXNPbzN8ta3FgAAf4QKjo36OVfIE\",\"scope\":\"openid\",\"id_token\":\"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTU5MTA2ODE1LCJpYXQiOjE1NTkwMjA0MTUsIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.5uSFMTGnubyvtiExHc9l7HT9UsF8a_Qb0STtWzyclBk\",\"token_type\":\"Bearer\",\"expires_in\":86400}",
   "scopes" : [
      "openid"
   ],
   "accessTokenDuration" : 86400,
   "type" : "tokenResponse",
   "refreshToken" : "T1h7fJ6k55CyipDtXNPbzN8ta3FgAAf4QKjo36OVfIE",
   "accessTokenExpiresAt" : 1730552811449,
   "refreshTokenDuration" : 864000,
   "clientId" : 12898884596863
}

このレスポンスの resultMessageactionresponseContent の 3 つのキー/値ペアに注目してください。

  • resultMessage: リクエスト処理の結果を人間が読める形式で提供します。
  • action: 認可サーバーが次に行うべきアクションを示します。この場合の値は OK であり、認可サーバーがクライアントにトークンレスポンスを返すべきことを示しています。
  • responseContent: 認可サーバーからクライアントへのレスポンス内容を示します。

認可サーバーは以下のレスポンスをクライアントに送信する必要があります (メッセージ #17)。

HTTP/1.1 200 OK
Content-Type: application/json

{
 "access_token":"7FfwOnGjVHwxXhs2Wr67XV1-ZhQaoy3ctKcGkLyKxuY",
 "refresh_token":"T1h7fJ6k55CyipDtXNPbzN8ta3FgAAf4QKjo36OVfIE",
 "scope":"openid",
 "id_token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTU5MTA2ODE1LCJpYXQiOjE1NTkwMjA0MTUsIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.5uSFMTGnubyvtiExHc9l7HT9UsF8a_Qb0STtWzyclBk",
 "token_type":"Bearer",
 "expires_in":86400
}

クライアントはこのレスポンスを受信すると、必要に応じて ID トークンをデコードします。

ID トークンのデコード

クライアントは、レスポンス内の id_token の値をデコードし、その有効性を確認する必要があります。

このチュートリアルでは、無料のオープンソースツール Online JWT Verifier を使用してトークンをデコードします。

以下のリンクを開き、JWT Verifier UI の (Step 1) Set JWT (JSON Web Token) to verify テキストエリアに id_token の値を貼り付けてください。このチュートリアルの例では ID トークンの値として eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTU5MTA2ODE1LCJpYXQiOjE1NTkwMjA0MTUsIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.5uSFMTGnubyvtiExHc9l7HT9UsF8a_Qb0STtWzyclBk を使用します。

その後、(Step 3) Verify セクション内の Just Decode JWT ボタンをクリックして、Parsed JWT セクションにデコードされた内容を確認してください。

デコードされた JWT トークン (ヘッダーとペイロード)

デコード結果は以下のようになります。

ヘッダー:

{
  "alg": "HS256"
}

ペイロード:

{
  "sub": "testuser01",
  "aud": [
    "12898884596863"
  ],
  "iss": "https://authlete.com",
  "exp": 1730552811,
  "iat": 1730552811,
  "nonce": "n-0S6_WzA2Mj"
}

上記の内容には、修正が必要な点がいくつかあります。

  • isshttps://authlete.com となっていますが、これは Authlete のデフォルト値です。このチュートリアルでは、認可サーバーの識別子として https://as.example.com にする必要があります。
  • sub はユーザーの識別に関する唯一の属性です。クライアントの利便性のために、他のユーザー属性を追加することが望ましいです。

次のセクションでは、iss の値を修正し、追加のクレームを追加します。

ID トークンの修正

発行者識別子の設定

https://console.authlete.com にログインし、このチュートリアルで作成した Demo AS サービスを選択します。サービス設定 ボタンをクリックして、サービス設定にアクセスします。

サービス設定ボタンを強調表示した Authlete サービス

一般 タブにある 発行者識別子 のデフォルト値が https://authlete.com であることに注意してください。この値を https://as.example.com に変更し、ページ下部の 変更を保存 ボタンをクリックして保存します。

確認ダイアログが表示されたら OK をクリックします。

更新された発行者識別子 URL を表示する Authlete サービス設定

これで、ID トークンの発行者識別子 iss が修正されました。

認可リクエストの送信

先ほどと同じ認可リクエストを送信します (便宜上、同じ nonce 値を使用します)。このリクエストは Authlete の /auth/authorization API に送信されます (ステップ #5)。以下のように <Service ID><Service Access Token>、および <Client ID> を置き換えて使用してください。

curl -s -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/authorization \
-H 'Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
-H 'Content-Type: application/json' \
-d '{ "parameters": "redirect_uri=https://client.example.org/cb/example.com&response_type=code&client_id=<Client ID e.g. 12898884596863>&scope=openid&nonce=n-0S6_WzA2Mj" }'

以下のようなレスポンスを受け取るはずです (簡略化のため省略されています)。

{
   [...]
   "action" : "INTERACTION",
   "resultCode" : "A004001",
   "resultMessage" : "[A004001] Authlete has successfully issued a ticket to the service (API Key = 10738933707579) for the authorization request from the client (ID = 12898884596863). [response_type=code, openid=true]",
   "ticket" : "JjQ_Th1UvZyU5MsdKTLIfLv3VlKwEiYnnULmW6l_d9A",
}

追加クレームの追加

次に、認可コードを発行するために Authlete の /auth/authorization/issue API にリクエストを送信します。このリクエストに含まれるクレームには以下の追加項目を含めます。

項目
name Test User
email testuser01@example.com
email_verified true

以下の claims パラメータを使用してクレームを追加します。リクエストは以下のように構築されます。

curl -s -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/authorization/issue \
-H 'Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
-H 'Content-Type: application/json' \
-d '{ "ticket": "<Ticket e.g. JjQ_Th1UvZyU5MsdKTLIfLv3VlKwEiYnnULmW6l_d9A>", "subject": "testuser01", "claims": "{\"name\": \"Test User\", \"email\": \"testuser01@example.com\", \"email_verified\": true}" }'

以下のようなレスポンスを受け取るはずです。

{
   "responseContent" : "https://client.example.org/cb/example.com?code=ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI",
   "accessTokenDuration" : 0,
   "authorizationCode" : "ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI",
   "accessTokenExpiresAt" : 0,
   "type" : "authorizationIssueResponse",
   "resultMessage" : "[A040001] The authorization request was processed successfully.",
   "resultCode" : "A040001",
   "action" : "LOCATION"
}

認可サーバーは以下のリダイレクトレスポンスをユーザーエージェントに送信する必要があります。その後、ユーザーエージェントは以下のような HTTP GET リクエストをクライアントに送信します。

GET /cb/example.com?code=ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI HTTP/1.1
Host: client.example.org

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

クライアントは以下のようにトークンリクエストを認可サーバーに送信します (改行は可読性向上のため追加されています)。

POST /token HTTP/1.1
Host: as.example.com
Authorization: Basic base64(12898884596863:-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg)
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
 &code=ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI
 &redirect_uri=https://client.example.org/cb/example.com

認可サーバーは、Authlete の /auth/token API を呼び出します。

curl -s -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/token \
-H 'Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
-H 'Content-Type: application/json' \
-d '{ "clientId": "<Client ID e.g. 12898884596863>", "clientSecret": "<Client Secret e.g. -olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg>", "parameters": "grant_type=authorization_code&code=<Code e.g. ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI>&redirect_uri=https://client.example.org/cb/example.com" }'

Authlete は以下のようなレスポンスを返します。

{
   "grantType" : "AUTHORIZATION_CODE",
   "responseContent" : "{\"access_token\":\"R4sd3s02Y1Gj72iI5Md6ZkGapXZ6mSnIEdihTvrM_Ro\",\"refresh_token\":\"k4WqWw2tcDOHxXXo29NxOCwQJyeDOtZ6aw_Y9Ugy-6U\",\"scope\":\"openid\",\"id_token\":\"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVGVzdCBVc2VyIiwiZW1haWwiOiJ0ZXN0dXNlcjAxQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImV4cCI6MTU1OTEzNzMwMSwiaWF0IjoxNTU5MDUwOTAxLCJub25jZSI6Im4tMFM2X1d6QTJNaiJ9.8ngbBoGLUvHXIO4VyGN0-txJfE5Yq86xElMSxqGlLv0\",\"token_type\":\"Bearer\",\"expires_in\":86400}",
   "resultMessage" : "[A050001] The token request (grant_type=authorization_code) was processed successfully.",
   "accessTokenExpiresAt" : 1730554257440,
   "accessToken" : "R4sd3s02Y1Gj72iI5Md6ZkGapXZ6mSnIEdihTvrM_Ro",
   "resultCode" : "A050001",
   "scopes" : [
      "openid"
   ],
   "refreshTokenExpiresAt" : 1730554257440,
   "subject" : "testuser01",
   "action" : "OK",
   "refreshTokenDuration" : 864000,
   "accessTokenDuration" : 86400,
   "refreshToken" : "k4WqWw2tcDOHxXXo29NxOCwQJyeDOtZ6aw_Y9Ugy-6U",
   "clientIdAliasUsed" : false,
   "idToken" : "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVGVzdCBVc2VyIiwiZW1haWwiOiJ0ZXN0dXNlcjAxQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImV4cCI6MTU1OTEzNzMwMSwiaWF0IjoxNTU5MDUwOTAxLCJub25jZSI6Im4tMFM2X1d6QTJNaiJ9.8ngbBoGLUvHXIO4VyGN0-txJfE5Yq86xElMSxqGlLv0",
   "clientId" : 12898884596863
}

認可サーバーは以下のレスポンスをクライアントに返すことが期待されます (メッセージ #17)。

HTTP/1.1 200 OK
Content-Type: application/json

{
 "access_token":"R4sd3s02Y1Gj72iI5Md6ZkGapXZ6mSnIEdihTvrM_Ro",
 "refresh_token":"k4WqWw2tcDOHxXXo29NxOCwQJyeDOtZ6aw_Y9Ugy-6U",
 "scope":"openid",
 "id_token":"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVGVzdCBVc2VyIiwiZW1haWwiOiJ0ZXN0dXNlcjAxQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImV4cCI6MTU1OTEzNzMwMSwiaWF0IjoxNTU5MDUwOTAxLCJub25jZSI6Im4tMFM2X1d6QTJNaiJ9.8ngbBoGLUvHXIO4VyGN0-txJfE5Yq86xElMSxqGlLv0",
 "token_type":"Bearer",
 "expires_in":86400
}

クライアントがこのレスポンスを受信した後、再び Online JWT Verifier を使用してトークンをデコードしてみましょう。

上記リンクを開き、レスポンス内の id_token の値を Step 1 のテキストエリアに貼り付けます。このチュートリアルでは ID トークンの値として eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVGVzdCBVc2VyIiwiZW1haWwiOiJ0ZXN0dXNlcjAxQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImV4cCI6MTU1OTEzNzMwMSwiaWF0IjoxNTU5MDUwOTAxLCJub25jZSI6Im4tMFM2X1d6QTJNaiJ9.8ngbBoGLUvHXIO4VyGN0-txJfE5Yq86xElMSxqGlLv0 を使用します。

その後、Step 3Just Decode JWT ボタンをクリックし、Parsed JWT セクションでデコードされた内容を確認してください。

追加クレームを含む JWT トークンのデコード結果

デコード結果は以下の通りです。

ヘッダー:

{
  "alg": "HS256"
}

ペイロード:

{
  "name": "Test User",
  "email": "testuser01@example.com",
  "email_verified": true,
  "iss": "https://as.example.com",
  "sub": "testuser01",
  "aud": [
    "12898884596863"
  ],
  "exp": 1559137301,
  "iat": 1559050901,
  "nonce": "n-0S6_WzA2Mj"
}

これにより、以下の点が確認できます。

  • iss の値が正しく設定されています。
  • nameemail、および email_verified といった追加クレームが含まれています。

まとめ

このチュートリアルでは、Authlete API を使用して OpenID Connect プロバイダーとして動作する認可サーバーをシミュレートし、認可コードフローを用いて ID トークンを発行する方法を学びました。以下の重要なステップを完了しました。

  • Authlete API を使用して認可コードフローを認可サーバー (OIDC アイデンティティプロバイダー) に実装する方法
  • Authlete 管理コンソールで発行者識別子や追加クレームを設定し、それらを ID トークンからデコードする方法

このウォークスルーでは一部のプロセスを簡略化しましたが、Authlete をバックエンドサービスとして利用することで、独自のインフラストラクチャ上でホストされる認可サーバーがどのように動作するかを深く理解できたはずです。独自の認可サーバーを構築する場合、複雑なロジックやコード、シークレットの安全な取り扱いに細心の注意を払う必要がありますが、Authlete API を利用することで、これらの実装を大幅に簡素化できます。

次のステップ

以下の機能を試し、Authlete をさらに深く理解しましょう。