> ## Documentation Index
> Fetch the complete documentation index at: https://developers.authlete.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Adding Custom Claims to Userinfo API Responses

> How to determine and add claims to the Userinfo API payload

## Introduction

The claims returned by the Userinfo API can be customized with the `claims` parameter just like those in [How to Add Custom Claims to ID Tokens](/configuration-reference/tokens-and-claims/adding-claims-to-an-id-token).

This article explains how to add arbitrary claims to the Userinfo endpoint response and which Authlete features help determine the right claims.

## Basic Implementation of the Userinfo Endpoint

When an OpenID Provider builds a Userinfo API endpoint with Authlete, it needs to call the following two APIs:

* Userinfo Request [/api/\{serviceId}/auth/userinfo](/api-reference/userinfo-endpoint/process-userinfo-request)
* Issue Userinfo Response [/api/\{serviceId}/auth/userinfo/issue](/api-reference/userinfo-endpoint/issue-userinfo-response)

Authlete's Userinfo Request endpoint validates the presented access token and returns the user information tied to that token. The OpenID Provider inspects the Userinfo Request response to confirm the token validity and the associated subject, retrieves the subject's attributes from its data store, and submits them to the Issue Userinfo Response API.

### Calling the Userinfo Request API

In practice, the OpenID Provider forwards the user's access token to Authlete's Userinfo Request API:

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

If the access token is valid, the response looks like the following:

```sh theme={null}
{
  "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."
}
```

Here `action` is `OK`, which proves the token is valid. Because the `subject` is `john`, the OpenID Provider can collect the attributes linked to `john` and provide them to the Issue Userinfo Response API.

### Calling the Issue Userinfo Response API

Since Authlete does not store attribute values linked to users, the OpenID Provider must prepare the attribute values to be included in the response from the UserInfo endpoint. On the other hand, the OpenID Provider can use the claims parameter returned by Authlete to determine which attributes to include in the UserInfo response.

The `claims` parameter contained in the Userinfo Request API response is a merged list of [claims derived from the scopes specified at the authorization endpoint](https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims) and [claims explicitly requested via the claims parameter](https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter), just like the logic described in [Determining Claims to Add to an ID Token](/configuration-reference/tokens-and-claims/identifying-claims-expected-to-be-included-into-an-id-token).

In the previous example, the requested scope included `openid` and `email`, so the `email` scope expanded to `email` and `email_verified`, and both claims appeared in the `claims` array. For the list of scopes and their corresponding claims, refer to the Authlete Java Common Javadoc [ClaimsScope](https://authlete.github.io/authlete-java-common/com/authlete/common/types/ClaimsScope.html).

Below is an example where the OpenID Provider injects the following claims from Authlete's `claims` response into the Userinfo payload:

| Claim             | Value                                         |
| ----------------- | --------------------------------------------- |
| "email"           | "[john@example.com](mailto:john@example.com)" |
| "email\_verified" | true                                          |

The request that adds these claims (line breaks inserted for readability) looks like this:

```sh theme={null}
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}" }'
```

A successful response shows that the specified claims were embedded in `responseContent`:

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

## Customizing the List of Claims to Include

The `claims` array calculated by Authlete follows OpenID Connect Core, but it may not match real-world requirements. For example, you might need to return a different set of claims from the Userinfo endpoint than from the ID token, or you may accept only the `openid` and `email` scopes while still needing to send additional user-consented claims in the Userinfo response.

In that case, the OpenID Provider can leverage `consentedClaims` to propagate the claims that the end-user allowed the RP to access at the authorization endpoint to both the Introspection and Userinfo endpoints.

> `consentedClaims` is available in Authlete 2.3 and later.
> For details on `consentedClaims`, please refer to the Authlete JavaDoc: [AuthorizationIssueRequest.html#setConsentedClaims()](https://authlete.github.io/authlete-java-common/com/authlete/common/dto/AuthorizationIssueRequest.html#setConsentedClaims%28%29).

### Telling Authlete Which Claims the User Consented To

Assume that during authorization the user agreed to share their full name, username, and email address with the RP, and the OpenID Provider wants to return those attributes from the Userinfo endpoint.

The authorization endpoint first sends the following request to Authlete and receives a ticket:

```sh theme={null}
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"}'
```

Partial response:

```json theme={null}
{
  "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]"
}
```

After obtaining the user's consent to share their full name, username, and email address, the OpenID Provider calls the `auth/authorization/issue` endpoint. It passes `consentedClaims` with `name`, `username`, `email`, and `email_verified`.

```sh theme={null}
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 stores the `consentedClaims` specified at authorization time and later includes them in the responses from `/auth/userinfo` and `/auth/introspection`.

> Ensure that any claim you plan to list in `consentedClaims` has already been registered under the target service's `Tokens & Claims` > `Claims` > `Supported Claims` settings.
>
> <img src="https://mintcdn.com/authlete/EJDZNZMvOu_9CJHJ/configuration-reference/endpoints/supported-claims.png?fit=max&auto=format&n=EJDZNZMvOu_9CJHJ&q=85&s=16194ddff5ac32e8e22ddff3c018d0b2" alt="supported claims" width="1187" height="659" data-path="configuration-reference/endpoints/supported-claims.png" />

*>*

### Using Consented Claims in the Userinfo API Response

When the access token tied to the above authorization flow is sent to the Userinfo Request API, the response is as follows:

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

```json theme={null}
{
  "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."
}
```

Instead of the `claims` array, the OpenID Provider can use the `consentedClaims` array and return the claims the user agreed to share as the Userinfo endpoint payload.

```sh theme={null}
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}" }'
```

As a result of the above request, the Userinfo endpoint returns a response containing the user's name, username, and email address, which the user has consented to provide, as shown below.

```json theme={null}
{
  "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."
}
```
