Table of Contents
このドキュメントでは、Authlete を利用した Financial-grade API Security Profile 1.0 - Part 2: Advanced (以下 FAPI)対応のアイデンティティ・プロバイダーを構築する手順を通じて、同仕様が規定するセキュリティ条項の概要と Authlete の設定方法を紹介します。
手順の実施にあたっては、以下のチュートリアルの実施とナレッジベース記事の通読を行い、 OpenID Connect と Authlete に関する基本的な理解を有していることが必須です。
本チュートリアルでは以下の構成を想定します。 なお、実サービスとして動作するのは、Authlete のコンソールと API だけです。
認可サーバー(OIDC アイデンティティプロバイダー)とリソースサーバーはいずれも実際には存在しませんが、 それぞれのサーバーがクライアント(OIDC リライングパーティ)から認可リクエストやトークンリクエスト、そしてトークンイントロスペクションリクエストを受信したときに、 どのような 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 |
認可サーバー(OIDC アイデンティティプロバイダー) (Authorization Server) | as.example.com |
クライアント(OIDC リライングパーティ) (Client) | client.example.org |
リソースサーバー (Resource Server) | N/A |
本ドキュメントでは、FAPI に準拠した以下のトークン授受・利用フローに対応するための設定を行います。
クライアントはリクエストオブジェクトを用いた認可リクエストを作成・送信する必要があります。
リクエストオブジェクトは値渡し(request
パラメーターを使用)もしくは参照渡し(request_uri
パラメーターを使用)のいずれかとなります。本ドキュメントでは前者を用います。
また、response_type
パラメーターの指定についても FAPI の規定に従う必要があります。
response_type
として本ドキュメントでは code id_token
を用います。
response_type
として code
を用いる場合には、JARM (JWT Secured Authorization Response Mode for OAuth 2.0) の設定が必要です。
その他、claims
の設定などについては後述します。
本ドキュメントでは、認可リクエストに response_type=code id_token
が指定されることから、フラグメントとして code
を返却します。
トークンリクエストでは、認可サーバーはクライアントを認証する方法として公開鍵方式を用いる必要があります。 本ドキュメントでは TLS 双方向認証を用います。
認可サーバーは、トークンエンドポイントに提示されるクライアント証明書と、発行するアクセストークンとをバインド(ひもづけ)し、トークンレスポンスを返却します。
クライアントとリソースサーバーは、TLS 双方向認証を用いてクライアント認証を行った上で、アクセストークンを含む API リクエストを送受信します。 リソースサーバーはクライアント証明書とアクセストークンとのひもづけを検証の上、API レスポンスを返却します。
Authlete のサービス管理者コンソール https://so.authlete.com/
にログインし、右側の「サービス作成」をクリックします。
するとサービス作成のページが表示されます。「サービス名」と「トークン発行者識別子」を以下に従い入力し、「作成」をクリックします。
確認のダイアログが表示されるので「OK」をクリックします。
項目 | 値 |
---|---|
サービス名 | 任意の値(例: FAPI Service ) |
トークン発行者識別子 | https://as.example.com |
サービスを作成すると「APIキー」と「APIシークレット」が自動生成されます。 これらの値は、次にクライアントアプリ開発者コンソールにログインするときのログインID・パスワードとして用いるとともに、 認可サーバーが Authlete API にリクエストを行う際のクレデンシャルとなります。
項目 | 値 |
---|---|
API キー | 自動生成された値(例: 174381609020 ) |
API シークレット | 自動生成された値(例: LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k ) |
このサービスの FAPI サポートを有効化しましょう。 下方にある「編集」ボタンをクリックし、内容を編集可能にします。 「認可」タブの設定項目の中に「サポートするプロフィール群」があり、 「FAPI」チェックボックスにチェックが入っていない状態になっているはずです。 ここにチェックを入れて、下方にある「更新」ボタンをクリックします。 確認のダイアログが表示されるので「OK」をクリックします。
次に、再度「編集」ボタンをクリックし、内容を編集可能にします。
「トークン」タブの設定項目の中に「サポートするスコープ」があり、
address
や openid
などの既定スコープが表示されているはずです。
この項目の右側にある「スコープ作成」ボタンをクリックすると、スコープ作成のダイアログが表示されます。
ここでは以下の内容のスコープを作成します。
fapi
、値: rw
を追加すると、Authlete はそのスコープが要求された場合に FAPI 準拠の処理を行います。スコープ属性についてはナレッジベースの記事をご参照ください。
項目 | 値 |
---|---|
スコープ名 | payment |
デフォルト設定 | 非デフォルト |
説明 | 任意の値 |
スコープの属性群(「属性作成」をクリックして追加) | 属性のキー: fapi / 属性値: rw |
Authlete のクライアントアプリ開発者コンソール(https://cd.authlete.com/<API キー>
例: https://cd.authlete.com/174381609020
)にアクセスし、
ログイン ID として先ほど作成したサービスの「API キー」を、
パスワードとして同じく「API シークレット」を用いてログインします。
ログイン後、右手にある「アプリ作成」をクリックすると、 アプリ作成のページが表示されます。まず「基本情報」タブでは、任意の「クライアント名」を入力し、 クライアントタイプとして 「CONFIDENTIAL」 を選択します。
項目 | 値 |
---|---|
クライアント名 | 任意の値(例: FAPI Client ) |
クライアントタイプ | CONFIDENTIAL |
次に、「基本情報」タブの隣にある「認可」タブをクリックし、「リダイレクト URI」セクションにある「リダイレクト URI 作成」をクリックして、 以下のリダイレクト URI を作成します。
項目 | 値 |
---|---|
リダイレクト URI | https://client.example.org/cb/example.com |
指定後、ページ下方にある「作成」をクリックします。 確認のダイアログが表示されるので「OK」をクリックします。
これにより、サービスへのクライアント情報の登録が完了しました。
自動生成された「クライアント ID」は、
クライアントが認可サーバーにリクエストを行う際の client_id
の値として用いられます。
なお、同時に「クライアントシークレット」も生成されていますが、
本チュートリアルでは使いません。
また、そのほか指定した各値が正しく設定されていることも確認しましょう。
項目 | 値 |
---|---|
クライアント ID | 自動生成された値(例: 591205987816490 ) |
クライアントタイプ | CONFIDENTIAL |
リダイレクト URI | https://client.example.org/cb/example.com |
上記の設定によって Authlete がどのように動作するかを、まず /auth/authorization
API を用いて確認します。
認可サーバーが、FAPI-RW 対象のスコープが含まれない (scope=openid
のみの) 認可リクエストを受信したと仮定し、
/auth/authorization
API に対して以下のリクエストを送信します。
curl -s -X POST https://api.authlete.com/api/auth/authorization \
-u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' \
-H 'Content-Type: application/json' \
-d '{"parameters": "redirect_uri=https://client.example.org/cb/example.com&scope=openid&response_type=code&client_id=591205987816490&nonce=n-0S6_WzA2Mj"}' |jq
すると、以下のようなレスポンス(一部折り返しています)が返却されます。
{
"type": "authorizationResponse",
"resultCode": "A004001",
"resultMessage": "[A004001] Authlete has successfully issued a ticket
to the service (API Key = 174381609020) for the authorization request
from the client (ID = 591205987816490). [response_type=code, openid=true]",
[...]
resultMessage
の記述から、scope=openid
のように、FAPI 対象ではないスコープの場合には、認可リクエストが Authlete に受け入れられたことがわかります。
それでは、FAPI の対象となるスコープの場合にはどのようになるか、次に試してみます。
認可サーバーが、FAPI 対象のスコープ(payment
)を含む認可リクエスト(scope=openid payment
)を受信したと仮定し、
/auth/authorization
API に対して以下のリクエストを送信します。
curl -s -X POST https://api.authlete.com/api/auth/authorization \
-u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' \
-H 'Content-Type: application/json' \
-d '{"parameters": "redirect_uri=https://client.example.org/cb/example.com&scope=openid+payment&response_type=code&client_id=591205987816490&nonce=n-0S6_WzA2Mj"}' |jq
すると、以下のようなエラーレスポンスが返却されます。
{
"type": "authorizationResponse",
"resultCode": "A150312",
"resultMessage": "[A150312] The value of 'response_type' (code) is not allowed.",
[...]
resultMessage
の内容を見ると、response_type=code
は許可されていないことがわかります。
これは FAPI の 5.2. Advanced security provisions / 5.2.2. Authorization server に
- shall require
- the
response_type
valuecode id_token
, or- the
response_type
valuecode
in conjunction with theresponse_mode
valuejwt
;
とある通り、FAPI では response_type=code id_token
か、もしくは response_mode=jwt
を指定した上でresponse_type=code
の、どちらかを用いなくてはならないからです。
つまり response_type=code
のみの指定は禁止されている(認可サーバーはそのようなレスポンスタイプを受け付けてはならない)のです。
それでは、response_type=code
ではなく response_type=code id_token
とした認可リクエストの場合にはどうなるでしょうか。
/auth/authorization
API に対して以下のリクエストを送信します。
curl -s -X POST https://api.authlete.com/api/auth/authorization \
-u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' \
-H 'Content-Type: application/json' \
-d '{"parameters": "redirect_uri=https://client.example.org/cb/example.com&scope=openid+payment&response_type=code+id_token&client_id=591205987816490&nonce=n-0S6_WzA2Mj"}' |jq
すると以下のような異なるエラーレスポンスが返却されます。
{
"type": "authorizationResponse",
"resultCode": "A150301",
"resultMessage": "[A150301] A request object is required.",
[...]
resultMessage
の記述から、この場合には、リクエストオブジェクトが必要だとわかります。
これは上述と同じく、FAPI の 5.2. Advanced security provisions / 5.2.2. Authorization server に
- shall only use the parameters included in the signed request object passed via the
request
orrequest_uri
parameter;
とある通り、FAPI では、認可サーバーはクライアントに対して、リクエストオブジェクトを値渡し(request
)ないし参照渡し(request_uri
)にて認可リクエストに含めるよう、
要求しなくてはならないからです。
それでは次に、リクエストオブジェクトを用いた認可リクエストを準備してみましょう。
本セクションでは、リクエストオブジェクトを用いた認可リクエストを作成します。
まず、クライアントがリクエストオブジェクトに署名するための鍵を準備します。
ここでは例として、 mkjwk を用いて、ES256 の鍵ペアを生成し、 2 種類(秘密鍵を含むもの・含まないもの)の鍵セットを生成します。 パラメーターは以下の通り選択・入力しています。
項目 | 値 |
---|---|
タブ | EC (楕円曲線) |
曲線 | P-256 |
鍵の用途 | Signing |
アルゴリズム | ES256 (ECDSA using P-256 and SHA-256) |
鍵の ID | 任意の値(例: 1 ) |
以下は生成された鍵セットの例です。
es256_keyset.txt
(秘密鍵 "d"
の行を含む){
"keys": [
{
"kty": "EC",
"d": "L6KxA-db4oh5NKYEpO6IulUDSRXP7fqNAmScu6fygIE",
"use": "sig",
"crv": "P-256",
"kid": "1",
"x": "icP8p_AigyTzwSpLRyv_bBQTSGu_NG7pMVXd-RAxwYE",
"y": "06tC0MJeBlZNYlnY8g4bCA9wJ34XN-rWfWlmmlhf-F0",
"alg": "ES256"
}
]
}
es256_keyset_pub.txt
(es256_keyset.txt
から秘密鍵 "d"
の行を削除){
"keys": [
{
"kty": "EC",
"use": "sig",
"crv": "P-256",
"kid": "1",
"x": "icP8p_AigyTzwSpLRyv_bBQTSGu_NG7pMVXd-RAxwYE",
"y": "06tC0MJeBlZNYlnY8g4bCA9wJ34XN-rWfWlmmlhf-F0",
"alg": "ES256"
}
]
}
Authlete サービスに、クライアントから受信したリクエストオブジェクトの署名を検証させるためには、 そのクライアントの設定として公開鍵を登録し、さらに署名アルゴリズムを指定する必要があります。
Authlete のクライアントアプリ開発者コンソール(https://cd.authlete.com/<API キー>
例: https://cd.authlete.com/174381609020
)にアクセスし、 各タブにおいて以下を設定します。
項目 | 値 |
---|---|
JWK セットの内容 | es256_keyset_pub.txt の内容をペースト |
項目 | 値 |
---|---|
リクエストオブジェクトの署名アルゴリズム | ES256 |
上記の設定により、リクエストオブジェクトの署名検証の準備が整いました。
ここではリクエストオブジェクトを作成し、認可リクエストを組み立てます。
まず、以下のペイロードを準備します。client_id
, nbf
, exp
の値は適宜変更します。
payload.txt
{
"redirect_uri":"https://client.example.org/cb/example.com",
"response_type":"code id_token",
"client_id":"<クライアント ID> 例: 591205987816490",
"scope":"openid payment",
"nbf": <現在時刻の Unix time> 例: 1613373232,
"exp": <nbf に 3600 を加えた値> 例: 1613376832,
"aud":"https://as.example.com",
"nonce":"n-0S6_WzA2Mj"
}
nbf
と exp
の値の生成例です。
nbf
クレーム:
date +%s
などを実行して現在時刻の Unix time を取得し、
それを nbf
クレームの値としてペイロードに追加します。
たとえば date +%s
の結果が 1613373232
である場合には、payload.txt
に追加する行は以下の通りです。
"nbf":1613373232,
exp
クレーム: nbf
に 3600
を加えた値を、exp
に指定します。
たとえば "nbf":1613373232
である場合には、1613373232 + 3600 = 1613376832
となり、
payload.txt
の当該行の修正は以下の通りです。
"exp":1613376832,
秘密鍵を用いて Signed JWT を作成します。 以下は mkjose を用いて作成する例です。 各項目を入力・選択し、「生成する」ボタンを押下すると、「結果」の欄に Signed JWT が出力されます。
項目 | 値 |
---|---|
ペイロード | payload.txt の内容をペースト |
署名アルゴリズム | EC256 を選択 |
署名鍵 | es256_keyset.txt の内容から、先頭 2 行("keys": , [ )と末尾 2 行(] , } )を削除してペースト(JWK セットではなく JWK にする必要があるため) |
また、step CLI を用いて作成する場合には以下の例のようになります。
cat payload.txt | \
step crypto jws sign --jwks=es256_keyset.txt --kid=1
以下は実行結果の例です。この文字列を、認可リクエストの request
パラメーターの値として用います。
eyJhbGciOiJFUzI1NiIsImtpZCI6IjEifQ.ewoicmVkaXJlY3RfdXJpIjoiaHR0cHM6Ly9jbGllbnQuZXhhbXBsZS5vcmcvY2IvZXhhbXBsZS5jb20iLAoicmVzcG9uc2VfdHlwZSI6ImNvZGUgaWRfdG9rZW4iLAoiY2xpZW50X2lkIjoiNTkxMjA1OTg3ODE2NDkwIiwKInNjb3BlIjoib3BlbmlkIHBheW1lbnQiLAoiZXhwIjoxNTU0OTczMDAwMCwKImF1ZCI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLAoibm9uY2UiOiJuLTBTNl9XekEyTWoiCn0K.q_MbfV5qN-gnB93JaQGVrEXu8WvhDuUzWx6DwC50J8AiQGjXDEpw9satUAMN18rrgnGNciiFztoEFJuJjrJoyA
認可サーバーが認可リクエストをクライアントから受信したと仮定し、
Authlete の /auth/authorization
API に対して以下のリクエストを送信します。
curl -s -X POST https://api.authlete.com/api/auth/authorization \
-u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' \
-H 'Content-Type: application/json' \
-d '{"parameters": "redirect_uri=https://client.example.org/cb/example.com&scope=openid+payment&response_type=code+id_token&client_id=591205987816490&nonce=n-0S6_WzA2Mj&request=eyJhbGciOiJFUzI1NiIsImtpZCI6IjEifQ.ewoicmVkaXJlY3RfdXJpIjoiaHR0cHM6Ly9jbGllbnQuZXhhbXBsZS5vcmcvY2IvZXhhbXBsZS5jb20iLAoicmVzcG9uc2VfdHlwZSI6ImNvZGUgaWRfdG9rZW4iLAoiY2xpZW50X2lkIjoiNTkxMjA1OTg3ODE2NDkwIiwKInNjb3BlIjoib3BlbmlkIHBheW1lbnQiLAoiZXhwIjoxNTU0OTczMDAwMCwKImF1ZCI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLAoibm9uY2UiOiJuLTBTNl9XekEyTWoiCn0K.q_MbfV5qN-gnB93JaQGVrEXu8WvhDuUzWx6DwC50J8AiQGjXDEpw9satUAMN18rrgnGNciiFztoEFJuJjrJoyA"}' |jq
すると、以下のようなレスポンス(一部折り返しています)が返却されます。
{
"type": "authorizationResponse",
"resultCode": "A004001",
"resultMessage": "[A004001] Authlete has successfully issued a ticket to the service
(API Key = 174381609020) for the authorization request from the client
(ID = 591205987816490). [response_type=code id_token, openid=true]",
[...]
"ticket": "rjasCNvemUwamKP0G1h9Fh5Uo_3fgBfQsTF1PU4-GiE"
[...]
requestMessage
の記述から、リクエストが受理されたことがわかります。
そして期待した通り、ticket
が返却されています。
認可サーバーはこの ticket
の値をログインセッションに格納し、
ユーザー認証と同意確認を行い、そして Authlete の /auth/authorization/issue
API を呼び出し、
認可レスポンスの生成を要求することになります。
本ドキュメントの手順では、認可リクエストに response_type=code id_token
と指定しています。
よって認可レスポンスは、認可コード code
と ID トークン id_token
を、
フラグメントとして含むものになります。
認可サーバーがユーザー認証と同意確認を行い、その結果決定したユーザー識別子(subject
)が testuser01
であったと仮定し、
/auth/authorization/issue
API にリクエストを送信してみましょう。
この subject
と、上記の ticket
が、API リクエストの引数となります。
curl -s -X POST https://api.authlete.com/api/auth/authorization/issue \
-u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' \
-H 'Content-Type: application/json' \
-d '{"subject":"testuser01","ticket":"rjasCNvemUwamKP0G1h9Fh5Uo_3fgBfQsTF1PU4-GiE"}' | jq
すると、以下のようなレスポンス(一部折り返しています)が返却されます。
{
"type": "authorizationIssueResponse",
"resultCode": "A151301",
"resultMessage": "[A151301] The algorithm
('HS256' for 'id_token_signed_response_alg')
to sign the ID token is not allowed.",
[...]
resultMessage
の記述から、現在設定されている(Authlete の既定値である)HS256 が、ID トークンの署名アルゴリズムとして許可されていないことがわかります。
これは FAPI の 8.6. Algorithm considerations に
- shall use PS256 or ES256 algorithms;
とある通り、クライアントと認可サーバーは JWS アルゴリズムとして ES256 もしくは PS256 のどちらかを用いなければならないからです。 本ドキュメントでは、認可サーバーが ID トークンの署名アルゴリズムとして ES256 を用いるように、Authlete を設定してみます。
ES256 の鍵セットを生成し、ID トークンの署名に用いる鍵としてサービスに登録するとともに、 クライアント設定として ID トークンの署名アルゴリズムに ES256 を指定します。 手順は Authlete ナレッジベースの以下の記事を参照してください。
本ドキュメントでは、以下のパラメーターを選択・入力します。
項目 | 値 |
---|---|
タブ | EC (楕円曲線) |
曲線 | P-256 |
鍵の用途 | Signing |
アルゴリズム | ES256 (ECDSA using P-256 and SHA-256) |
鍵の ID | 任意の値(例: 1 ) |
生成された鍵セット(“Keypair set”)を、まずサービスに登録します。
Authlete のサービス管理者コンソール https://so.authlete.com/
にログインし、
設定の「JWK Set (JWK セット)」にある「JWK Set Content (JWK セットの内容)」の項目に追加します。
また同じページの「ID Token Signature Key ID(ID トークン署名キー ID)」の項目に、この Keypair set の kid の値(上記の例では「1」)を入力します。
次に、Authlete のクライアントアプリ開発者コンソール(https://cd.authlete.com/<API キー>
例: https://cd.authlete.com/174381609020
)にアクセスし、
ログイン ID として先ほど作成したサービスの「API キー」を、
パスワードとして同じく「API シークレット」を用いてログインします。
ログイン後、「ID トークン」タブにある「ID トークンの署名アルゴリズム」の項目にて、「ES256」を選択します。 この設定により Authlete は、このクライアントに対して ID トークンを発行する際の署名アルゴリズムとして ES256 を用いるようになります。
変更後、ticket
生成から再度動作確認を行います。
まず /auth/authorization
API を実行します。
curl -s -X POST https://api.authlete.com/api/auth/authorization \
-u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' \
-H 'Content-Type: application/json' \
-d '{"parameters": "redirect_uri=https://client.example.org/cb/example.com&scope=openid+payment&response_type=code+id_token&client_id=591205987816490&nonce=n-0S6_WzA2Mj&request=eyJhbGciOiJFUzI1NiIsImtpZCI6IjEifQ.ewoicmVkaXJlY3RfdXJpIjoiaHR0cHM6Ly9jbGllbnQuZXhhbXBsZS5vcmcvY2IvZXhhbXBsZS5jb20iLAoicmVzcG9uc2VfdHlwZSI6ImNvZGUgaWRfdG9rZW4iLAoiY2xpZW50X2lkIjoiNTkxMjA1OTg3ODE2NDkwIiwKInNjb3BlIjoib3BlbmlkIHBheW1lbnQiLAoiZXhwIjoxNTU0OTczMDAwMCwKImF1ZCI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLAoiY2xhaW1zIjp7CiAgImlkX3Rva2VuIjp7CiAgICAiYWNyIjp7CiAgICAgICJlc3NlbnRpYWwiOnRydWUsCiAgICAgICJ2YWx1ZXMiOlsidXJuOmV4YW1wbGU6cHNkMjpzY2EiXQogICAgfQogIH0KfSwKIm5vbmNlIjoibi0wUzZfV3pBMk1qIgp9Cg.b5rDSqaI3dh8n4A8hK4B5zSpnZNO_8--W-kTU03CNbCq1I_Vuf3w33ZVUhD0A-rla8cTPlZ25keQBncGWafzOA"}' \
| jq | grep ticket
この処理結果(一部折り返しています)として ticket
が返却されます。
{
[...]
"resultMessage": "[A004001] Authlete has successfully issued a ticket to the service
(API Key = 174381609020) for the authorization request from the client
(ID = 591205987816490). [response_type=code id_token, openid=true]",
"ticket": "3TzdZO2t8qXaQXIEUA5LLN106uVk5fpwL8_UDGlcwUQ"
[...]
返却された ticket
と subject
の値を用いて、/auth/authorization/issue
API にリクエストを行います。
curl -s -X POST https://api.authlete.com/api/auth/authorization/issue -u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' -H 'Content-Type: application/json' -d '{"subject":"testuser01","ticket":"3TzdZO2t8qXaQXIEUA5LLN106uVk5fpwL8_UDGlcwUQ"}' | jq
すると、以下のようなレスポンス(一部折り返しています)が返却されます。
{
"type": "authorizationIssueResponse",
"resultCode": "A040001",
"resultMessage": "[A040001] The authorization request was processed successfully.",
"accessTokenDuration": 0,
"accessTokenExpiresAt": 0,
"action": "LOCATION",
"authorizationCode": "TSRAvPIp6V3RgPOs2O7FpPG1_7t6Xpc_kcIramz8gBQ",
"idToken": "eyJraWQiOiIxIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjU5MTIwN
Tk4NzgxNjQ5MCJdLCJjX2hhc2giOiJZQjloU01CWkJLdnFobnFaWWRWTXJnIiwiaXNzIjoiaHR0cHM6L
y9hcy5leGFtcGxlLmNvbSIsImV4cCI6MTU3MjQxMDUyNiwiaWF0IjoxNTcyMzI0MTI2LCJub25jZSI6I
m4tMFM2X1d6QTJNaiJ9.ZY5XK4TqAfcnLsMhkigNRpyM6CvwD7SdX-f9TQ18pwMUdh7eoGc6ijlfEnc4
I3l0jYhlm22yuEeffV6XZhdL0A",
"responseContent": "https://client.example.org/cb/example.com#
code=TSRAvPIp6V3RgPOs2O7FpPG1_7t6Xpc_kcIramz8gBQ&
id_token=eyJraWQiOiIxIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjU5MTIwN
Tk4NzgxNjQ5MCJdLCJjX2hhc2giOiJZQjloU01CWkJLdnFobnFaWWRWTXJnIiwiaXNzIjoiaHR0cHM6L
y9hcy5leGFtcGxlLmNvbSIsImV4cCI6MTU3MjQxMDUyNiwiaWF0IjoxNTcyMzI0MTI2LCJub25jZSI6I
m4tMFM2X1d6QTJNaiJ9.ZY5XK4TqAfcnLsMhkigNRpyM6CvwD7SdX-f9TQ18pwMUdh7eoGc6ijlfEnc4
I3l0jYhlm22yuEeffV6XZhdL0A"
}
resultMessage
の記述から、認可リクエストの処理に成功したことがわかります。また idToken
, authorizationCode
にそれぞれ値が返却されています。
そして responseContent
として、認可サーバーがクライアントに返却する HTTP レスポンスが生成されており、レスポンスのフラグメント部に ID トークンと認可コードが含まれていることがわかります。
この後クライアントは ID トークンを検証し、さらにその中に含まれる c_hash
クレームを用いて認可コードを検証したのちに、
認可サーバーにトークンリクエストを送信することになります。そして認可サーバーはそのトークンリクエストを Authlete の /auth/token
API に送信し、
アクセストークンを含むトークンレスポンスの生成を要求します。
/auth/token
API に対するリクエストは以下の通りです。
curl -s -X POST https://api.authlete.com/api/auth/token \
-u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' \
-H 'Content-Type: application/json' \
-d '{"clientId":"591205987816490","clientSecret":"e7iqzq7WE8Kg00yepYnpMTjvDnAnBlq5nfA9DDQLkiYkPQBV6Lr8sLhn7DhUJd17i0O6TwQ2hKFeDAYuU160Vg","parameters": "grant_type=authorization_code&redirect_uri=https://client.example.org/cb/example.com&code=TSRAvPIp6V3RgPOs2O7FpPG1_7t6Xpc_kcIramz8gBQ"}'|jq
すると、以下のようなレスポンス(一部折り返しています)が返却されます。
{
"type": "tokenResponse",
"resultCode": "A157301",
"resultMessage": "[A157301] The client type of the client is 'confidential'
but the client authentication method is 'none'.",
"accessTokenDuration": 0,
"accessTokenExpiresAt": 0,
"action": "INVALID_CLIENT",
"clientId": 591205987816490,
"clientIdAliasUsed": false,
"grantType": "AUTHORIZATION_CODE",
"refreshTokenDuration": 0,
"refreshTokenExpiresAt": 0,
"responseContent": "{\"error_description\":\"[A157301] The client type
of the client is 'confidential' but the client authentication method is 'none'.\",
\"error\":\"invalid_client\",\"error_uri\":\"https://docs.authlete.com/#A157301\"}"
}
resultMessage
の記述から、コンフィデンシャルクライアントのクライアント認証として、
Authlete の既定値である none
は許可されていないことがわかります。
これは FAPI の 5.2 Read and write API security provisions / 5.2.2. Authorization server に
shall authenticate the confidential client using one of the following methods (this overrides FAPI Security Profile 1.0 - Part 1: Baseline clause 5.2.2-4):
tls_client_auth
orself_signed_tls_client_auth
as specified in section 2 of MTLS, orprivate_key_jwt
as specified in section 9 of OIDC;
とある通り、FAPI では
RFC 8705 が定義する Mutual TLS for OAuth Client Authentication、もしくは OpenID Connect Core 1.0 が定義する private_key_jwt のどちらかを用いなくてはならないからです。つまり none
や、コンフィデンシャルクライアントの場合に広く使われている client_secret_basic
は禁止されている(認可サーバーはそのようなクライアント認証を行ってはならない)のです。
本ドキュメントでは後者、かつ PKI Mutual-TLS Method (tls_client_auth
) を用いるように Authlete を設定してみます。
private_key_jwt
を用いる場合にはナレッジベースの記事をご参照ください。なお、同クライアント認証手段を用いた場合にも、「Holder of Key」を実現するための TLS 双方向認証の設定は同時に必要となります。
クライアント認証に「TLS クライアント認証」を用いるように、サービスおよびクライアントの設定を変更します。
Authlete のサービス管理者コンソール https://so.authlete.com/
にログインし、
「認可」タブの「トークンエンドポイント」セクションにおいて以下を設定します。
項目 | 値 |
---|---|
サポートするクライアント認証方式 | TLS_CLIENT_AUTH |
Authlete のクライアントアプリ開発者コンソール(https://cd.authlete.com/<API キー>
例: https://cd.authlete.com/174381609020
)にアクセスし、
「認可」タブの「トークンエンドポイント」セクションにおいて以下を設定します。
項目 | 値 |
---|---|
サポートするクライアント認証方式 | TLS_CLIENT_AUTH |
項目 | 値 |
---|---|
Subject Distinguished Name | CN=client.example.org, O=Client, L=Chiyoda-ku, ST=Tokyo, C=JP |
以上の設定により、Authlete サービスは TLS 双方向認証によるクライアント認証に対応し、かつ上記のクライアントからのトークンリクエストについて、その認証方式を適用することになります。
また認証の際のクライアント識別名として CN=client.example.org, ...
を用います。
クライアントが自身の認証に用いる証明書を作成します。以下は openssl
を用いて作成する例です。
openssl genrsa 2048 > private_key_nopass.pem
Generating RSA private key, 2048 bit long modulus
...............+++
.......................+++
e is 65537 (0x10001)
CN=client.example.org, O=Client, L=Chiyoda-ku, ST=Tokyo, C=JP
を指定$ openssl req -new -key private_key_nopass.pem -out server.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:JP
State or Province Name (full name) []:Tokyo
Locality Name (eg, city) []:Chiyoda-ku
Organization Name (eg, company) []:Client
Organizational Unit Name (eg, section) []:
Common Name (eg, fully qualified host name) []:client.example.org
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
$ cat server.csr
-----BEGIN CERTIFICATE REQUEST-----
MIICpTCCAY0CAQAwYDELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRva3lvMRMwEQYD
VQQHDApDaGl5b2RhLWt1MQ8wDQYDVQQKDAZDbGllbnQxGzAZBgNVBAMMEmNsaWVu
[...]
r4MUVOwPNWOM6UGYQZwjvtJ2rmKr8cQrbfvbcFiY4s6lLQGOz5yLzmO8GUdmfzUd
p5BW1iL+SpjS
-----END CERTIFICATE REQUEST-----
$ openssl x509 -days 365 -req -signkey private_key_nopass.pem -in server.csr -out server.crt
Signature ok
subject=/C=JP/ST=Tokyo/L=Chiyoda-ku/O=Client/CN=client.example.org
Getting Private key
本手順にて作成した証明書は以下の通りです。
server.crt
-----BEGIN CERTIFICATE-----
MIIDPDCCAiQCCQDWNMOIuzwDfzANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJK
UDEOMAwGA1UECAwFVG9reW8xEzARBgNVBAcMCkNoaXlvZGEta3UxDzANBgNVBAoM
BkNsaWVudDEbMBkGA1UEAwwSY2xpZW50LmV4YW1wbGUub3JnMB4XDTE5MTAyODA3
MjczMFoXDTIwMTAyNzA3MjczMFowYDELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRv
a3lvMRMwEQYDVQQHDApDaGl5b2RhLWt1MQ8wDQYDVQQKDAZDbGllbnQxGzAZBgNV
BAMMEmNsaWVudC5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAK2Oyc+BV4N5pYcp47opUwsb2NaJq4X+d5Itq8whpFlZ9uCCHzF5TWSF
XrpYscOp95veGPF42eT1grfxYyvjFotE76caHhBLCkIbBh6Vf222IGMwwBbSZfO9
J3eURtEADBvsZ117HkPVdjYqvt3Pr4RxdR12zG1TcBAoTLGchyr8nBqRADFhUTCL
msYaz1ADiQ/xbJN7VUNQpKhzRWHCdYS03HpbGjYCtAbl9dJnH2EepNF0emGiSPFq
df6taToyCr7oZjM7ufmKPjiiEDbeSYTf6kbPNmmjtoPNNLeejHjP9p0IYx7l0Gkj
mx4kSMLp4vSDftrFgGfcxzaMmKBsosMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA
qzdDYbntFLPBlbwAQlpwIjvmvwzvkQt6qgZ9Y0oMAf7pxq3i9q7W1bDol0UF4pIM
z3urEJCHO8w18JRlfOnOENkcLLLntrjOUXuNkaCDLrnv8pnp0yeTQHkSpsyMtJi9
R6r6JT9V57EJ/pWQBgKlN6qMiBkIvX7U2hEMmhZ00h/E5xMmiKbySBiJV9fBzDRf
mAy1p9YEgLsEMLnGjKHTok+hd0BLvcmXVejdUsKCg84F0zqtXEDXLCiKcpXCeeWv
lmmXxC5PH/GEMkSPiGSR7+b1i0sSotsq+M3hbdwabpJ6nQLLbKkFSGcsQ87yL+gr
So6zun26vAUJTu1o9CIjxw==
-----END CERTIFICATE-----
curl コマンドを用いてリクエストを行う際には、上記の内容を 1 行で表現したものを用います。
-----BEGIN CERTIFICATE-----\nMIIDPDCCAiQCCQDWNMOIuzwDfzANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJK\nUDEOMAwGA1UECAwFVG9reW8xEzARBgNVBAcMCkNoaXlvZGEta3UxDzANBgNVBAoM\nBkNsaWVudDEbMBkGA1UEAwwSY2xpZW50LmV4YW1wbGUub3JnMB4XDTE5MTAyODA3\nMjczMFoXDTIwMTAyNzA3MjczMFowYDELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRv\na3lvMRMwEQYDVQQHDApDaGl5b2RhLWt1MQ8wDQYDVQQKDAZDbGllbnQxGzAZBgNV\nBAMMEmNsaWVudC5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBAK2Oyc+BV4N5pYcp47opUwsb2NaJq4X+d5Itq8whpFlZ9uCCHzF5TWSF\nXrpYscOp95veGPF42eT1grfxYyvjFotE76caHhBLCkIbBh6Vf222IGMwwBbSZfO9\nJ3eURtEADBvsZ117HkPVdjYqvt3Pr4RxdR12zG1TcBAoTLGchyr8nBqRADFhUTCL\nmsYaz1ADiQ/xbJN7VUNQpKhzRWHCdYS03HpbGjYCtAbl9dJnH2EepNF0emGiSPFq\ndf6taToyCr7oZjM7ufmKPjiiEDbeSYTf6kbPNmmjtoPNNLeejHjP9p0IYx7l0Gkj\nmx4kSMLp4vSDftrFgGfcxzaMmKBsosMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA\nqzdDYbntFLPBlbwAQlpwIjvmvwzvkQt6qgZ9Y0oMAf7pxq3i9q7W1bDol0UF4pIM\nz3urEJCHO8w18JRlfOnOENkcLLLntrjOUXuNkaCDLrnv8pnp0yeTQHkSpsyMtJi9\nR6r6JT9V57EJ/pWQBgKlN6qMiBkIvX7U2hEMmhZ00h/E5xMmiKbySBiJV9fBzDRf\nmAy1p9YEgLsEMLnGjKHTok+hd0BLvcmXVejdUsKCg84F0zqtXEDXLCiKcpXCeeWv\nlmmXxC5PH/GEMkSPiGSR7+b1i0sSotsq+M3hbdwabpJ6nQLLbKkFSGcsQ87yL+gr\nSo6zun26vAUJTu1o9CIjxw==\n-----END CERTIFICATE-----\n
サービス設定とクライアント設定をそれぞれ変更したのちに、以下の手順を実行します。
/auth/authorization
API を実行し、レスポンスから ticket
の値を取得/auth/authorization/issue
API を実行し、レスポンスから authorizationCode
の値を取得/auth/token
API を実行
* clientCertificate
パラメーターを追加し、値としてクライアント証明書を指定する
* clientSecret
パラメーターを削除する(TLS 双方向認証を用いるため不要となります)以下は /auth/token
API に送信するリクエストの例です。
curl -s -X POST https://api.authlete.com/api/auth/token \
-u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' \
-H 'Content-Type: application/json' \
-d '{"clientId":"591205987816490","parameters": "grant_type=authorization_code&redirect_uri=https://client.example.org/cb/example.com&code=HVIza0dGG9nDKGStAzMObYH9GkXME0aRSaLEcToHEI8","clientCertificate":"-----BEGIN CERTIFICATE-----\nMIIDPDCCAiQCCQDWNMOIuzwDfzANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJK\nUDEOMAwGA1UECAwFVG9reW8xEzARBgNVBAcMCkNoaXlvZGEta3UxDzANBgNVBAoM\nBkNsaWVudDEbMBkGA1UEAwwSY2xpZW50LmV4YW1wbGUub3JnMB4XDTE5MTAyODA3\nMjczMFoXDTIwMTAyNzA3MjczMFowYDELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRv\na3lvMRMwEQYDVQQHDApDaGl5b2RhLWt1MQ8wDQYDVQQKDAZDbGllbnQxGzAZBgNV\nBAMMEmNsaWVudC5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBAK2Oyc+BV4N5pYcp47opUwsb2NaJq4X+d5Itq8whpFlZ9uCCHzF5TWSF\nXrpYscOp95veGPF42eT1grfxYyvjFotE76caHhBLCkIbBh6Vf222IGMwwBbSZfO9\nJ3eURtEADBvsZ117HkPVdjYqvt3Pr4RxdR12zG1TcBAoTLGchyr8nBqRADFhUTCL\nmsYaz1ADiQ/xbJN7VUNQpKhzRWHCdYS03HpbGjYCtAbl9dJnH2EepNF0emGiSPFq\ndf6taToyCr7oZjM7ufmKPjiiEDbeSYTf6kbPNmmjtoPNNLeejHjP9p0IYx7l0Gkj\nmx4kSMLp4vSDftrFgGfcxzaMmKBsosMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA\nqzdDYbntFLPBlbwAQlpwIjvmvwzvkQt6qgZ9Y0oMAf7pxq3i9q7W1bDol0UF4pIM\nz3urEJCHO8w18JRlfOnOENkcLLLntrjOUXuNkaCDLrnv8pnp0yeTQHkSpsyMtJi9\nR6r6JT9V57EJ/pWQBgKlN6qMiBkIvX7U2hEMmhZ00h/E5xMmiKbySBiJV9fBzDRf\nmAy1p9YEgLsEMLnGjKHTok+hd0BLvcmXVejdUsKCg84F0zqtXEDXLCiKcpXCeeWv\nlmmXxC5PH/GEMkSPiGSR7+b1i0sSotsq+M3hbdwabpJ6nQLLbKkFSGcsQ87yL+gr\nSo6zun26vAUJTu1o9CIjxw==\n-----END CERTIFICATE-----\n"}' |jq
すると、以下のようなレスポンス(一部折り返しています)が返却されます。
{
"type": "tokenResponse",
"resultCode": "A152305",
"resultMessage": "[A152305] The service and the client are not configured
so that the required Holder of Key methods are performed.",
"accessToken": "RCqjF4tlffJ7-n92sAEFQNIwrRm0syOUrBu0cNLAIJU",
"accessTokenDuration": 0,
"accessTokenExpiresAt": 0,
"action": "BAD_REQUEST",
"clientId": 591205987816490,
"clientIdAliasUsed": false,
"grantType": "AUTHORIZATION_CODE",
"idToken": "eyJraWQiOiIxIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjU5MTIwN
Tk4NzgxNjQ5MCJdLCJpc3MiOiJodHRwczovL2FzLmV4YW1wbGUuY29tIiwiZXhwIjoxNTcyNDEyMTcwL
CJpYXQiOjE1NzIzMjU3NzAsIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.x4XmPTh698AbNEjCaNcD5k54q
S249BSPkc9EkwZuUI17AL8z593GYTg3GVQQdhF9k0HYLRA17c3m39OxYDrx3g",
"refreshToken": "jy5lN7TXZrAlIfgFbOaMMkzDtoJUu4prBtNa3HcoRRE",
"refreshTokenDuration": 0,
"refreshTokenExpiresAt": 0,
"responseContent": "{\"error_description\":\"[A152305] The service and the client are
not configured so that the required Holder of Key methods are performed.\",
\"error\":\"invalid_request\",\"error_uri\":\"https://docs.authlete.com/#A152305\"}"
}
resultMessage
の記述から、アクセストークンは発行されたものの、未だ設定が不足しているために、
FAPI 仕様上必須である 「Holder of Key」が行われなかったことがわかります。
すなわち、ここまでの手順だけでは、
TLS クライアント証明書をひもづけたアクセストークン発行の処理が行われていないということです。
Authlete のサービス管理者コンソール https://so.authlete.com/
にログインし、
「トークン」タブの「アクセストークン」セクションにおいて以下を設定します。
項目 | 値 |
---|---|
TLS クライアント証明書を紐付けたアクセストークンのサポート | サポートする |
Authlete のクライアントアプリ開発者コンソール(https://cd.authlete.com/<API キー>
例: https://cd.authlete.com/174381609020
)にアクセスし、
「基本情報」タブにおいて以下を設定します。
項目 | 値 |
---|---|
TLS クライアント証明書を紐付けたアクセストークンの使用 | 使用する |
以上により、FAPI 準拠の認可サーバーの設定が完了しました。
変更後、先と同様の手順により /auth/authorization
API、/auth/authorization/issue
API、/auth/token
API を実行します。
さらに /auth/introspection
API を実行して、最終的に API リクエストに用いられるアクセストークンが、クライアントの
TLS クライアント証明書に紐づけられていることを確認します。
/auth/authorization
API へのリクエストcurl -s -X POST https://api.authlete.com/api/auth/authorization -u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' -H 'Content-Type: application/json' -d '{"parameters": "redirect_uri=https://client.example.org/cb/example.com&scope=openid+payment&response_type=code+id_token&client_id=591205987816490&nonce=n-0S6_WzA2Mj&request=eyJhbGciOiJFUzI1NiIsImtpZCI6IjEifQ.ewoicmVkaXJlY3RfdXJpIjoiaHR0cHM6Ly9jbGllbnQuZXhhbXBsZS5vcmcvY2IvZXhhbXBsZS5jb20iLAoicmVzcG9uc2VfdHlwZSI6ImNvZGUgaWRfdG9rZW4iLAoiY2xpZW50X2lkIjoiNTkxMjA1OTg3ODE2NDkwIiwKInNjb3BlIjoib3BlbmlkIHBheW1lbnQiLAoiZXhwIjoxNTU0OTczMDAwMCwKImF1ZCI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLAoiY2xhaW1zIjp7CiAgImlkX3Rva2VuIjp7CiAgICAiYWNyIjp7CiAgICAgICJlc3NlbnRpYWwiOnRydWUsCiAgICAgICJ2YWx1ZXMiOlsidXJuOm1hY2U6aW5jb21tb246aWFwOnNpbHZlciJdCiAgICB9CiAgfQp9LAoibm9uY2UiOiJuLTBTNl9XekEyTWoiCn0K.50gewunAqCITD6p2kI52GDXdUgQP-EzLDjjjoDT9C4zY8YCKgLzN7sR2ZvkAQ_pimLpwFh2QYjjyPskvvtnC9g"}' |jq|grep ticket
{
[...]
"resultMessage": "[A004001] Authlete has successfully issued a ticket
to the service (API Key = 174381609020) for the authorization request
from the client (ID = 591205987816490). [response_type=code id_token, openid=true]",
[...]
"ticket": "b0JGD-ZkT8ElBGw2ck-T-t87Z033jXvhqC2omPT1bQ4"
[...]
/auth/authorization/issue
API へのリクエストcurl -s -X POST https://api.authlete.com/api/auth/authorization/issue -u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' -H 'Content-Type: application/json' -d '{"subject":"testuser01","ticket":"b0JGD-ZkT8ElBGw2ck-T-t87Z033jXvhqC2omPT1bQ4"}' | jq
{
"type": "authorizationIssueResponse",
"resultCode": "A040001",
"resultMessage": "[A040001] The authorization request was processed successfully.",
"accessTokenDuration": 0,
"accessTokenExpiresAt": 0,
"action": "LOCATION",
"authorizationCode": "DxiKC0cOc_46nzVjgr41RWBQtMDrAvc0BUbMJ_v7I70",
"idToken": "eyJraWQiOiIxIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjU5MTIwN
Tk4NzgxNjQ5MCJdLCJjX2hhc2giOiJqR2kyOElvYm5HcjNNQ3Y0UUVQRTNnIiwiaXNzIjoiaHR0cHM6L
y9hcy5leGFtcGxlLmNvbSIsImV4cCI6MTU3MjQxMjY4MiwiaWF0IjoxNTcyMzI2MjgyLCJub25jZSI6I
m4tMFM2X1d6QTJNaiJ9.1PFmc0gAsBWtLBriq3z9a4Tsi_ioEYlOqOYbicGEXWIS1WGX5ffGOyZNSzVB
MamZbltZmSys0jlYmmYYLqgGsg",
"responseContent": "https://client.example.org/cb/example.com#
code=DxiKC0cOc_46nzVjgr41RWBQtMDrAvc0BUbMJ_v7I70&
id_token=eyJraWQiOiIxIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjU5MTIwN
Tk4NzgxNjQ5MCJdLCJjX2hhc2giOiJqR2kyOElvYm5HcjNNQ3Y0UUVQRTNnIiwiaXNzIjoiaHR0cHM6L
y9hcy5leGFtcGxlLmNvbSIsImV4cCI6MTU3MjQxMjY4MiwiaWF0IjoxNTcyMzI2MjgyLCJub25jZSI6I
m4tMFM2X1d6QTJNaiJ9.1PFmc0gAsBWtLBriq3z9a4Tsi_ioEYlOqOYbicGEXWIS1WGX5ffGOyZNSzVB
MamZbltZmSys0jlYmmYYLqgGsg"
}
/auth/token
API へのリクエストcurl -s -X POST https://api.authlete.com/api/auth/token \
-u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' \
-H 'Content-Type: application/json' \
-d '{"clientId":"591205987816490","parameters": "grant_type=authorization_code&redirect_uri=https://client.example.org/cb/example.com&code=DxiKC0cOc_46nzVjgr41RWBQtMDrAvc0BUbMJ_v7I70","clientCertificate":"-----BEGIN CERTIFICATE-----\nMIIDPDCCAiQCCQDWNMOIuzwDfzANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJK\nUDEOMAwGA1UECAwFVG9reW8xEzARBgNVBAcMCkNoaXlvZGEta3UxDzANBgNVBAoM\nBkNsaWVudDEbMBkGA1UEAwwSY2xpZW50LmV4YW1wbGUub3JnMB4XDTE5MTAyODA3\nMjczMFoXDTIwMTAyNzA3MjczMFowYDELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRv\na3lvMRMwEQYDVQQHDApDaGl5b2RhLWt1MQ8wDQYDVQQKDAZDbGllbnQxGzAZBgNV\nBAMMEmNsaWVudC5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBAK2Oyc+BV4N5pYcp47opUwsb2NaJq4X+d5Itq8whpFlZ9uCCHzF5TWSF\nXrpYscOp95veGPF42eT1grfxYyvjFotE76caHhBLCkIbBh6Vf222IGMwwBbSZfO9\nJ3eURtEADBvsZ117HkPVdjYqvt3Pr4RxdR12zG1TcBAoTLGchyr8nBqRADFhUTCL\nmsYaz1ADiQ/xbJN7VUNQpKhzRWHCdYS03HpbGjYCtAbl9dJnH2EepNF0emGiSPFq\ndf6taToyCr7oZjM7ufmKPjiiEDbeSYTf6kbPNmmjtoPNNLeejHjP9p0IYx7l0Gkj\nmx4kSMLp4vSDftrFgGfcxzaMmKBsosMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA\nqzdDYbntFLPBlbwAQlpwIjvmvwzvkQt6qgZ9Y0oMAf7pxq3i9q7W1bDol0UF4pIM\nz3urEJCHO8w18JRlfOnOENkcLLLntrjOUXuNkaCDLrnv8pnp0yeTQHkSpsyMtJi9\nR6r6JT9V57EJ/pWQBgKlN6qMiBkIvX7U2hEMmhZ00h/E5xMmiKbySBiJV9fBzDRf\nmAy1p9YEgLsEMLnGjKHTok+hd0BLvcmXVejdUsKCg84F0zqtXEDXLCiKcpXCeeWv\nlmmXxC5PH/GEMkSPiGSR7+b1i0sSotsq+M3hbdwabpJ6nQLLbKkFSGcsQ87yL+gr\nSo6zun26vAUJTu1o9CIjxw==\n-----END CERTIFICATE-----\n"}' |jq
{
"type": "tokenResponse",
"resultCode": "A050001",
"resultMessage": "[A050001] The token request (grant_type=authorization_code)
was processed successfully.",
"accessToken": "SUtEVc3Tj3D3xOdysQtssQxe9egAhI4fimexNVMjRyU",
"accessTokenDuration": 86400,
"accessTokenExpiresAt": 1572412769390,
"action": "OK",
"clientId": 591205987816490,
"clientIdAliasUsed": false,
"grantType": "AUTHORIZATION_CODE",
"idToken": "eyJraWQiOiIxIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjU5MTIwN
Tk4NzgxNjQ5MCJdLCJpc3MiOiJodHRwczovL2FzLmV4YW1wbGUuY29tIiwiZXhwIjoxNTcyNDEyNzY5L
CJpYXQiOjE1NzIzMjYzNjksIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.9EQojck-Cf2hnKAZWR164kr21
o5lPKehvIHyViZgRg4CY_ZGmnyFooG4FCwlZxu-QOTtaDCffCsuCdz4GqknTA",
"refreshToken": "tXZjYfoK35I-djg9V3n6s58zsrVqRIzTNMXKIS_wkj8",
"refreshTokenDuration": 864000,
"refreshTokenExpiresAt": 1573190369390,
"responseContent": "{\"access_token\":\"SUtEVc3Tj3D3xOdysQtssQxe9egAhI4fimexNVMjRyU\",
\"refresh_token\":\"tXZjYfoK35I-djg9V3n6s58zsrVqRIzTNMXKIS_wkj8\",\"scope\":\"openid payment\",
\"id_token\":\"eyJraWQiOiIxIiwiYWxnIjoiRVMyNTYifQ.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjU5MTIwN
Tk4NzgxNjQ5MCJdLCJpc3MiOiJodHRwczovL2FzLmV4YW1wbGUuY29tIiwiZXhwIjoxNTcyNDEyNzY5L
CJpYXQiOjE1NzIzMjYzNjksIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.9EQojck-Cf2hnKAZWR164kr21
o5lPKehvIHyViZgRg4CY_ZGmnyFooG4FCwlZxu-QOTtaDCffCsuCdz4GqknTA\",
\"token_type\":\"Bearer\",\"expires_in\":86400}",
"scopes": [
"openid",
"payment"
],
"subject": "testuser01"
}
上記手順の結果、アクセストークンとして SUtEVc3Tj3D3xOdysQtssQxe9egAhI4fimexNVMjRyU
が生成されています。
この値をリソースサーバーがクライアントから受信したと仮定し、/auth/introspection
API を用いて、
このアクセストークンの有効性と、関連する情報の取得を試みます。
この際に、リソースサーバーがクライアントから同時に受け取るであろう、クライアント証明書も併せて API に送信します。
/auth/introspection
API へのリクエストcurl -s -X POST https://api.authlete.com/api/auth/introspection \
-u '174381609020:LszYEVDLM5Bu4lRjO9Vaj0tMSMVerWiPf_zcdy-vu4k' \
-H 'Content-Type: application/json' \
-d '{"token":"SUtEVc3Tj3D3xOdysQtssQxe9egAhI4fimexNVMjRyU","clientCertificate":"-----BEGIN CERTIFICATE-----\nMIIDPDCCAiQCCQDWNMOIuzwDfzANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJK\nUDEOMAwGA1UECAwFVG9reW8xEzARBgNVBAcMCkNoaXlvZGEta3UxDzANBgNVBAoM\nBkNsaWVudDEbMBkGA1UEAwwSY2xpZW50LmV4YW1wbGUub3JnMB4XDTE5MTAyODA3\nMjczMFoXDTIwMTAyNzA3MjczMFowYDELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRv\na3lvMRMwEQYDVQQHDApDaGl5b2RhLWt1MQ8wDQYDVQQKDAZDbGllbnQxGzAZBgNV\nBAMMEmNsaWVudC5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC\nAQoCggEBAK2Oyc+BV4N5pYcp47opUwsb2NaJq4X+d5Itq8whpFlZ9uCCHzF5TWSF\nXrpYscOp95veGPF42eT1grfxYyvjFotE76caHhBLCkIbBh6Vf222IGMwwBbSZfO9\nJ3eURtEADBvsZ117HkPVdjYqvt3Pr4RxdR12zG1TcBAoTLGchyr8nBqRADFhUTCL\nmsYaz1ADiQ/xbJN7VUNQpKhzRWHCdYS03HpbGjYCtAbl9dJnH2EepNF0emGiSPFq\ndf6taToyCr7oZjM7ufmKPjiiEDbeSYTf6kbPNmmjtoPNNLeejHjP9p0IYx7l0Gkj\nmx4kSMLp4vSDftrFgGfcxzaMmKBsosMCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA\nqzdDYbntFLPBlbwAQlpwIjvmvwzvkQt6qgZ9Y0oMAf7pxq3i9q7W1bDol0UF4pIM\nz3urEJCHO8w18JRlfOnOENkcLLLntrjOUXuNkaCDLrnv8pnp0yeTQHkSpsyMtJi9\nR6r6JT9V57EJ/pWQBgKlN6qMiBkIvX7U2hEMmhZ00h/E5xMmiKbySBiJV9fBzDRf\nmAy1p9YEgLsEMLnGjKHTok+hd0BLvcmXVejdUsKCg84F0zqtXEDXLCiKcpXCeeWv\nlmmXxC5PH/GEMkSPiGSR7+b1i0sSotsq+M3hbdwabpJ6nQLLbKkFSGcsQ87yL+gr\nSo6zun26vAUJTu1o9CIjxw==\n-----END CERTIFICATE-----\n"}'|jq
{
"type": "introspectionResponse",
"resultCode": "A056001",
"resultMessage": "[A056001] The access token is valid.",
"action": "OK",
"certificateThumbprint": "cBNP0zNH0fkcIQdVHdB8GDQAbaZyIjKXB0EVRTByJMU",
"clientId": 591205987816490,
"clientIdAliasUsed": false,
"existent": true,
"expiresAt": 1572412769000,
"refreshable": true,
"responseContent": "Bearer error=\"invalid_request\"",
"scopes": [
"openid",
"payment"
],
"subject": "testuser01",
"sufficient": true,
"usable": true
}
これによりリソースサーバーは、クライアントから受信したアクセストークンの有効性を確認し、そのトークンにひもづいている情報を取得することができました。
本チュートリアルでは、FAPI に準拠したトークン授受・使用に対応した認可サーバーを構築するための、Authlete の設定を行いました。