OIDC Basics

はじめに

このドキュメントでは、OpenID Connect (OIDC) の Authorization Code Flow に対応したアイデンティティプロバイダーを構築する際の、Authlete API の基本的な利用方法について説明します。

構成

本チュートリアルでは以下の構成を想定します。 なお、実サービスとして動作するのは、Authlete のコンソールと API だけです。 認可サーバー(OIDC アイデンティティプロバイダー)、クライアント(OIDC リライングパーティ)、リソースサーバーについては、いずれも実際には存在せず、それぞれの処理は curl コマンドの実行により代用します。


各サービスの FQDN は以下の通りです。上述の通り認可サーバーとクライアントは存在しませんが、OAuth のフローを説明する上で FQDN が最低限必要となります。

サービス FQDN
Authlete API api.authlete.com
Authlete サービス管理者コンソール (Service Owner Console) so.authlete.com
Authlete クライアントアプリ開発者コンソール (Developer Console) cd.authlete.com
認可サーバー(OIDC アイデンティティプロバイダー) (Authorization Server) as.example.com
クライアント(OIDC リライングパーティ) (Client) client.example.org
リソースサーバー (Resource Server) N/A

環境設定

Authlete サービスのアカウント登録

Authlete を認可サーバーのバックエンドとして用いる場合には、まず Authlete のアカウントを取得する必要があります。 取得は以下のページから行います。入力した「ログインID」と「パスワード」を忘れないようにしましょう。

https://so.authlete.com/accounts/signup

アカウントが登録されているかどうか、「サービス管理者コンソール」へログインして確認してみましょう。 Web ブラウザを用いて以下のページにアクセスし、「ログインID」と「パスワード」を用いてログインします。

https://so.authlete.com/accounts/login


ログインに成功すると以下のようなページが表示されます。


これで Authlete のサービス管理者機能が利用できるようになりました。 なおログアウトする場合にはページ右上の「ログアウト」をクリックします。

Authlete サービスの追加

それでは、本チュートリアル専用の、認可サーバーのバックエンド API を準備します。 再度 Authlete のサービス管理者コンソール https://so.authlete.com/accounts/login にログインし、右側の「サービス作成」をクリックします。


サービス作成のページが表示されます。任意の「サービス名」を入力し、「作成」をクリックします。 確認のダイアログが表示されるので「OK」をクリックします。


新規サービスの作成が完了しました。自動生成された「APIキー」と「APIシークレット」は、次にクライアントアプリ開発者コンソールにログインするときのログインID・パスワードとして用いるとともに、認可サーバーが Authlete API にリクエストを行う際のクレデンシャルとなります。


項目
API キー 自動生成された値(例: 10723797812772
API シークレット 自動生成された値(例: ekYoYTI84qZcpe6bXGzDwduQ1fGBYxJT8K8Tnwd7poc

OAuth クライアント(OIDC リライングパーティ)の追加

次に、この新規サービスに、さらに新規クライアントの設定を追加します。 Authlete のクライアントアプリ開発者コンソール(https://cd.authlete.com/<API キー> 例: https://cd.authlete.com/10723797812772)にアクセスし、ログイン ID として先ほど作成したサービスの「API キー」を、パスワードとして同じく「API シークレット」を用いてログインします。


クライアントアプリ開発者コンソールのログイン後のページです。右手にある「アプリ作成」をクリックします。


アプリ作成のページです。まず「基本情報」タブが表示されます。 ここでは任意の「クライアント名」を入力します。 またクライアントタイプとして CONFIDENTIAL を選択します。次に、「基本情報」タブの隣にある「認可」タブをクリックします。


「認可」タブをクリック後のページです。ここでは「リダイレクト URI」と「クライアント認証方式」を、以下の通り指定します。


項目
リダイレクト URI https://client.example.org/cb/example.com
クライアント認証方式 CLIENT_SECRET_BASIC

指定後、ページ下方にある「作成」をクリックします。確認のダイアログが表示されるので「OK」をクリックします。

これにより、サービスへのクライアント情報の登録が完了しました。 自動生成されている「クライアント ID」と「クライアントシークレット」はそれぞれ、クライアントが認可サーバーにリクエストを行う際の client_idclient_secret の値として用いられます。 また、そのほか指定した各値が正しく設定されていることも確認しましょう。



項目
クライアント ID 自動生成された値(例: 12898884596863
クライアントシークレット 自動生成された値(例: dcDHEXr_tXNi7QdIMXLSXpXAy_j7Cr4C4LT2xAukQcW_09E2Ag1jTBdwpQrG-HBxflPF4Bz_Nb9Zd_ySAxOs6A
クライアントタイプ CONFIDENTIAL
リダイレクト URI https://client.example.org/cb/example.com
クライアント認証方式 CLIENT_SECRET_BASIC

以上により、認可サーバーとクライアントからなる、OIDC 認可コードフローを実施するための最小限の構成が完成しました。それでは、実際にこのフローを試してみましょう。

OIDC 認可コードフローの実行から ID トークン取得までの流れ

シーケンス図を以下に示します。以降の説明においては、この図にあるメッセージ番号を併せてご参照ください。


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

クライアントはユーザーエージェントを経由して、認可サーバーにOIDC 認証リクエスト(認可リクエスト)を送信します(メッセージ番号 2, 3)。 ここでは認可リクエストのパラメーターとして以下が指定されていたものとします。

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

認可サーバーは、ユーザーエージェントからのリクエストのクエリストリングとして、以下の内容(一部折り返しています)を受信することになります(メッセージ番号 3)。

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

認可サーバーは、本来はこれらのパラメーターの検証を自ら行う必要があります。 以下の検証後に認可サーバーは、scope の値が openid, かつ response_type の値が code であることから、リクエストを OIDC 認可コードフローとして処理することになります。

  • クライアント ID 12898884596863 に相当するクライアントが、(scope=openid であることから)単なる OAuth クライアントとしてではなく、 OIDC リライングパーティとして認可サーバーに登録されているかどうか
  • リダイレクト URI https://client.example.org/cb/example.com が、そのクライアントに事前登録されているリダイレクト URI のどれかに合致するか
  • そのほかのパラメーター(レスポンスタイプや、今回は指定していませんがスコープなど)が、そのクライアントに許可されている(クライアントが指定可能である)かどうか

この検証プロセスを代行するのが Authlete の /auth/authorization API です。 認可サーバーの立場になり、この API にリクエストしてみましょう。ここでは curl コマンドを以下のように実行します(メッセージ番号 4)。 なお <API Key>, <API Secret>, <Client ID> は、本チュートリアルの過程にて生成された値に置き換えてください。

curl -s -X POST https://api.authlete.com/api/auth/authorization \
-u '<API Key e.g. 10723797812772>:<API Secret e.g. ekYoYTI84qZcpe6bXGzDwduQ1fGBYxJT8K8Tnwd7poc>' \
-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" }'

なお Windows 10 にて標準の curl.exe コマンドを PowerShell から用いる場合には、以下のようになります。curl ではなく curl.exe とすること、" をエスケープすること、行の区切りに`を用いることにご注意ください。

curl.exe -s -X POST https://api.authlete.com/api/auth/authorization `
-u '<API Key e.g. 10723797812772>:<API Secret e.g. ekYoYTI84qZcpe6bXGzDwduQ1fGBYxJT8K8Tnwd7poc>' `
-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. 12800697055611>&scope=openid&nonce=n-0S6_WzA2Mj\"}'

リクエストが適切な場合、Authlete から以下のようなレスポンス(見やすさのため改行し一部省略)が返却されます(メッセージ番号 5)。

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

このうち、とくに注目すべきキーは、 resultMessage, action, ticket です。

{
   [...]
   "ticket" : "bi2Kxe2WW5mK_GZ_fDFOpK1bnY6xTy40Ap_8nxf-7AU",
   "action" : "INTERACTION",
   "resultMessage" : "[A004001] Authlete has successfully issued a ticket to the service (API Key = 10723797812772) for the authorization request from the client (ID = 12898884596863). [response_type=code, openid=true]",
  • resultMessage: リクエストの処理結果をわかりやすく示しています(参考: Authlete の result code について)。 さらに openid=true となっており、OIDC プロトコルとして処理されるということがわかります。
  • action: 認可サーバーが次に何をすべきかを示します。
  • ticket: 認可フロー処理の次のステップにて、後述する別の Authlete API を呼ぶときに必要な値となります。

それ以外に返却される値として、サービス情報とクライアント情報があります。認可サーバーはこれらの値を用いて、ユーザーに、「どのようなサービスに対する、どのようなアクセス権限を、どのようなクライアントに許可するか」を確認することになります。

ユーザー認証と認証結果提供の確認

このチュートリアルの中では、ユーザーと具体的にどのようなインタラクションを行うかについては言及しません。多くの場合、認可サーバーはユーザーを何らかの方法(ID/パスワードなど)を用いて認証し、ユーザーのロールや権限を確認したのちに、前述した認証結果提供の確認を行います(メッセージ番号 6, 7)。

認可コードの発行

ユーザー認証と認証結果提供の確認が完了することにより、認可サーバーは以下の状態に至ったとします。

  • ユーザーを特定した。そのユーザーを一意に識別するために Authlete と共有する値(subject)として testuser01 を用いる。
  • ユーザーから、クライアントに対する認証結果提供の許可を得た。

認可サーバーはこれをうけて、Authlete の /auth/authorization/issue API を用いて、認可コードの発行を指示します。 認可サーバーは subject と、先ほど /auth/authorization API のレスポンスから取得した ticket の値を、 この API へのリクエストのパラメーターとして指定します。ここでは curl コマンドを以下のように実行します(メッセージ番号 8)。 なお <API Key>, <API Secret>, <Ticket> は、本チュートリアルの過程にて生成された値に置き換えてください。

curl -s -X POST https://api.authlete.com/api/auth/authorization/issue \
-u '<API Key e.g. 10723797812772>:<API Secret e.g. ekYoYTI84qZcpe6bXGzDwduQ1fGBYxJT8K8Tnwd7poc>' \
-H 'Content-Type: application/json' \
-d '{ "ticket": "<Ticket e.g. bi2Kxe2WW5mK_GZ_fDFOpK1bnY6xTy40Ap_8nxf-7AU>", "subject": "testuser01" }'

リクエストが適切な場合、Authlete から以下のようなレスポンス(見やすさのため改行)が返却されます(メッセージ番号 9)。

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

このうち、特に注目すべきキーは、 resultMessage, action, responseContent, です。

  • resultMessage, action: 先の /auth/authorization API と同様に、リクエストの処理結果と、認可サーバーが次に何をすべきかを示します。今回は action の値として LOCATION が指定されています。これは、認可サーバーはクライアントにリダイレクトレスポンスを返却してくださいという意味です。
  • responseContent: レスポンスの内容として指定する値です。

結果的に、認可サーバーは、以下のレスポンス(一部折り返しています)をユーザーエージェントに返却することが期待されます(メッセージ番号 10)。

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 を使い分けることになります。

トークンリクエスト

先のレスポンスを認可サーバーがユーザーエージェントに返却した結果、ユーザーエージェントは以下のリクエスト(一部折り返しています)をクライアントに送信することになります(メッセージ番号 11)。

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

クライアントはこのリクエストから code の値を抽出し、トークンリクエストを組み立て、認可サーバーに送信します(一部折り返しています)。 ここではトークンエンドポイントを https://as.example.com/token とします(メッセージ番号 12)。

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

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

このトークンリクエストを受け取った認可サーバーは、先の認可リクエスト処理のときと同様に、パラメーターの検証を行い、トークンレスポンスをクライアントに返却することになります。 本チュートリアルでは、この一連の処理を Authlete の /auth/token API を用いて行います。 ここでは curl コマンドを以下のように実行します(メッセージ番号 13)。 なお <API Key>, <API Secret>, <Client ID>, <Client Secret>, <Code> は、本チュートリアルの過程にて生成された値に置き換えてください。

curl -s -X POST https://api.authlete.com/api/auth/token \
-u '<API Key e.g. 10723797812772>:<API Secret e.g. ekYoYTI84qZcpe6bXGzDwduQ1fGBYxJT8K8Tnwd7poc>' \
-H 'Content-Type: application/json' \
-d '{ "clientId": "<Client ID e.g. 12898884596863>", "clientSecret": "<Client Secret e.g. dcDHEXr_tXNi7QdIMXLSXpXAy_j7Cr4C4LT2xAukQcW_09E2Ag1jTBdwpQrG-HBxflPF4Bz_Nb9Zd_ySAxOs6A>", "parameters": "grant_type=authorization_code&code=<Code e.g. GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U>&redirect_uri=https://client.example.org/cb/example.com" }'

リクエストが適切な場合、Authlete から以下のようなレスポンス(見やすさのため改行)が返却されます(メッセージ番号 14)。

{
   "resultMessage" : "[A050001] The token request (grant_type=authorization_code) was processed successfully.",
   "action" : "OK",
   "clientIdAliasUsed" : false,
   "subject" : "testuser01",
   "resultCode" : "A050001",
   "refreshTokenExpiresAt" : 1559288344881,
   "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" : 1558510744881,
   "refreshTokenDuration" : 864000,
   "clientId" : 12898884596863
}

このうち、特に注目すべきキーは、resultMessage, action, responseContent です。

  • resultMessage, action: これまでと同様に、リクエストの処理結果と、認可サーバーが次に何をすべきかを示します。今回は action の値として OK が指定されています。これは、正常に処理が完了したので認可サーバーはクライアントにレスポンスを返却してくださいという意味です。
  • responseContent: レスポンスの内容として指定する値です。

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

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
}

以上により、認可サーバーはトークンを生成し、クライアントに提供することができました。そして Authlete の API を活用することにより認可サーバーは、複雑な処理を実装せずとも、認可リクエストやトークンリクエストのパラメーターを正しく検証し、さらに正しいレスポンス内容を返却することができました。

ID トークンの利用

レスポンスを受け取ったクライアントは、その中に含まれる id_token の値のデコード・検証を行うことになります。本チュートリアルでは Online JWT Verfier を用いてデコードを試します。

Online JWT Verfier (https://kjur.github.io/jsrsasign/tool/tool_jwtveri.html)

上記のページにアクセスし、「(Step1) Set JWT(JSON Web Token) to verify.」のフィールドに、id_token の値 eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTU5MTA2ODE1LCJpYXQiOjE1NTkwMjA0MTUsIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.5uSFMTGnubyvtiExHc9l7HT9UsF8a_Qb0STtWzyclBk を(事前に入っている値を上書きするかたちで)コピーアンドペーストします。

そして「(Step3) Verify.」にある「Just Decode JWT」ボタンを押下すると、「Parsed JWT」のセクションにデコードされた結果が表示されます。


デコードした結果は以下のような内容です。

  • Header
{
  "alg": "HS256"
}
  • Payload
{
  "sub": "testuser01",
  "aud": [
    "12898884596863"
  ],
  "iss": "https://authlete.com",
  "exp": 1559106815,
  "iat": 1559020415,
  "nonce": "n-0S6_WzA2Mj"
}

このように ID トークンの内容を見ると、いくつか改善・改良すべき点があることに気づきます。

まず、iss が Authlete の初期値である https://authlete.com のままになっています。これは本チュートリアルにおける認可サーバー https://as.example.com とする必要があります。 またユーザーに関する属性情報としては識別子である sub しか含まれていませんが、クライアントの利便性を考えると、その他のユーザー属性も併せて提供するほうが良いかもしれません。

次のセクションでは、iss の値を修正し、ユーザー情報として他のクレームを追加してみます。

ID トークンの修正と拡張

発行者識別子の修正

Authlete のサービス管理者コンソール https://so.authlete.com/accounts/login にログインし、本チュートリアルの過程にて作成したサービスを選択します。下方にある「編集」ボタンをクリックし、内容を編集可能にします。


「基本情報」タブの設定項目の中に「トークン発行者識別子」があり、「https://authlete.com」になっているはずです。 これを「https://as.example.com」に変更し、下方にある「更新」ボタンをクリックします。 確認のダイアログが表示されるので「OK」をクリックします。


これで発行者識別子(iss) の値が変更されました。

認可リクエスト

先ほどと同じ認可リクエスト(便宜上 nonce も同じ値を設定しています)を、Authlete の /auth/authorization API に送信してみましょう(メッセージ番号 4)。 なお <API Key>, <API Secret>, <Client ID> は、本チュートリアルの過程にて生成された値に置き換えてください。

curl -s -X POST https://api.authlete.com/api/auth/authorization \
-u '<API Key e.g. 10723797812772>:<API Secret e.g. ekYoYTI84qZcpe6bXGzDwduQ1fGBYxJT8K8Tnwd7poc>' \
-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 = 10723797812772) for the authorization request from the client (ID = 12898884596863). [response_type=code, openid=true]",
   "ticket" : "JjQ_Th1UvZyU5MsdKTLIfLv3VlKwEiYnnULmW6l_d9A",
   "type" : "authorizationResponse"
}

ID トークンの拡張(クレームの追加)

それでは /auth/authorization/issue API を呼び出し、認可コードとトークン生成を行います。 なお <API Key>, <API Secret>, <Ticket> は、本チュートリアルの過程にて生成された値に置き換えてください。

また、この API を呼び出す際に、以下のクレームを追加してみます。

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

クレームの追加には claims パラメーターを利用します。リクエストは以下のようなかたちになります。

curl -s -X POST https://api.authlete.com/api/auth/authorization/issue \
-u '<API Key e.g. 10723797812772>:<API Secret e.g. ekYoYTI84qZcpe6bXGzDwduQ1fGBYxJT8K8Tnwd7poc>' \
-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:dcDHEXr_tXNi7QdIMXLSXpXAy_j7Cr4C4LT2xAukQcW_09E2Ag1jTBdwpQrG-HBxflPF4Bz_Nb9Zd_ySAxOs6A)
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 で次のように実行します。 なお <API Key>, <API Secret>, <Client ID>, <Client Secret>, <Code> は、本チュートリアルの過程にて生成された値に置き換えてください。

curl -s -X POST https://api.authlete.com/api/auth/token \
-u '<API Key e.g. 10723797812772>:<API Secret e.g. ekYoYTI84qZcpe6bXGzDwduQ1fGBYxJT8K8Tnwd7poc>' \
-H 'Content-Type: application/json' \
-d '{ "clientId": "<Client ID e.g. 12898884596863>", "clientSecret": "<Client Secret e.g. dcDHEXr_tXNi7QdIMXLSXpXAy_j7Cr4C4LT2xAukQcW_09E2Ag1jTBdwpQrG-HBxflPF4Bz_Nb9Zd_ySAxOs6A>", "parameters": "grant_type=authorization_code&code=<Code e.g. ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI>&redirect_uri=https://client.example.org/cb/example.com" }'

レスポンスは以下のようになります(見やすさのため改行)。

{
   "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" : 1559115444898,
   "accessToken" : "R4sd3s02Y1Gj72iI5Md6ZkGapXZ6mSnIEdihTvrM_Ro",
   "type" : "tokenResponse",
   "resultCode" : "A050001",
   "scopes" : [
      "openid"
   ],
   "refreshTokenExpiresAt" : 1559893044898,
   "subject" : "testuser01",
   "action" : "OK",
   "refreshTokenDuration" : 864000,
   "accessTokenDuration" : 86400,
   "refreshToken" : "k4WqWw2tcDOHxXXo29NxOCwQJyeDOtZ6aw_Y9Ugy-6U",
   "clientIdAliasUsed" : false,
   "idToken" : "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVGVzdCBVc2VyIiwiZW1haWwiOiJ0ZXN0dXNlcjAxQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImV4cCI6MTU1OTEzNzMwMSwiaWF0IjoxNTU5MDUwOTAxLCJub25jZSI6Im4tMFM2X1d6QTJNaiJ9.8ngbBoGLUvHXIO4VyGN0-txJfE5Yq86xElMSxqGlLv0",
   "clientId" : 12898884596863
}

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

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 Verfier を用いて、id_token の値のデコードを行ってみましょう。

Online JWT Verfier (https://kjur.github.io/jsrsasign/tool/tool_jwtveri.html)

上記のページにアクセスし、「(Step1) Set JWT(JSON Web Token) to verify.」のフィールドに、id_token の値 eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVGVzdCBVc2VyIiwiZW1haWwiOiJ0ZXN0dXNlcjAxQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImV4cCI6MTU1OTEzNzMwMSwiaWF0IjoxNTU5MDUwOTAxLCJub25jZSI6Im4tMFM2X1d6QTJNaiJ9.8ngbBoGLUvHXIO4VyGN0-txJfE5Yq86xElMSxqGlLv0 を(事前に入っている値を上書きするかたちで)コピーアンドペーストします。

そして「(Step3) Verify.」にある「Just Decode JWT」ボタンを押下すると、「Parsed JWT」のセクションにデコードされた結果が表示されます。


デコードした結果は以下のような内容です。

  • Header
{
  "alg": "HS256"
}
  • Payload
{
  "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 の値を確認することができました。 またクレームとして、name, email, email_verified が正しく追加されていることもわかります。

まとめ

本チュートリアルでは、以下の 2 点について、実際の動作を確認しました。

  • 認可サーバー(OIDC アイデンティティ・プロバイダー)に認可コードフローを実装する際の Authlete API の利用方法
  • 発行者の修正とクレームの追加

次のステップ

チュートリアルの次のステップとして以下を試し、Authlete への理解を深めましょう。