Table of Contents
本ドキュメントでは、FAPI 2.0 Security Profile で規定される認可コードフローの概要について解説します。また、それに準拠するためのサービス・クライアントの設定方法についても解説します。
FAPI 2.0 Security Profile の機能は Authlete 2.3 以降で利用可能です。
FAPI 2.0 Security Profile で規定される認可コードフローは以下のようになります。
最初に、クライアントは認可サーバーの pushed authorization request エンドポイントに対してリクエストを送信します。これにより、送信された認可リクエストパラメーター群が認可サーバーに登録されます。FAPI 2.0 Security Profile の要請により、認可リクエストパラメーターにはいくつかの要求事項が課されます (response_type=code 等)。また、クライアント認証方法についても mutual TLS authentication または private_key_jwt のいずれかを用いることが要求されます。本ドキュメントではクライアント認証方法として private_key_jwt を用いることに注意してください。
リクエストが正常に処理された場合、pushed authorization request エンドポイントはリクエスト URI (request_uri) を含むレスポンスを返却します。
クライアントはリクエスト URI (request_uri) を含む認可リクエストを認可サーバーの認可エンドポイントに送信します。このステップはユーザーエージェントを通じて行われます。
リクエストが正常に処理された場合、認可エンドポイントから認可コードを含むレスポンスが返却されます。これを受けて、ユーザーエージェントはクライアントのリダイレクト URI へリダイレクトされます。
クライアントは認可コードを含めてトークンエンドポイントへリクエストを送信します。FAPI 2.0 Security Profile による要請から、トークンエンドポイントは mutual TLS または DPoP によって送信者制限されたアクセストークン を発行する必要があります。本ドキュメントでは送信者制限のメカニズムとして DPoP を利用することにします。また、pushed authorization request エンドポイントと同様にトークンエンドポイントでも private_key_jwt によってクライアント認証を行うことに注意してください。
リクエストが正常に処理された場合、トークンエンドポイントはアクセストークンを含むレスポンスを返却します。
クライアントは発行されたアクセストークンとその所有者証明 (本ドキュメントの場合、DPoP proof JWT) を利用して、リソースエンドポイントへアクセスします。
Authlete 2.3 以降、FAPI 2.0 Security Profile のために新たなスコープ属性が導入されました。属性の定義は以下の通りです。
属性のキー | 属性の値 |
---|---|
fapi2 | sp |
以後、本ドキュメントでは、このスコープ属性に紐づけられたスコープを FAPI 2.0 Security Profile スコープ
と呼ぶことにします。以下は、FAPI 2.0 Security Profile スコープ
の一例です。
サービスを FAPI 2.0 Security Profile 準拠にするためには、以下のよう設定にしてください。
プロパティ | 説明 |
---|---|
サポートする認可種別 | AUTHORIZATION_CODE 含める。 |
サポートする応答種別 | CODE を含める。 |
サポートするプロフィール群 | FAPI 含める。 |
iss レスポンスパラメーター | 含める を選択。 |
トークンエンドポイントの URI | 認可サーバーのトークンエンドポイントの URI を設定。 |
サポートするクライアント認証方式 | PRIVATE_KEY_JWT を選択。 |
nbf クレーム | 必須 を選択。 |
オーディエンス確認 | 実行する を選択。 |
アクセストークン署名アルゴリズム | 注意:この設定は JWT 形式のアクセストークンを発される場合のみ必要。PS256 、ES256 、EdDSA のいずれかを選択。 |
サポートするスコープ | FAPI 2.0 Security Profile スコープを作成。 |
JWK セットの内容 | 注意:この設定は “JWK セットの内容” を利用する場合のみ必要。必要な JWK (e.g. JWT アクセストークンの署名用鍵) を含む JWK セットを設定。 |
JWK セットエンドポイントの URI | 注意:この設定は “JWK セットエンドポイントの URI” を利用する場合のみ必要。必要な JWK (e.g. JWT アクセストークンの署名用鍵) を含む JWK セットを指す URI を設定。https で始まる URI を設定すること。 |
クライアントを FAPI 2.0 Security Profile 準拠にするためには、以下のよう設定にしてください。
プロパティ | 説明 |
---|---|
クライアントタイプ | CONFIDENTIAL を選択。 |
認可種別 | AUTHORIZATION_CODE 含める。 |
応答種別 | CODE を含める。 |
リダイレクト URI | リダイレクト URI を少なくとも一つ作成。 |
クライアント認証方式 | PRIVATE_KEY_JWT を選択。 |
アサーション署名アルゴリズム | PS256 、ES256 、EdDSA のいずれかを選択。 |
ID トークン署名アルゴリズム | 注意:この設定は署名された ID トークンが発行される場合のみ必要。PS256 、ES256 、EdDSA のいずれかを選択。 |
ID トークン暗号化アルゴリズム | 注意:この設定は暗号化された ID トークンが発行される場合のみ必要。RSA1_5 以外を選択。 |
JWK セットの内容 | 注意:この設定は “JWK セットの内容” を利用する場合のみ必要。必要な JWK (e.g. クライアントアサーションの署名検証用鍵) を含む JWK セットを設定。 |
JWK セットの URI | 注意:この設定は “JWK セットの URI” を利用する場合のみ必要。必要な JWK (e.g. クライアントアサーションの署名検証用鍵) を含む JWK セットを指す URI を設定。https で始まる URI を設定すること。 |
このセクションでは、FAPI 2.0 Security Profile で規定される認可コードフローにおいて、認可サーバーから Authlete API に対して送信される API コールを実際にシミュレートします。
FAPI 2.0 Security Profile で規定される認可コードフローにおいて、クライアントが認可サーバーの pushed authorization request エンドポイントに対して正常なリクエストを送信したとします。FAPI 2.0 Security Profile, Requirements for Clients における要求事項により、クライアントから認可サーバーへのリクエストは以下のようになります。
POST /par HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&
client_assertion=eyJraWQiOiJjbGllbnQtYXNzZXJ0aW9uLWtleSIsImFsZyI6IkVTMjU2In0.eyJqdGkiOiIyZTQ3MzhkMjNjOWM5YjYyZGNjZCIsInN1YiI6IjEzNDQ2NzM2NDE4IiwiaXNzIjoiMTM0NDY3MzY0MTgiLCJhdWQiOiJodHRwczovL2F1dGhsZXRlLmNvbSIsImlhdCI6MTY1OTk1MDIwNywiZXhwIjoxNjU5OTUzMjA3fQ.VdPzRZ42v62Q2gUfZ-r6aGUL27pY4y5uUkJZRWU9taDHN8z7GtqyyhmmDLfmSuGKglvhmuQvQuv6nJeuQZk5wQ&
client_id=13446736418&
response_type=code&
redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb&
scope=myscope&
code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&
code_challenge_method=S256
scope パラメーターに myscope (FAPI 2.0 Security Profile スコープ) が指定されていることに注意してください。また、pushed authorization request エンドポイントにおけるクライアント認証方式は private_key_jwt であることに注意してください。
認可サーバーがクライアントからリクエストを受けた後、認可サーバーは Authlete の /pushed_auth_req API をコールします。以下の curl コマンドは、認可サーバーから Authlete の /pushed_auth_req API に対するリクエストをシミュレートしたものです。
curl -s -X POST https://api.authlete.com/api/pushed_auth_req \
-u '20699248885:VR6lv6BbPx04p7D7vcx-7YM6OrHVLUQitahPyma6API' \
-H 'Content-type: application/json' \
-d '{
"parameters": "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&\
client_assertion=eyJraWQiOiJjbGllbnQtYXNzZXJ0aW9uLWtleSIsImFsZyI6IkVTMjU2In0.eyJqdGkiOiJmNDE2ODVlZWY0ZWYzOGJjMzkwNiIsInN1YiI6IjEzNDQ2NzM2NDE4IiwiaXNzIjoiMTM0NDY3MzY0MTgiLCJhdWQiOiJodHRwczovL2F1dGhsZXRlLmNvbSIsImlhdCI6MTY2MDE0Mjc2NCwiZXhwIjoxNjYwMTQ1NzY0fQ.vagMXCXtrM9cai6ZID6Y3SyCw6FixAY2MGWkzx2-inwKcxpP1KHDX9iSiDiK75vF0cItwxGAALtcdfyoxWaw3A&\
client_id=13446736418&response_type=code&redirect_uri=https%3A%2F%2Fclient.example.com%2Fcb&\
scope=myscope&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&\
code_challenge_method=S256"
}'
/pushed_auth_req API からの正常レスポンスは以下のようになります。
{
"type": "pushedAuthReqResponse",
"resultCode": "A245001",
"resultMessage": "[A245001] Successfully registered a request object for client (13446736418), URI is urn:ietf:params:oauth:request_uri:QbGjdHSfZi_m6W_ldrqjZhmYjQo3QcQOd3Hx2RcGODg.",
"action": "CREATED",
"requestUri": "urn:ietf:params:oauth:request_uri:QbGjdHSfZi_m6W_ldrqjZhmYjQo3QcQOd3Hx2RcGODg",
"responseContent": "{\"expires_in\":600,\"request_uri\":\"urn:ietf:params:oauth:request_uri:QbGjdHSfZi_m6W_ldrqjZhmYjQo3QcQOd3Hx2RcGODg\"}"
}
pushed authorization request エンドポイントからリクエスト URI が発行された後、クライアントは認可サーバーの認可エンドポイントに対して当該リクエスト URI を含めた認可リクエストを送信します。 以下はリクエストの例です。
GET /authorization?client_id=13446736418&
request_uri=urn%3Aietf%3Aparams%3Aoauth%3Arequest_uri%3AQbGjdHSfZi_m6W_ldrqjZhmYjQo3QcQOd3Hx2RcGODg HTTP/1.1
Host: server.example.com
クライアントから認可リクエストを受けた後、認可サーバーは Authlete の /auth/authorization API をコールします。以下の curl コマンドは、認可サーバーから Authlete の /auth/authorization API に対するリクエストをシミュレートしたものです。
curl -s -X POST https://api.authlete.com/api/auth/authorization \
-u '20699248885:VR6lv6BbPx04p7D7vcx-7YM6OrHVLUQitahPyma6API' \
-H 'Content-type: application/json' \
-d '{"parameters":"client_id=13446736418
&request_uri=urn%3Aietf%3Aparams%3Aoauth%3Arequest_uri%3AQbGjdHSfZi_m6W_ldrqjZhmYjQo3QcQOd3Hx2RcGODg"}'
/auth/authorization API からの正常レスポンスは以下のようになります。
{
"type": "authorizationResponse",
"resultCode": "A004001",
"resultMessage": "[A004001] Authlete has successfully issued a ticket to the service (API Key = 20699248885) for the authorization request from the client (ID = 13446736418). [response_type=code, openid=false]",
...
"ticket": "CBKnPeMOf9xfv0sV-srVzbZv_dtFh01Zc0VkQ2nQKFg"
}
認可サーバーが /auth/authorization API から正常レスポンスを受けた後、エンドユーザーはブラウザ上でクライアントを認可/拒否し、その結果が認可サーバーに伝達されます。それを受けて、認可サーバーは Authlete の /auth/authorization/issue API をコールします。以下の curl コマンドは、認可サーバーから Authlete の /auth/authorization/issue API に対するリクエストをシミュレートしたものです。
curl -s -X POST https://api.authlete.com/api/auth/authorization/issue \
-u '20699248885:VR6lv6BbPx04p7D7vcx-7YM6OrHVLUQitahPyma6API' \
-H 'Content-type: application/json' \
-d '{"ticket":"CBKnPeMOf9xfv0sV-srVzbZv_dtFh01Zc0VkQ2nQKFg",
"subject":"john",
"result":"AUTHORIZED"
}'
/auth/authorization/issue API からの正常レスポンスは以下のようになります。
{
"type": "authorizationIssueResponse",
"resultCode": "A040001",
"resultMessage": "[A040001] The authorization request was processed successfully.",
"authorizationCode": "xY1Vd-rjb-Yj84sXGgkr424VR9JbVGQw2wgVbudSXGU",
...
}
認可エンドポイントから認可コードを含むレスポンスを受けた後、クライアントは認可サーバーのトークンエンドポイントに対して以下のようなリクエストを送ります。
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDIiwidXNlIjoic2lnIiwiY3J2IjoiUC0yNTYiLCJ4IjoiRk4xYk81cnBVY0ZNeU9ncE9iQ1BTaGZkcldJ
TFN1RVBBTmZKUWl4cU16ayIsInkiOiJYY3RYc0xXY1YzMkJMVVZCMDhqVjJ4d2VFU2FTY0xULVNKUEl6TlVoSHRvIiwiYWxnIjoiRVMyNTYifX0.eyJqdGkiOiI0OWE1YWU0ZTA5NTZiNDJkMjEwMyIsImh0bSI6IlBPU1QiLCJodHUiOiJodHRwczovL3NlcnZlci5leGFtcGxlLmNvbS90b2tlbiIsImlhdCI6MTY2MDE0Mjk2N30.codEOIUYuytFacobXDn4-Jx7xr6oRaw83lorgPbOS1y5pMyDCfUf08SA9tCUWMMUctgGdt7D9wf7hDCip6lgTA
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJraWQiOiJjbGllbnQtYXNzZXJ0aW9uLWtleSIsImFsZyI6IkVTMjU2In0.eyJqdGkiOiJmYzRkMDRlMTI0MTRjNzU5OGNlNyIsInN1YiI6IjEzNDQ2NzM2NDE4IiwiaXNzIjoiMTM0NDY3MzY0MTgiLCJhdWQiOiJodHRwczovL2F1dGhsZXRlLmNvbSIsImlhdCI6MTY2MDE0Mjk2NCwiZXhwIjoxNjYwMTQ1OTY0fQ.-Gn4X3d_ymujjhSh8ZLWdtOzq2-TcgvwGzU-NEjVDaJSLN8kpOVHguOytSDXqJW5QJcsH8J_bkTaVZV7Nyl2IA
&client_id=13446736418
&code=xY1Vd-rjb-Yj84sXGgkr424VR9JbVGQw2wgVbudSXGU
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&grant_type=authorization_code
&code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
クライアントが
ことに注意してください。
その後、認可サーバーは Authlete の /auth/token
API をコールします。以下の curl コマンドは、認可サーバーから Authlete の /auth/token API に対するリクエストをシミュレートしたものです。
curl -s -X POST https://api.authlete.com/auth/token \
-u '20699248885:VR6lv6BbPx04p7D7vcx-7YM6OrHVLUQitahPyma6API' \
-H 'Content-type: application/json' \
-d {"parameters":"client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=eyJraWQiOiJjbGllbnQtYXNzZXJ0aW9uLWtleSIsImFsZyI6IkVTMjU2In0.eyJqdGkiOiJmYzRkMDRlMTI0MTRjNzU5OGNlNyIsInN1YiI6IjEzNDQ2NzM2NDE4IiwiaXNzIjoiMTM0NDY3MzY0MTgiLCJhdWQiOiJodHRwczovL2F1dGhsZXRlLmNvbSIsImlhdCI6MTY2MDE0Mjk2NCwiZXhwIjoxNjYwMTQ1OTY0fQ.-Gn4X3d_ymujjhSh8ZLWdtOzq2-TcgvwGzU-NEjVDaJSLN8kpOVHguOytSDXqJW5QJcsH8J_bkTaVZV7Nyl2IA
&client_id=13446736418
&code=xY1Vd-rjb-Yj84sXGgkr424VR9JbVGQw2wgVbudSXGU
&redirect_uri=h...
/auth/token API からの正常レスポンスは以下のようになります。
{
"type": "tokenResponse",
"resultCode": "A050001",
"resultMessage": "[A050001] The token request (grant_type=authorization_code) was processed successfully.",
"accessToken": "7i9xPkbkKCmcmkZIvSGci5PKf4HO9TUAefwsABMrbTQ",
...
}
以上のステップを経て、認可サーバーはクライアントに対してアクセストークンを発行します。クライアントはそのアクセストークンを利用して、リソースサーバーのエンドポイントにアクセスします。以下はリクエストの例です。
GET /api/sample?client_id=13446736418&request_uri=urn%3Aietf%3Aparams%3Aoauth%3Arequest_uri%3AQbGjdHSfZi_m6W_ldrqjZhmYjQo3QcQOd3Hx2RcGODg HTTP/1.1
Authorization: DPoP 7i9xPkbkKCmcmkZIvSGci5PKf4HO9TUAefwsABMrbTQDPoP: eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDIiwidXNlIjoic2lnIiwiY3J2IjoiUC0yNTYiLCJ4IjoiRk4xYk81cnBVY0ZNeU9ncE9iQ1BTaGZkcldJTFN1RVBBTmZKUWl4cU16ayIsInkiOiJYY3RYc0xXY1YzMkJMVVZCMDhqVjJ4d2VFU2FTY0xULVNKUEl6TlVoSHRvIiwiYWxnIjoiRVMyNTYifX0.eyJqdGkiOiI5YWMwYTRjYWM1ODA4MmZlYzQxOSIsImh0bSI6IkdFVCIsImh0dSI6Imh0dHBzOi8vcmVzb3VyY2UuZXhhbXBsZS5jb20vYXBpL3NhbXBsZSIsImlhdCI6MTY2MDE0MzAzMiwiYXRoIjoiaDdacFQ2VnJCU3JpaGdYSDA1ZE5tM3VvQ0x5TmVXYWNfZHFkOUhOOUktbyJ9.avJW2u8Gasm2wpXi4XlxJ2Z4A4WsgXm5jFscbN893vRzcxqZU4AwK0J5Tosk4T1d9WmL5wnZKnAEy2Gb9L2_pQ
Host: resource.example.com
DPoP リクエストヘッダーに DPoP proof JWT が含まれていることに注意してください。
リソースエンドポイントはクライアントからのリクエストを受けた後、Authlete の /auth/introspection API をコールし、アクセストークンの検証を行います。以下の curl コマンドは、リソースサーバーから Authlete の /auth/introspection API に対するリクエストをシミュレートしたものです。
curl -s -X POST https://api.authlete.com/api/auth/introspection \
-u '20699248885:VR6lv6BbPx04p7D7vcx-7YM6OrHVLUQitahPyma6API' \
-H 'Content-type: application/json' \
-d {"token":"7i9xPkbkKCmcmkZIvSGci5PKf4HO9TUAefwsABMrbTQ",
"dpop":"eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjp7Imt0eSI6IkVDIiwidXNlIjoic2lnIiwiY3J2IjoiUC0yNTYiLCJ4IjoiRk4xYk81cnBVY0ZNeU9ncE9iQ1BTaGZkcldJTFN1RVBBTmZKUWl4cU16ayIsInkiOiJYY3RYc0xXY1YzMkJMVVZCMDhqVjJ4d2VFU2FTY0xULVNKUEl6TlVoSHRvIiwiYWxnIjoiRVMyNTYifX0.eyJqdGkiOiI5NmYzNDc4OWFjNWFmZDNkMzhhNiIsImh0bSI6IkdFVCIsImh0dSI6Imh0dHBzOi8vcmVzb3VyY2UuZXhhbXBsZS5jb20vYXBpL3NhbXBsZSIsImlhdCI6MTY1OTk1MDUyNywiYXRoIjoidmdDa3JDWEhIYTQ3VVpVazdJNVk4QmFKdWxWek9KMFhEMVNzZGdWdHVKSSJ9.ysI4w__vdqVPOjjVhUidhHoletEOmvSMJD6TdqUIM49KIGcjxjgVpaVA-D5yKnEs_4aRGkt_tsRiSsHUNam9KA",
"htm":"GET",
"htu":"https://resource.example.com/api/sample"
}'
/auth/introspection API からの正常レスポンスは以下のようになります。
{
"type": "introspectionResponse",
"resultCode": "A056001",
"resultMessage": "[A056001] The access token is valid.",
"action": "OK",
...
}