OAuth 2.0 Basics

はじめに

このドキュメントでは、OAuth 2.0 の Authorization Code Grant Flow に対応した認可サーバーを構築する際の、Authlete API の基本的な利用方法について説明します。

構成

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


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

サービス FQDN
Authlete API api.authlete.com
Authlete サービス管理者コンソール (Service Owner Console) so.authlete.com
Authlete クライアントアプリ開発者コンソール (Developer Console) cd.authlete.com
認可サーバー (Authorization Server) as.example.com
クライアント (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 クライアントの追加

次に、この新規サービスに、さらに新規クライアントの設定を追加します。 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 自動生成された値(例: 12800697055611
クライアントシークレット 自動生成された値(例: dcDHEXr_tXNi7QdIMXLSXpXAy_j7Cr4C4LT2xAukQcW_09E2Ag1jTBdwpQrG-HBxflPF4Bz_Nb9Zd_ySAxOs6A
クライアントタイプ CONFIDENTIAL
リダイレクト URI https://client.example.org/cb/example.com
クライアント認証方式 CLIENT_SECRET_BASIC

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

認可コードグラントフローの実行からトークン利用までの流れ

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


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

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

項目
client_id 12800697055611
response_type code
redirect_uri https://client.example.org/cb/example.com

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

redirect_uri=https://client.example.org/cb/example.com
 &response_type=code
 &client_id=12800697055611

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

  • クライアント ID 110723797812772 に相当するクライアントが、認可サーバーに登録されているかどうか
  • リダイレクト 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. 12800697055611>" }'

なお 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>\"}'

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

{
   "resultMessage" : "[A004001] Authlete has successfully issued a ticket to the service (API Key = 10723797812772) for the authorization request from the client (ID = 12800697055611). [response_type=code, openid=false]",
   "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 = 12800697055611). [response_type=code, openid=false]",
  • resultMessage: リクエストの処理結果をわかりやすく示しています。(参考: Authlete の result code について
  • 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(12800697055611: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. 12800697055611>", "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",
   "responseContent" : "{\"access_token\":\"7FfwOnGjVHwxXhs2Wr67XV1-ZhQaoy3ctKcGkLyKxuY\",\"refresh_token\":\"T1h7fJ6k55CyipDtXNPbzN8ta3FgAAf4QKjo36OVfIE\",\"scope\":null,\"token_type\":\"Bearer\",\"expires_in\":86400}",
   "accessTokenDuration" : 86400,
   "type" : "tokenResponse",
   "refreshToken" : "T1h7fJ6k55CyipDtXNPbzN8ta3FgAAf4QKjo36OVfIE",
   "accessTokenExpiresAt" : 1558510744881,
   "refreshTokenDuration" : 864000,
   "clientId" : 12800697055611
}

このうち、特に注目すべきキーは、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":null,
 "token_type":"Bearer",
 "expires_in":86400
}

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

API リクエスト(アクセストークン検証)

このあと実際には、クライアントはリソースサーバーに対して、アクセストークンを含むリクエストを送信し、API の利用を試みることになります(メッセージ番号 16)。

アクセストークンを受け取ったリソースサーバーは、そのトークンの有効性を確認し、さらにトークンに付随するユーザーやクライアントの情報を取得して、どのような結果をクライアントに返却すべきか(すべきではないか)を判断する必要があります。

Authlete には、トークンの有効性を検証しその結果を返却する、/auth/introspection API が存在します。 ここでは curl コマンドを以下のように実行します(メッセージ番号 17)。 なお <API Key>, <API Secret>, <Token> は、本チュートリアルの過程にて生成された値に置き換えてください。

curl -s -X POST https://api.authlete.com/api/auth/introspection \
-u '<API Key e.g. 10723797812772>:<API Secret e.g. ekYoYTI84qZcpe6bXGzDwduQ1fGBYxJT8K8Tnwd7poc>' \
-H 'Content-Type: application/json' \
-d '{ "token": "<Token e.g. 7FfwOnGjVHwxXhs2Wr67XV1-ZhQaoy3ctKcGkLyKxuY>" }'

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

{
   "clientIdAliasUsed" : false,
   "type" : "introspectionResponse",
   "resultCode" : "A056001",
   "responseContent" : "Bearer error=\"invalid_request\"",
   "action" : "OK",
   "subject" : "testuser01",
   "expiresAt" : 1558510744000,
   "existent" : true,
   "resultMessage" : "[A056001] The access token is valid.",
   "refreshable" : true,
   "sufficient" : true,
   "usable" : true,
   "clientId" : 12800697055611
}

リソースサーバーはこのレスポンス結果から、アクセストークンの有効期限 (expiresAt) や、アクセス認可を行なったユーザーの識別子 (subject) などを取得します。そしてそれらの値に基づいて、クライアントに対する API レスポンスを決定できるようになります(メッセージ番号 19)。

PKCEの有効化

2019年6月現在、仕様策定が進められている OAuth 2.0 Security Best Current Practice では、認可コードグラントフローにおいて Proof Key for Code Exchange (PKCE) を用いることが必須とされています。本チュートリアルでは、PKCEの有効化を追加設定として行います。

PKCEの必須化

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


「基本情報」タブが編集可能になっている状態において、そのタブの並びにある「認可」タブを選択します。 すると、表示された「認可」タブの設定項目の中に「コード交換用証明キー (RFC 7636)」があり、「要求しない」になっているはずです。 これを「要求する」に変更し、下方にある「更新」ボタンをクリックします。 確認のダイアログが表示されるので「OK」をクリックします。


これで PKCE の利用が必須となりました。

認可リクエスト

先ほどと同じ認可リクエストを、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. 12800697055611>" }'

すると、先の実行例とは異なり、次のようなエラーレスポンス(見やすさのため改行し一部省略)が返却されるはずです(メッセージ番号 5)。

{
   [...]
   "responseContent" : "https://client.example.org/cb/example.com?error=invalid_request&error_description=%5BA124301%5D+The+authorization+request+does+not+contain+%27code_challenge%27+parameter.+See+RFC+7636+for+details.&error_uri=https%3A%2F%2Fwww.authlete.com%2Fdocuments%2Fapis%2Fresult_codes%23A124301",
   "resultCode" : "A124301",
   "resultMessage" : "[A124301] The authorization request does not contain 'code_challenge' parameter. See RFC 7636 for details.",
}

Authlete のサービス側で PKCE を必須としたことにより、同仕様のパラメーターが存在しない場合には、Authlete は認可リクエストを不正とみなし、エラーとします。

それでは、認可リクエストに次の 2 つのパラメーターを追加してみましょう。 本チュートリアルでは簡易的に、元の RFC に例示されている以下の値を用います。 またパラメーターの詳細は 2.2 code_challenge の値 - Proof Key for Code Exchange (RFC 7636) をご参照ください。

項目
code_challenge E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
code_challenge_method S256

認可リクエストのパラメーターとしては以下のようになります(一部折り返しています)。

redirect_uri=https://client.example.org/cb/example.com
 &response_type=code
 &client_id=12800697055611
 &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
 &code_challenge_method=S256

再び curl を実行してみます。 なお <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. 12800697055611>&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256" }'

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

{
   [...]
   "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 = 12800697055611). [response_type=code, openid=false]",
   "ticket" : "9GHLMvWuwIlbu5RaQFFfp8HXcwQAvEi3CNbCEDb8z78",
   "type" : "authorizationResponse"
}

今度は正常に処理が完了したことを示す resultCode とともに、ticket の値が返却されています。 それでは /auth/authorization/issue API を呼び出し、認可コードの生成を行います。 なお <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. 9GHLMvWuwIlbu5RaQFFfp8HXcwQAvEi3CNbCEDb8z78>", "subject": "testuser01" }'

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

{
   "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

トークンリクエスト

クライアントは PKCE のパラメーターを追加したトークンリクエスト(一部折り返しています)を認可サーバーに送信します。 そのパラメーターが code_verifier です。 本チュートリアルでは簡易的に、元の RFC に例示されている以下の値を用います。 詳細は 2.3 code_verifier の値 - Proof Key for Code Exchange (RFC 7636) をご参照ください。

項目
code_verifier dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
POST /token HTTP/1.1
Host: as.example.com
Authorization: Basic base64(12800697055611: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
 &code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk

認可サーバーは Authlete の /auth/token API に、クライアントから受け取ったこれらのパラメーターを送信します。ここでは curl で次のように実行します。パラメータの指定方法が先ほどと変わらない(”parameters" キーの値としてクエリパラメーターを指定する)ことに注目してください。 なお <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. 12800697055611>", "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&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk" }'

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

{
   "action" : "OK",
   "grantType" : "AUTHORIZATION_CODE",
   "accessTokenDuration" : 86400,
   "clientIdAliasUsed" : false,
   "subject" : "testuser01",
   "refreshTokenDuration" : 864000,
   "accessTokenExpiresAt" : 1558544312409,
   "type" : "tokenResponse",
   "refreshToken" : "xpWmT9Mkbvw11RQcZkvrzSL-_OYQYReZ_Nkjff4OHS4",
   "accessToken" : "0ns8-6a2IhT9luPaoserTEX36h-vBGsPXdJCW77j_r8",
   "clientId" : 12800697055611,
   "responseContent" : "{\"access_token\":\"0ns8-6a2IhT9luPaoserTEX36h-vBGsPXdJCW77j_r8\",\"refresh_token\":\"xpWmT9Mkbvw11RQcZkvrzSL-_OYQYReZ_Nkjff4OHS4\",\"scope\":null,\"token_type\":\"Bearer\",\"expires_in\":86400}",
   "resultCode" : "A050001",
   "resultMessage" : "[A050001] The token request (grant_type=authorization_code) was processed successfully.",
   "refreshTokenExpiresAt" : 1559321912409
}

リクエストの処理は正常に完了し、トークンが返却されました。

まとめ

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

  • 認可サーバーに認可コードグラントフローを実装する際の Authlete API の利用方法
  • PKCE を必須とした場合の Authlete API の挙動

次のステップ

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