- トークン全般
- アクセストークン
- リフレッシュトークン
- ID トークン
-
所持証明 (PoP) トークン
- TLS クライアント証明書を結びつけたアクセストークンの発行
- DPoP の利用
- 認可タイプ
- スコープ
- PKCE (RFC 7636)
- クライアント管理
- 認可リクエスト
- ユーザー認証
- エラー処理
- クライアント認証
- イントロスペクション
- Userinfo エンドポイント
- JARM
- デバイスフロー (RFC 8628)
TLS クライアント証明書を結びつけたアクセストークンの発行
はじめに
本記事では、“RFC 8705 OAuth 2.0 Mutual-TLS Client Authentication and Certificate-Bound Access Tokens” にて規定されている “Mutual-TLS certificate-bound access tokens” を利用するための、Authlete の設定手順を説明します。
動作のしくみ
“Mutual-TLS certificate-bound access tokens” の設定が有効化されている場合、Authlete の API は次の処理を行います。
-
/auth/token API
- クライアント証明書 (clientCertificate) をリクエストパラメーターとして受け取り、発行するアクセストークンに結びつけます。
- JWT 形式のアクセストークンが有効化されている場合には、発行するアクセストークンに、クライアント証明書の情報(サムプリント)を含めます。
-
/auth/introspection API
- アクセストークン (token) とクライアント証明書 (clientCertificate) をリクエストパラメーターとして受け取り、両者が結びついているかを確認します。
-
/auth/introspection/standard API
- アクセストークン (token) を、リクエストパラメーターのひとつ (parameters) に含まれる値として受け取り、そのトークンに結びついているクライアント証明書の情報(サムプリント)を返却します。
これにより、相互 TLS によってクライアント証明書を提示できたクライアントのみが、そのアクセストークンの所持を証明し、API リクエストに利用できる(言い換えれば、他のクライアントが利用できない)ようになります。
設定
サービス側のアクセストークン設定
Authlete のサービス管理者コンソールにログインし、 「トークン」タブの「アクセストークン」セクションにおいて以下を設定します。
項目 |
値 |
TLS クライアント証明書を紐付けたアクセストークンのサポート |
サポートする |

クライアント側のアクセストークン設定
Authlete のクライアントアプリ開発者コンソールにアクセスし、 「基本情報」タブにおいて以下を設定します。
項目 |
値 |
TLS クライアント証明書を紐付けたアクセストークンの使用 |
使用する |

以上により、“Mutual-TLS certificate-bound access tokens” が利用可能となります。
実行例
以下は設定後の、各 API の実行例です。(読みやすさのため折り返しています)
/auth/token API
リクエスト
認可サーバーはクライアントとの相互 TLS 接続から得られたクライアント証明書を "clientCertificate" の値として指定し、Authlete にリクエストを送信します。
$ curl -s -X POST https://api.authlete.com/api/auth/token \ -u ...:... \ -H 'Content-type: application/json' \ -d '{'\ '"clientCertificate":"-----BEGIN CERTIFICATE-----\n MIIDPDCCAiQCCQDfkemtGUyxAjANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJK\n UDEOMAwGA1UECAwFVG9reW8xEzARBgNVBAcMCkNoaXlvZGEta3UxDzANBgNVBAoM\n BkNsaWVudDEbMBkGA1UEAwwSY2xpZW50LmV4YW1wbGUub3JnMB4XDTIwMDUxMTEx\n MDcyM1oXDTIxMDUxMTExMDcyM1owYDELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRv\n a3lvMRMwEQYDVQQHDApDaGl5b2RhLWt1MQ8wDQYDVQQKDAZDbGllbnQxGzAZBgNV\n BAMMEmNsaWVudC5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n AQoCggEBAMu7V2QyQk4iLPry0OsykR/8WO2aNOBNoVZYDexF1TsFv9s2S4PEDFEt\n 1BZrEmBe5HWpGb1iuDGG6wjAanEkea8AIUgslMsOOB0rQnbJA3nI5wktjCG2VzWo\n zrmxAAaBM7ixaLPcJT1K0FSu4fzse3X9gtA2rtNGwk1JEMNIBpFghxw7zzUZBduS\n lkVPPcQ3gPGVutiWfNPNPAqb4eMKwtuTPXbZSJ4RO9xGKMIuoaBWO9xPS6rNy+Kr\n vOckNEsR+8PBYh9vzbmF0mDlk+BMd9sOGyylYBARFdqukMJnSbVcRvr+Gcaf+QSg\n FRHkVGWXHXtMRI+MsCvOXrhmlJhxbdMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA\n JfEyXTEGdjchre2dFCa/WLdH5PZBqB+E0Umm+/I+puA+aUpkRaOfmIUPNaCZ1Lgg\n mOo8BGuEG0oXpOSBoRkxf46d1bxJk5YSe+TgSxS6YX/mE6Lt1Aj7HjojlCuNFGS6\n vzyEugQSsOjuoIPS32PvqmZ+80jzVNUsMD76xGl32ZsVeJmDnogVPZ4NlolQcmH2\n bYjK00uPXaUU30IVu+UTrEBhe30My/aW31NbT2I7Ct52wwu67pyP3QOKmuLxMd6N\n +KkxfIY23zla4herq9vWZejgfBfkAwOapeIIHGYtY7IFxm6nqufb4h71vjeoouOt\n 31J7bEcAU9WRP1Pr/X4hLA==\n-----END CERTIFICATE-----\n",'\ '"parameters"':\ '"redirect_uri=https://client.example.org/cb/example.com'\ '&grant_type=authorization_code'\ '&client_id=...'\ '&code=smA...Gp4"'\ }'
レスポンス
クライアント証明書に結びつけられたアクセストークンが発行されます。
{ "type": "tokenResponse", "resultCode": "A050001", "resultMessage": "[A050001] The token request (grant_type=authorization_code) was processed successfully.", "accessToken": "AHu...MMs", "accessTokenDuration": 86400, "accessTokenExpiresAt": 1591935416474, "action": "OK", "clientId": 17566160603766, "clientIdAliasUsed": false, "grantType": "AUTHORIZATION_CODE", "refreshToken": "_zkZeqy6pLdFerpwqJPh0S0gEZsSj9EbmwVsN92WNsE", "refreshTokenDuration": 864000, "refreshTokenExpiresAt": 1592713016474, "responseContent": "{\"access_token\":\"AHu...MMs\", \"refresh_token\":\"_zk...NsE\", \"scope\":null, \"token_type\":\"Bearer\", \"expires_in\":86400}", "subject": "testuser01" }
JWT 形式のアクセストークンの場合には、以下のようなアクセストークンになります。
eyJraWQiOiIxIiwiYWxnIjoiRVMyNTYifQ. eyJzdWIiOiJ0ZXN0dXNlcjAxIiwic2NvcGUiOm51bGwsImlzcyI6Imh0dHBzOi8 vYXMuZXhhbXBsZS5jb20iLCJjbmYiOnsieDV0I1MyNTYiOiJPSURfU2MyeVJlVE R4OVFTN2YxU01Vek54c2g3a2hKWW1hSXdxWHc4WXV3In0sImV4cCI6MTU5MTkzO TMyNiwiaWF0IjoxNTkxODUyOTI2LCJjbGllbnRfaWQiOiIxNzU2NjE2MDYwMzc2 NiIsImp0aSI6InN6dDVnV0ZTb3ZGSVU1Ti13amRMeUZELUVpUzNyZEcyS1IzMTF CMkY2RmMifQ. Pw3IntOrXDqW3Z5eoGSeeJaPG5n1aKEVokgbUh_BJpqzuZ6F6GDDLhj98XBvjii x9oAmaTpy39ijl1vcq3r1BA
このアクセストークンのペイロード部には、以下のように、証明書のサムプリントが含まれます。
{ "sub": "testuser01", "scope": null, "iss": "https://as.example.com", "cnf": { "x5t#S256": "OID_Sc2yReTDx9QS7f1SMUzNxsh7khJYmaIwqXw8Yuw" }, "exp": 1591939326, "iat": 1591852926, "client_id": "17566160603766", "jti": "szt5gWFSovFIU5N-wjdLyFD-EiS3rdG2KR311B2F6Fc" }
/auth/introspection API
リクエスト
リソースサーバーはクライアントとの相互 TLS 接続から得られたクライアント証明書を "clientCertificate" の値として指定し、Authlete にリクエストを送信します。
$ curl -s -X POST https://api.authlete.com/api/auth/introspection \ -u ...:... -H 'Content-type: application/json' \ -d '{'\ '"token":"AHu...MMs",'\ '"clientCertificate":"-----BEGIN CERTIFICATE-----\n MIIDPDCCAiQCCQDfkemtGUyxAjANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJK\n UDEOMAwGA1UECAwFVG9reW8xEzARBgNVBAcMCkNoaXlvZGEta3UxDzANBgNVBAoM\n BkNsaWVudDEbMBkGA1UEAwwSY2xpZW50LmV4YW1wbGUub3JnMB4XDTIwMDUxMTEx\n MDcyM1oXDTIxMDUxMTExMDcyM1owYDELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRv\n a3lvMRMwEQYDVQQHDApDaGl5b2RhLWt1MQ8wDQYDVQQKDAZDbGllbnQxGzAZBgNV\n BAMMEmNsaWVudC5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\n AQoCggEBAMu7V2QyQk4iLPry0OsykR/8WO2aNOBNoVZYDexF1TsFv9s2S4PEDFEt\n 1BZrEmBe5HWpGb1iuDGG6wjAanEkea8AIUgslMsOOB0rQnbJA3nI5wktjCG2VzWo\n zrmxAAaBM7ixaLPcJT1K0FSu4fzse3X9gtA2rtNGwk1JEMNIBpFghxw7zzUZBduS\n lkVPPcQ3gPGVutiWfNPNPAqb4eMKwtuTPXbZSJ4RO9xGKMIuoaBWO9xPS6rNy+Kr\n vOckNEsR+8PBYh9vzbmF0mDlk+BMd9sOGyylYBARFdqukMJnSbVcRvr+Gcaf+QSg\n FRHkVGWXHXtMRI+MsCvOXrhmlJhxbdMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA\n JfEyXTEGdjchre2dFCa/WLdH5PZBqB+E0Umm+/I+puA+aUpkRaOfmIUPNaCZ1Lgg\n mOo8BGuEG0oXpOSBoRkxf46d1bxJk5YSe+TgSxS6YX/mE6Lt1Aj7HjojlCuNFGS6\n vzyEugQSsOjuoIPS32PvqmZ+80jzVNUsMD76xGl32ZsVeJmDnogVPZ4NlolQcmH2\n bYjK00uPXaUU30IVu+UTrEBhe30My/aW31NbT2I7Ct52wwu67pyP3QOKmuLxMd6N\n +KkxfIY23zla4herq9vWZejgfBfkAwOapeIIHGYtY7IFxm6nqufb4h71vjeoouOt\n 31J7bEcAU9WRP1Pr/X4hLA==\n-----END CERTIFICATE-----\n"'\ '}'
レスポンス
アクセストークン (token) とクライアント証明書 (clientCertificate) の結びつきが確認できた場合には、以下のようなレスポンスが返却されます。このレスポンスには、クライアント証明書のサムプリント(certificateThumbprint) が含まれています。
{ "type": "introspectionResponse", "resultCode": "A056001", "resultMessage": "[A056001] The access token is valid.", "action": "OK", "certificateThumbprint": "OID_Sc2yReTDx9QS7f1SMUzNxsh7khJYmaIwqXw8Yuw", "clientId": ..., "clientIdAliasUsed": false, "existent": true, "expiresAt": 1591936228000, "refreshable": true, "responseContent": "Bearer error=\"invalid_request\"", "subject": "testuser01", "sufficient": true, "usable": true }
/auth/introspection/standard API
リクエスト
リソースサーバーは認可サーバーのトークンイントロスペクションエンドポイントに、対象のアクセストークンを送信します。認可サーバーはそのリクエスト内容を Authlete に転送します。
$ curl -s -X POST https://api.authlete.com/api/auth/introspection/standard \ -u ...:... -H 'Content-type: application/json' \ -d '{ "parameters":"token=AHu...MMs" }'
レスポンス
アクセストークンに結びつくクライアント証明書が確認できた場合には、Authlete はその証明書のサムプリントを含む responseContent を返却します。認可サーバーはこの responseContent をリソースサーバーに、トークンイントロスペクションエンドポイントからのレスポンスとして返却します。
{ "type": "standardIntrospectionResponse", "resultCode": "A145001", "resultMessage": "[A145001] Introspection was performed successfully (type=access_token, active=true).", "action": "OK", "responseContent": "{\"sub\":\"testuser01\", \"scope\":null, \"iss\":\"https://as.example.com\", \"active\":true, \"cnf\":{\"x5t#S256\":\"OID_Sc2yReTDx9QS7f1SMUzNxsh7khJYmaIwqXw8Yuw\"}, \"token_type\":\"Bearer\", \"exp\":1591936228, \"client_id\":\"17566160603766\"}" }
How did we do with this article?