Userinfo API のレスポンスに任意のクレームを追加する

Userinfo API のレスポンスに任意のクレームを追加する

はじめに

Userinfo API が応答するクレームは ID トークンに任意のクレームを追加する方法 と同様に、claims パラメータを利用することでカスタマイズできます。

この記事では Userinfo エンドポイントのレスポンスに任意のクレームを追加する方法と、クレームの決定に役立つ Authlete の機能について解説します。

基本的な Userinfo エンドポイントの実装

OpenID プロバイダーが Authlete を利用し Userinfo API エンドポイントを実装する場合、以下の 2 つの API を呼び出す必要があります。

Authlete の Userinfo Request エンドポイントはアクセストークンを提示することにより、アクセストークンの検証をしたうえで、トークンに紐づくユーザーの情報を応答します。 OpenID プロバイダーは Userinfo Request の応答からトークンの有効性と紐づいたユーザーを確認し、対象ユーザーの属性をデータストアから収集し、Issue Userinfo Response API に提示します。

Userinfo Request API の呼び出し例

具体的な例は以下の通りです。まず OpenID プロバイダーはユーザーが提示したアクセストークンを Authlete の Userinfo Request API に送信します。

curl --request POST \
  --url https://jp.authlete.com/api/{{serviceId}}/auth/userinfo \
  --header 'authorization: Bearer {{serviceAccessToken}}' \
  --header 'content-type: application/json' \
  --data '{"token": "{{accessToken}}"}'

アクセストークンが有効な場合の応答例は以下の通りです。

{
  "action": "OK",
  "clientId": 2064424232,
  "subject": "john",
  "scopes": [
    "openid",
    "email"
  ],
  "claims": [
    "email",
    "email_verified"
  ],
  "token": "{{accessToken}}",
  "clientIdAlias": "2064424232",
  "clientIdAliasUsed": true,
  "consentedClaims": [
    "email",
    "email_verified"
  ],
  "clientEntityIdUsed": false,
  "resultCode": "A091001",
  "resultMessage": "[A091001] The access token presented at the userinfo endpoint is valid."
}

この例では actionOK でトークンが有効であることが示され、さらに subjectjohn であると判別できるため、 OpenID プロバイダーは john に紐づく属性を収集し、 Issue Userinfo Response に提示します。

Issue Userinfo Response の呼び出し例

Authlete はユーザーに紐づく属性の値は保持しないため、Userinfo エンドポイントの応答に含める属性の値は OpenID プロバイダーが用意する必要があります。一方、OpenID プロバイダーは Userinfo に含める属性を決定するために Authlete が応答する claims パラメータを利用できます。

Userinfo Request API の 応答に含まれる claims パラメータは IDトークンに追加する「クレーム」の判別 と同様に、/auth/authorization エンドポイントに提示された parameters 内の スコープ(scope)に対応するクレーム と、claims パラメーターを用いて個別に指定されるクレームがマージされたリストです。

例えば上記例では scopeopenid email が含まれていたため、email スコープが展開され email, email_verified が含めるべきクレームとして claims 応答に含まれます。スコープとそれに対応するクレームの一覧は Authlete Java Common の Javadoc ClaimsScope をご確認ください。

ここでは OpenID プロバイダーが Authlete からの応答 claims に含まれる以下の項目を Userinfo レスポンスに追加する例を示します。

項目
“email” john@example.com
“email_verified” true

上記のクレームを追加する場合のリクエストは以下のようになります。(読みやすさのため折り返しています。)

curl --request POST \
  --url https://jp.authlete.com/api/{{serviceId}}/auth/userinfo/issue \
  --header 'authorization: Bearer {{serviceAccessToken}}' \
  --header 'content-type: application/json' \
  --data '{"token": "{{accessToken}}",
    "claims": "{
      \"email\": \"john@example.com\",
      \"email_verified\": true}"
 }'

正常な応答は以下の通りです。responseContent のクレームに指定したクレームが追加されていることが確認できます。

{
  "action": "JSON",
  "responseContent": "{\"sub\":\"john\",\"email\":\"john@example.com\",\"email_verified\":true}",
  "resultCode": "A096001",
  "resultMessage": "[A096001] User information was obtained successfully."
}

含めるべきクレームのリストをカスタマイズする

Authlete が自動で計算する claims は OpenID Connect Core の仕様に則したものですが、実際の運用環境には適さない場合があります。例えば ID トークンに含めるクレームと異なるクレームを Userinfo から返したい、scopeopenid, email のみを指定するが OpenID プロバイダーがユーザーの同意内容をもとに追加のクレームを Userinfo エンドポイントから応答したいといった要件があるでしょう。

この場合、Authlete の consentedClaims を利用しユーザーが認可エンドポイントで RP に公開することを許可したクレームを、Introspection エンドポイント や Userinfo エンドポイントに伝達することが可能です。

consentedClaims は Authlete 2.3 以降で利用できます。 consentedClaims の詳細は Authlete Java Doc AuthorizationIssueRequest.html#setConsentedClaims() を確認ください。

ユーザーが提供に同意したクレームを Authlete に伝える

例えばユーザーが認可処理を行った際、氏名とユーザー名、メールアドレスを RP に伝えることに同意し、 OpenID プロバイダーの実装ではそれらの情報を Userinfo エンドポイントから情報を返すような実装を考えます。

認可エンドポイントは以下のようなリクエストを Authlete に送信しチケットを得ます。

curl --request POST \
  --url https://jp.authlete.com/api/{{serviceId}}/auth/authorization \
  --header 'authorization: Bearer {{serviceAccessToken}}' \
  --header 'content-type: application/json' \
  --data '{"parameters": "client_id=rest-client-client&scope=openid%20email&response_type=code&redirect_uri=https://example.com&state=xyz&nonce=12345"}'

応答例 (一部省略)

{
  "action": "INTERACTION",
  "service": {
  },
  "client": {
  },
  "display": "PAGE",
  "maxAge": 0,
  "scopes": [
    {
      "name": "email",
      "defaultEntry": false,
      "description": "A permission to request an OpenID Provider to include the email claim and the email_verified claim in an ID Token. See OpenID Connect Core 1.0, 5.4. for details."
    },
    {
      "name": "openid",
      "defaultEntry": false,
      "description": "A permission to request an OpenID Provider to issue an ID Token. See OpenID Connect Core 1.0, 3.1.2.1. for details."
    }
  ],
  "ticket": "IWjy7qiCFJsHYHBKAfwJNLHfoV86lL7KYC0ojmi-Qrk",
  "resultCode": "A004001",
  "resultMessage": "[A004001] Authlete has successfully issued a ticket to the service (API Key = 666990377) for the authorization request from the client (ID = 1110197986). [response_type=code, openid=true]"
}

OpenID プロバイダーは、氏名とユーザー名、メールアドレスを対象のクライアントに提供するための同意を得たのち、auth/authorization/issue エンドポイントを呼び出します。この際に consentedClaims として name, username, email, email_verified を指定します。

curl --request POST \
  --url https://jp.authlete.com/api/{{serviceId}}/auth/authorization \
  --header 'authorization: Bearer {{serviceAccessToken}}' \
  --header 'content-type: application/json' \
  --data '{
    "ticket": "{{ticket}}",
    "subject": "john",
    "claims": "{\"claim_for_id_token\":\"value_for_id_token\"}",
    "consentedClaims": ["name", "username", "email", "email_verified"]
}'

Authlete は認可時に指定された consentedClaims をデータベースに保存し、/auth/userinfo/auth/introspection の応答に含めます。

ここで consentedClaims に指定するクレームはあらかじめ対象サービスの トークン&クレーム > クレーム > サポート可能なクレーム に追加しておく必要がある点に注意してください。

supported claims
>

ユーザーが提供に同意したクレームを Userinfo API の応答に含める

先ほどの認可リクエストに紐づくトークンを Userinfo Request API に送信すると以下のような応答が得られます。

curl --request POST \
  --url https://jp.authlete.com/api/{{serviceId}}/auth/userinfo \
  --header 'authorization: Bearer {{serviceAccessToken}}' \
  --header 'content-type: application/json' \
  --data '{"token": "{{accessToken}}"}'
{
  "action": "OK",
  "clientId": 1110197986,
  "subject": "john",
  "scopes": [
    "email",
    "openid"
  ],
  "claims": [
    "email",
    "email_verified"
  ],
  "token": "ytaniPwocUVRSDuCBn6EEIR7SYYRxIHkmvv2ht7oPLU",
  "clientIdAlias": "rest-client-client",
  "clientIdAliasUsed": true,
  "clientEntityIdUsed": false,
  "consentedClaims": [
    "name",
    "username",
    "email",
    "email_verified"
  ],
  "resultCode": "A091001",
  "resultMessage": "[A091001] The access token presented at the userinfo endpoint is valid."
}

OpenID プロバイダーは claims 応答の代わりに、consentedClaims 応答を参照し、ユーザーが提供に同意したクレームを Userinfo エンドポイントの応答として返却することが可能となります。

curl --request POST \
  --url https://jp.authlete.com/api/{{serviceId}}/auth/userinfo/issue \
  --header 'authorization: Bearer {{serviceAccessToken}}' \
  --header 'content-type: application/json' \
  --data '{"token": "{{accessToken}}",
    "claims": "{
      \"name\": \"John Doe\",
      \"username\": \"jdoe\",
      \"email\": \"john@example.com\",
      \"email_verified\": true}"
 }'

上記リクエストの結果、Userinfo エンドポイントから、以下のようにユーザーが提供に同意した氏名とユーザー名、メールアドレスを含む応答が得られます。

{
  "action": "JSON",
  "responseContent": "{\"sub\":\"john\",\"name\":\"John Doe\",\"email\":\"john@example.com\",\"email_verified\":true,\"username\":\"jdoe\"}",
  "resultCode": "A096001",
  "resultMessage": "[A096001] User information was obtained successfully."
}