OAuth 2.0 Basics

はじめに

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

構成

本チュートリアルでは以下の構成を想定します。 なお、実サービスとして動作するのは、Authlete のコンソールと API だけです。

認可サーバーとリソースサーバーはいずれも実際には存在しませんが、 それぞれのサーバーがクライアントから認可リクエストやトークンリクエスト、そしてトークンイントロスペクションリクエストを受信したときに、 どのような API リクエストを Authlete に行うかを、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 API サービスの作成と、そのサービスへのクライアント登録を行います。

本チュートリアルでは、環境設定の結果として以下の値を生成・指定したものとします。

項目
クライアント 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 の PowerShell から curl.exe コマンドを用いる場合には、以下のようになります。curl ではなく curl.exe とすること、" をエスケープすること、行の区切りに ` を用いることにご注意ください。(メッセージ番号 4)。 なお、API Key, API Secret, Client ID は、本チュートリアルの過程にて生成された値に置き換えてください。

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" }'

curl.exe コマンドを以下のように実行します(メッセージ番号 8)。なお、API Key, API Secret, Ticket は、本チュートリアルの過程にて生成された値に置き換えてください。

curl.exe -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" }'

curl.exe コマンドを以下のように実行します(メッセージ番号 13)。なお、API Key, API Secret, Client ID, Client Secret, Code は、本チュートリアルの過程にて生成された値に置き換えてください。

curl.exe -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>" }'

curl.exe コマンドを以下のように実行します(メッセージ番号 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)。

まとめ

本チュートリアルでは、認可サーバーに認可コードグラントフローを実装する際の Authlete API の利用方法について、実際の動作を確認しました。

次のステップ

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