private_key_jwt によるクライアント認証


概要


本ドキュメントでは private_key_jwt によるクライアント認証 (OpenID Connect Core 1.0, 9. Client Authentication) とその利用方法について解説します。


private_key_jwt


認可サーバーが private_key_jwt によってクライアントを認証する場合、クライアントはトークンエンドポイントへのリクエストに assertion (JWT) と呼ばれる認証情報を含める必要があります。assertion として送信する JWT には署名・ペイロードに関していくつかの要件が定められており、認可サーバー側ではこの検証を行う必要があります。具体的に必要となる処理はそれぞれ下記の通りとなります。

クライアント側の処理


トークンエンドポイントにおいて private_key_jwt によるクライアント認証が要求される場合、クライアントはトークンリクエストに以下のパラメーターを含める必要があります。
パラメーター
説明
client_assertion_type
client_assertion のタイプ
client_assertion
クライアントの認証情報を含む JWT

client_assertion_type には "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" という文字列を指定する必要があります。

client_assertion にはクライアントの認証情報を含んだ JWT を指定する必要があります。具体的には以下の要件を満たす JWT を指定します。

<署名>
  • 署名は非対称暗号アルゴリズム  (RS256 など) における秘密鍵を用いて計算すること
  • 署名検証用の公開鍵を認可サーバーに登録しておくこと

<ペイロード>
下記のうち、必須のクレイムを含めること。
クレイム
必須
説明
iss
YES
この JWT の発行者。値はクライアント ID に一致しなければならない。
sub
YES
この JWT のサブジェクト。値はクライアント ID に一致しなければならない。
aud
YES
この JWT の受け取り手。認可サーバーはこの値が適切なものかどうか検証しなければならない。また、この値はトークンエンドポイントの URI であるべきである。
jti
YES
この JWT の ID
exp
YES
この JWT の有効期限
iat
NO
この JWT の発行日時

上記要件を満たす JWT の具体例は、下記「assertion の生成」のセクションをご覧ください。

サーバー側の処理


認可サーバー側では、リクエストを下記仕様に従って適切に処理することになります。


これらの処理は全て Authlete に委譲できるため、ここでは詳細は割愛します。

Authlete 上で必要な設定


Authlete において private_key_jwt によるクライアント認証を行うためには以下の設定が必要になります。

サービスの設定


以下のように設定してください。
設定対象項目
設定内容
サポートするクライアント認証方式
少なくとも PRIVATE_KEY_JWT を含めるようにする

クライアントの設定


以下のように設定してください。
設定対象項目
設定内容
クライアントタイプ
Confidential
アサーション署名アルゴリズム
以下のいずれかの値。

RS256, RS384, RS512,
ES256, ES384, ES512,
PS256, PS384, PS512

実行例


以下では、認可サーバーのトークンエンドポイントにおいて private_key_jwt によるクライアント認証を行うケースをシミュレートします。

assertion の生成


事前準備として、トークンリクエストに含める client_assertion パラメーターの値 (JWT) を生成します。

まず JWT 内のペイロードとして以下のような JSON ファイルを生成してください。ここでは payload.json というファイル名でこれを保存します。

{
"jti":"<この JWT の ID>",
"sub":"<クライアント ID>",
"iss":"<クライアント ID>",
"aud":"<認可サーバーのトークンエンドポイントの URL>",
"exp":<この JWT の有効期限>,
"iat":<この JWT が発行されたタイムスタンプ>
}

具体的には以下のようになります。

{
"jti":"myJWTId001",
"sub":"38174623762",
"iss":"38174623762",
"aud":"http://localhost:4000/api/auth/token/direct/24523138205",
"exp":1536165540,
"iat":1536132708
}

次に署名の生成・検証に必要となる鍵 (JWK) を生成します。
こちらから利用する署名アルゴリズムに応じて、秘密鍵・公開鍵を生成してください。
下記は ES256 を署名アルゴリズムとして利用する場合の秘密鍵・公開鍵 (JWK) の例になります。

// 公開鍵と秘密鍵のペア
{
"kty": "EC",
"d": "ukQKQexNI8PtEv7SKpqUDnbZ-WkN6HaQqcVrVV8ZWRQ",
"use": "sig",
"crv": "P-256",
"x": "9Yxd2TvwBbgmupZh3bpg3umKihM_FNAk2_uI_-Edv_Q",
"y": "BOUFuyvWoBZ9-RVSeHJLF-L4I3ORv0xbaM1CKCFJr54",
"alg": "ES256"
}

// 公開鍵
{
"kty": "EC",
"use": "sig",
"crv": "P-256",
"x": "9Yxd2TvwBbgmupZh3bpg3umKihM_FNAk2_uI_-Edv_Q",
"y": "BOUFuyvWoBZ9-RVSeHJLF-L4I3ORv0xbaM1CKCFJr54",
"alg": "ES256"
}

ここでは生成した公開鍵と秘密鍵のペアを key_pair.jwk として保存します。また、公開鍵をクライアントの「JWK セットの内容」に登録するのを忘れないようにしてください。

最後にこのペイロードを含む JWT を生成します。
以下は authlete-jose ライブラリを利用して JWT を生成する例になります。

$ bin/jose-generator \
--payload-file payload.json \
--sign \
--signing-alg ES256 \
--jwk-signing-alg-file key_pair.jwk

結果的に以下のような JWT が得られます。(見やすさを考慮し一部改行してあります。)

eyJhbGciOiJFUzI1NiJ9.
ewogICJqdGkiOiJteUpXVElkMDAxIiwKICAic3ViIjoiMzgxNzQ2MjM3NjIiLAogICJpc3MiOiIzODE3NDYyMzc2MiIsCiAgImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NDAwMC9hcGkvYXV0aC90b2tlbi9kaXJlY3QvMjQ1MjMxMzgyMDUiLAogICJleHAiOjE1MzYxNjU1NDAsCiAgImlhdCI6MTUzNjEzMjcwOAp9Cg.
YB4gdhWUGRjWEsEbKDs7-G2WFH2oYz7bAEP5AtegHXInkY9ncA2V3IoA6O_HVQuFxyCRIklrxsMk32MfNF_ABA

トークンリクエストのシミュレート


クライアントから認可サーバーに対して以下のトークンリクエストが投げられたと仮定します。(見やすさを考慮し一部改行してあります。)

POST /token.oauth2 HTTP/1.1
Host: as.example.com
Content-Type: application/x-www-form-urlencoded
 
grant_type=authorization_code&
code=Gw30fMKJBHkcOBSde5awLrMm4ahvgCNM2cFSTUOUflY&
redirect_uri=https://example.com/redirection
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&
client_assertion=eyJhbGciOiJFUzI1NiJ9.
ewogICJqdGkiOiJteUpXVElkMDAxIiwKICAic3ViIjoiMzgxNzQ2MjM3NjIiLAogICJpc3MiOiIzODE3NDYyMzc2MiIsCiAgImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NDAwMC9hcGkvYXV0aC90b2tlbi9kaXJlY3QvMjQ1MjMxMzgyMDUiLAogICJleHAiOjE1MzYxNjU1NDAsCiAgImlhdCI6MTUzNjEzMjcwOAp9Cg.
YB4gdhWUGRjWEsEbKDs7-G2WFH2oYz7bAEP5AtegHXInkY9ncA2V3IoA6O_HVQuFxyCRIklrxsMk32MfNF_ABA

これを受けた認可サーバーは、 Authlete の /api/auth/token API に対してリクエストを投げます。以下のコマンドはこれをシミュレートしています。

$ curl -v -XPOST https://api.authlete.com/api/auth/token \
            -H 'Content-Type: application/json' \
            -u '10629969330:tszcLrddM8146JPApzflvRYc7QVU3HhkwCQnoAWF3UI' \
            -d '{ 
            "parameters":"grant_type=authorization_code&
            code=Gw30fMKJBHkcOBSde5awLrMm4ahvgCNM2cFSTUOUflY&
            redirect_uri=https://example.com/redirection&
            client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&
            client_assertion=eyJhbGciOiJFUzI1NiJ9.
            ewogICJqdGkiOiJteUpXVElkMDAxIiwKICAic3ViIjoiMzgxNzQ2MjM3NjIiLAogICJpc3MiOiIzODE3NDYyMzc2MiIsCiAgImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NDAwMC9hcGkvYXV0aC90b2tlbi9kaXJlY3QvMjQ1MjMxMzgyMDUiLAogICJleHAiOjE1MzYxNjU1NDAsCiAgImlhdCI6MTUzNjEzMjcwOAp9Cg.
            YB4gdhWUGRjWEsEbKDs7-G2WFH2oYz7bAEP5AtegHXInkY9ncA2V3IoA6O_HVQuFxyCRIklrxsMk32MfNF_ABA"}'

上記リクエストが正常に処理されると以下のようなレスポンスが得られます。

{
"type":"tokenResponse",
"resultCode":"A050001",
"resultMessage":"[A050001] The token request (grant_type=authorization_code) was processed successfully.",
"accessToken":"ni6uDszfkeR5GH96k3cUjt3R7MHG9-xRbMDObaKGY2A",
...
}


How did we do with this article?