> ## 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.

# OIDC Basics

> A tutorial to understand how OpenID Connect identity provider leverages Authlete APIs.

<Note>
  This page is for Authlete 3.0. For 2.x, see [this page](/v2/get-started/core-concepts/oidc-basics).
</Note>

# Introduction

This document is a tutorial to describe basic usage of [Authlete APIs](/api-reference) in order to implement OpenID Connect (OIDC) identity provider (IdP) server that supports the [authorization code flow](https://youtu.be/x2qtJZ3Wivc?feature=shared).

In completing the tutorial, you will

* Make requests simulating the requests which come from the authorization server to Authlete
* Set the issuer identifier in the Authlete Management Console, include additional claims in the authorization request to the Authlete authorize endpoint, and confirm that both the issuer and additional claims are included in the ID Token by decoding it.

<iframe width="560" height="315" src="https://www.youtube.com/embed/x2qtJZ3Wivc?si=OCXWzHwmkFt0NI9x" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen />

# Authorization Code Flow Components

<Note>
  **Note**

  In this tutorial, OIDC identity provider and relying party are described as authorization server and client respectively for convenience.
</Note>

In a typical Authlete implementation, the authorization server middleware would be responsible for passing requests to and handling responses from the Authlete API. In this tutorial, you will make these requests directly with the bash/zsh `curl` command. You may of course use an alternate HTTP client of your choice (PowerShell, Postman, etc.), but you'll need to know how to adapt the instructions for yourself in this instance.

```mermaid theme={null}
flowchart LR
    subgraph EndUser [End User]
        userAgent["User Agent (N/A)"]
        resourceOwner["Resource Owner (N/A)"]
    end

    subgraph APIClient [API Client]
        client["Client (N/A)"]
    end

    subgraph APIServer [API Server]
        authServer["Authorization Server/IdP (curl)"]
        resourceServer["Resource Server (curl)"]
        authAdmin["Authlete Administrator"]
    end

    subgraph Authlete [Authlete]
        mgmtConsole["Authlete Management Console"]
        authAPI["Authlete API"]
    end

    resourceOwner --> userAgent
    userAgent -- "Access to Client" --> client
    userAgent -- "Authorization Request (User Authentication and Consent)" --> authServer
    client -- "Token Request" --> authServer
    client -- "API Request" --> resourceServer

    %% API Server interactions with Authlete
    authAdmin -- "Service/Client Management" --> mgmtConsole
    mgmtConsole -- "API Request" --> authAPI

    authServer -- "API Request" --> authAPI
    resourceServer -- "API Request" --> authAPI
```

To understand how each piece fits together in this OAuth flow, we've provided a list of fully qualified domain names (FQDN) for each component. The FQDNs for the authorization server and the client are invented only for reference, and would of course be substituted for real ones in a real implementation.

| Component                   | FQDN                   |
| --------------------------- | ---------------------- |
| Authlete API US Cluster     | `us.authlete.com`      |
| Authlete Management Console | `console.authlete.com` |
| Authorization Server        | `as.example.com`       |
| Client                      | `client.example.org`   |
| Resource Server             | N/A                    |

<Note>
  **Note**

  API endpoints are cluster specific. If using a service in another cluster, you'd substitute in the cluster's two character ISO code for the complete domain name for that API endpoint (e.g. br, eu, jp).
</Note>

# Environment setup

<Note>
  **Note**

  Settings in this section are the same as described in Authlete API Tutorial - [OAuth 2.0 Basics](/get-started/quickstarts/oauth-2-0-basics). If you've already completed that tutorial, you can skip this section.
</Note>

Consult the [First API Call](/get-started/quickstarts/getting-started) guide for how to create an Authlete API service and register a client to the service.

Take care to note your Service ID, Service Access Token, and Client Secret values.

If you've already completed other Authlete tutorials, you can reuse your existing service. Otherwise use the following values to create your service, leaving all other fields as default:

| Field               | Value                         |
| ------------------- | ----------------------------- |
| API Cluster         | 🇺🇸 US                       |
| Service Name        | Demo AS                       |
| Service Description | Example authorization service |

You can use the following values to create your client, leaving all other fields as default:

| Field              | Value                            |
| ------------------ | -------------------------------- |
| Client Name        | Demo OIDC Client                 |
| Client Description | Example client for OIDC tutorial |
| Client Type        | CONFIDENTIAL                     |

<figure class="figure bg-transparent border-0">
  <img src="https://mintcdn.com/authlete/6e8OPufcWwl4fTPw/get-started/authlete-client-configs.png?fit=max&auto=format&n=6e8OPufcWwl4fTPw&q=85&s=432f34c5ec5bdc4500dbdd1f1f953ded" class="figure-img img-fluid rounded" alt="an Authlete client configured with client name, description and type" width="1636" height="792" data-path="get-started/authlete-client-configs.png" />
</figure>

Once your client is created, go to Client Settings > Endpoints > Global Settings. In the Redirect URIs section, click Add to enter and save the URI where the client will receive authorization responses.

The following example properties are generated or specified when you create a client. These are values required when making requests as part of the `code` flow that you will complete. Use the values you noted down in the environment setup section.

| Item                         | Value                                                                                                        |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------ |
| Service ID                   | Auto-generated e.g. `10738933707579`                                                                         |
| Service Access Token         | Auto-generated e.g. `Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ`                                            |
| Client ID                    | Auto-generated e.g. `12898884596863`                                                                         |
| Client Secret                | Auto-generated e.g. `-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg` |
| Client Type                  | `CONFIDENTIAL`                                                                                               |
| Redirect URIs                | `https://client.example.org/cb/example.com`                                                                  |
| Client Authentication Method | `CLIENT_SECRET_BASIC`                                                                                        |

Now, let's try the OIDC authorization code flow using this environment.

# Walk-through

We've provided the following sequence diagram to help you understand each of the steps involved in the code flow. You can identify where you are at in the walk-through using the numbers which correspond to specific steps in the diagram.

```mermaid theme={null}
sequenceDiagram
    autonumber
    participant RO as Resource Owner
    participant UA as User Agent
    participant C as Client
    participant AS as Authorization Server
    participant RS as Resource Server
    participant API as Authlete API

    RO ->> UA: Start
    UA ->> C: Make a request
    C -->> UA: Authorization request
    UA ->> AS: Forward the request
    AS ->> API: POST /auth/authorization
    API -->> AS: OK to proceed<br/>(including ticket)
    AS -->> UA: User authentication and consent page
    RO <<->> UA: Enter credentials
    UA ->> AS: Login and consent
    AS ->> API: POST /auth/authorization/issue<br/>(with ticket)
    API -->> AS: Authorization response content<br/>(including authorization code)
    AS -->> UA: Authorization response
    UA ->> C: Forward the response
    C ->> AS: Token request<br/>(with authorization code)
    AS ->> API: POST /auth/token
    API -->> AS: Token response content<br/>(including id token & access token)
    AS -->> C: Token response
```

## Authorization request from the client to the authorization server

We'll use the following values as example parameters for the request (as specified previously).

| Item           | Value                                       | Description                                                                                                                                      |
| -------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| client\_id     | `12898884596863`                            | Registered client ID                                                                                                                             |
| response\_type | `code`                                      | A value stating OIDC authorization code flow (when `scope` contains `openid`)                                                                    |
| redirect\_uri  | `https://client.example.org/cb/example.com` | One of registered redirect URIs                                                                                                                  |
| scope          | `openid`                                    | A value stating this request is OIDC authentication request                                                                                      |
| nonce          | `n-0S6_WzA2Mj`                              | Nonce value (See [3.1.2.1. Authentication Request - OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest)) |

When the resource owner attempts to access a protected resource through the client (steps #1, #2) the client makes an OIDC authentication request (authorization request) to the authorization server via user agent (steps #3, #4).

The authorization server receives the above data here shown as the HTTP `GET` query string from the user agent.

```shell theme={null}
redirect_uri=https://client.example.org/cb/example.com
 &response_type=code
 &client_id=12898884596863
 &scope=openid
 &nonce=n-0S6_WzA2Mj
```

The job of the authorization server is to evaluate these parameters. Here are some typical evaluation rules:

* Whether a client associated with the client ID `12898884596863` has been registered to the authorization server. It must be an OIDC relying party because of `scope=openid`.
* Whether the value of the redirect URI `https://client.example.org/cb/example.com` matches with one of URIs registered to the client
* Whether values of other parameters such as `response_type`, `scope` are applicable for the client, i.e. permitted for the client to specify in its request

After that, the authorization server would process the OIDC authorization code flow since the values of `scope` and `response_type` are `openid` and `code` respectively.

However, in the Authlete architecture the authorization server is simply a proxy for the actual authorization logic contained in the Authlete API which is surfaced at the [`/auth/authorization`](/api-reference/authorization-endpoint/process-authorization-request) endpoint. Once received, the Authlete API does the evaluation process on the authorization server's behalf.

You'll now simulate the authorization server's request to this API.

Execute the `curl` command as follows (message #5). Make sure to replace `<Service ID>`, `<Service Access Token>` and `<Client ID>` by your own values generated in the previous step.

<CodeGroup>
  ```text cURL theme={null}
  curl -s -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/authorization \
  -H 'Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
  -H 'Content-Type: application/json' \
  -d '{ "parameters": "redirect_uri=https://client.example.org/cb/example.com&response_type=code&client_id=<Client ID e.g. 12898884596863>&scope=openid&nonce=n-0S6_WzA2Mj" }'
  ```

  ```powershell PowerShell theme={null}
  $headers = @{ Authorization = "Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>" }
  $body = '{ "parameters": "redirect_uri=https://client.example.org/cb/example.com&response_type=code&client_id=<Client ID e.g. 12898884596863>&scope=openid&nonce=n-0S6_WzA2Mj" }'
  Invoke-RestMethod -Method Post `
    -Uri "https://us.authlete.com/api/<Service" `
    -Headers $headers -ContentType "application/json" -Body $body
  ```

  ```java Java theme={null}
  // authlete-java-common — initialize the client once and reuse it across the steps below.
  AuthleteConfiguration config = new AuthleteSimpleConfiguration()
          .setApiVersion("V3")
          .setBaseUrl("https://us.authlete.com")
          .setServiceApiKey("10738933707579")
          .setServiceAccessToken(System.getenv("SERVICE_ACCESS_TOKEN"));
  AuthleteApi authleteApi = AuthleteApiFactory.create(config);

  AuthorizationRequest request = new AuthorizationRequest()
          .setParameters("redirect_uri=https://client.example.org/cb/example.com"
                  + "&response_type=code"
                  + "&client_id=12898884596863"
                  + "&scope=openid"
                  + "&nonce=n-0S6_WzA2Mj");

  AuthorizationResponse response = authleteApi.authorization(request);
  System.out.println(response.getAction()); // INTERACTION
  System.out.println(response.getTicket());
  ```

  ```typescript TypeScript theme={null}
  import { Authlete } from "@authlete/typescript-sdk";

  // Initialize the client once and reuse it across the steps below.
  const authlete = new Authlete({
    serverURL: "https://us.authlete.com",
    bearer: process.env["SERVICE_ACCESS_TOKEN"] ?? "",
  });
  const SERVICE_ID = "10738933707579";

  const res = await authlete.authorization.processRequest({
    serviceId: SERVICE_ID,
    authorizationRequest: {
      parameters:
        "redirect_uri=https://client.example.org/cb/example.com&response_type=code&client_id=12898884596863&scope=openid&nonce=n-0S6_WzA2Mj",
    },
  });
  console.log(res.action); // "INTERACTION"
  console.log(res.ticket);
  ```

  ```ruby Ruby theme={null}
  require "authlete_ruby_sdk"

  # Initialize the client once and reuse it across the steps below.
  client     = Authlete::Client.new(
    bearer:     ENV.fetch("SERVICE_ACCESS_TOKEN"),
    server_url: "https://us.authlete.com"
  )
  SERVICE_ID = "10738933707579"

  req = Authlete::Models::Components::AuthorizationRequest.new(
    parameters: "redirect_uri=https://client.example.org/cb/example.com&response_type=code&client_id=12898884596863&scope=openid&nonce=n-0S6_WzA2Mj"
  )
  res = client.authorization.process_request(service_id: SERVICE_ID, authorization_request: req)

  puts res.authorization_response.action # "INTERACTION"
  puts res.authorization_response.ticket
  ```

  ```go Go theme={null}
  package main

  import (
  	"context"
  	"log"
  	"os"

  	authlete "github.com/authlete/authlete-go-sdk"
  	"github.com/authlete/authlete-go-sdk/models/components"
  )

  func main() {
  	ctx := context.Background()

  	// Initialize the client once and reuse it across the steps below.
  	s := authlete.New(
  		authlete.WithServerURL("https://us.authlete.com"),
  		authlete.WithSecurity(os.Getenv("SERVICE_ACCESS_TOKEN")),
  	)
  	const serviceID = "10738933707579"

  	res, err := s.Authorization.ProcessRequest(ctx, serviceID, components.AuthorizationRequest{
  		Parameters: "redirect_uri=https://client.example.org/cb/example.com&response_type=code&client_id=12898884596863&scope=openid&nonce=n-0S6_WzA2Mj",
  	})
  	if err != nil {
  		log.Fatal(err)
  	}
  	log.Printf("action=%v", *res.AuthorizationResponse.Action) // INTERACTION
  	log.Printf("ticket=%s", *res.AuthorizationResponse.Ticket)
  }
  ```
</CodeGroup>

If successful, Authlete will reply with the following response (shortened for brevity) (message #6).

```json theme={null}
{
   "resultMessage" : "[A004001] Authlete has successfully issued a ticket to the service (API Key = 10738933707579) for the authorization request from the client (ID = 12898884596863). [response_type=code, openid=true]",
   "resultCode" : "A004001",
   "client" : { [...] },
   "ticket" : "bi2Kxe2WW5mK_GZ_fDFOpK1bnY6xTy40Ap_8nxf-7AU",
   "action" : "INTERACTION",
   [...]
   "service" : {
      [...]
      "supportedClaims" : null,
      "supportedScopes" : null,
   }
}
```

Pay attention to the three key/value pairs in the response; `resultMessage`, `action` and `ticket` as seen above.

* `resultMessage` provides a human-readable result of the request processing (See also [Interpreting Authlete's result codes](/configuration-reference/error-handling-debugging/interpreting-authletes-result-codes)). `openid=true` indicates the request is to be processed in accordance with the OIDC protocol.
* `action` indicates what the authorization server should do next. (See also [Action Handling](/get-started/concepts/action-handling))
* `ticket` is required for the authorization server to make a request to another API in the next step. (See also [Two-Step API Calls](/get-started/concepts/two-step-api-calls))

Authlete also provides service and client information in the response. The authorization server uses them to ask the resource owner if he or she authorizes access for the client to the service.

## User authentication and confirmation of sharing authentication result

Actual interaction between the resource owner and the authorization server is out of scope in this tutorial. In most cases, authorization server would authenticate user with some credentials (e.g. ID/password), determine roles and privileges for the user, and ask the user if he or she authorizes to share the authentication result with the client (steps #7, #8, #9).

## Issuing an authorization code

Let's assume the authorization server reaches the following state after completion of the previous process:

* The authorization server has authenticated the resource owner, and determined that an identifier for the resource owner, to be shared with Authlete as a value of `subject` parameter,  is `testuser01`.
* The authorization server has got consent from the resource owner.

The authorization server makes a request to Authlete's [`/auth/authorization/issue`](/api-reference/authorization-endpoint/issue-authorization-response) in order to issue an authorization code. It specifies values of `subject` and `ticket` that were a part of the response from `/auth/authorization` API, as request parameters.

Execute the following `curl` command (message #10), making sure to replace `<Service ID>`, `<Service Access Token>` and `<Ticket>` by your own values generated in the previous step.

<CodeGroup>
  ```text cURL theme={null}
  curl -s -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/authorization/issue \
  -H 'Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
  -H 'Content-Type: application/json' \
  -d '{ "ticket": "<Ticket e.g. bi2Kxe2WW5mK_GZ_fDFOpK1bnY6xTy40Ap_8nxf-7AU>", "subject": "testuser01" }'
  ```

  ```powershell PowerShell theme={null}
  $headers = @{ Authorization = "Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>" }
  $body = '{ "ticket": "<Ticket e.g. bi2Kxe2WW5mK_GZ_fDFOpK1bnY6xTy40Ap_8nxf-7AU>", "subject": "testuser01" }'
  Invoke-RestMethod -Method Post `
    -Uri "https://us.authlete.com/api/<Service" `
    -Headers $headers -ContentType "application/json" -Body $body
  ```

  ```java Java theme={null}
  // Reuse the authleteApi client created in the authorization step.
  AuthorizationIssueRequest request = new AuthorizationIssueRequest()
          .setTicket("bi2Kxe2WW5mK_GZ_fDFOpK1bnY6xTy40Ap_8nxf-7AU")
          .setSubject("testuser01");

  AuthorizationIssueResponse response = authleteApi.authorizationIssue(request);
  System.out.println(response.getAction());           // LOCATION
  System.out.println(response.getAuthorizationCode());
  System.out.println(response.getResponseContent());
  ```

  ```typescript TypeScript theme={null}
  // Reuse the `authlete` client and SERVICE_ID created in the authorization step.
  const res = await authlete.authorization.issue({
    serviceId: SERVICE_ID,
    authorizationIssueRequest: {
      ticket: "bi2Kxe2WW5mK_GZ_fDFOpK1bnY6xTy40Ap_8nxf-7AU",
      subject: "testuser01",
    },
  });
  console.log(res.action);            // "LOCATION"
  console.log(res.authorizationCode);
  console.log(res.responseContent);
  ```

  ```ruby Ruby theme={null}
  # Reuse the `client` and SERVICE_ID created in the authorization step.
  req = Authlete::Models::Components::AuthorizationIssueRequest.new(
    ticket:  "bi2Kxe2WW5mK_GZ_fDFOpK1bnY6xTy40Ap_8nxf-7AU",
    subject: "testuser01"
  )
  res = client.authorization.issue_response(service_id: SERVICE_ID, authorization_issue_request: req)

  puts res.authorization_issue_response.action            # "LOCATION"
  puts res.authorization_issue_response.authorization_code
  puts res.authorization_issue_response.response_content
  ```

  ```go Go theme={null}
  // Reuse the `s` client and serviceID created in the authorization step.
  res, err := s.Authorization.Issue(ctx, serviceID, components.AuthorizationIssueRequest{
  	Ticket:  "bi2Kxe2WW5mK_GZ_fDFOpK1bnY6xTy40Ap_8nxf-7AU",
  	Subject: "testuser01",
  })
  if err != nil {
  	log.Fatal(err)
  }
  log.Printf("action=%v", *res.AuthorizationIssueResponse.Action) // LOCATION
  log.Printf("authorizationCode=%s", *res.AuthorizationIssueResponse.AuthorizationCode)
  log.Printf("responseContent=%s", *res.AuthorizationIssueResponse.ResponseContent)
  ```
</CodeGroup>

If successful, Authlete will reply with the following response (step #11).

```json theme={null}
{
   "action" : "LOCATION",
   "resultCode" : "A040001",
   "accessTokenDuration" : 0,
   "accessTokenExpiresAt" : 0,
   "resultMessage" : "[A040001] The authorization request was processed successfully.",
   "responseContent" : "https://client.example.org/cb/example.com?code=GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U",
   "authorizationCode" : "GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U",
   ...
}
```

Pay attention to three key/value pairs in the response; `resultMessage`, `action` and `responseContent`.

* `resultMessage` provides a human-readable result of the request processing. (See also [Interpreting Authlete's result codes](/configuration-reference/error-handling-debugging/interpreting-authletes-result-codes))
* `action` indicates what the authorization server should do next. The value in this response is `LOCATION`, which means the authorization server should make a redirection response back to the user agent. (See also [Action Handling](/get-started/concepts/action-handling))
* `responseContent` is the content of the response from the authorization server. (See also [Action Handling](/get-started/concepts/action-handling))

The authorization server is expected to make the following response (new line for readability) to the user agent (step #12).

```http theme={null}
HTTP/1.1 302 Found
Location: https://client.example.org/cb/example.com
 ?code=GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U
```

## Failure to issue an authorization code

Alternatively, the authorization server may fail to receive authorization. In this instance, it won't issue tokens to the client. In that situation the authorization server would notify the client that the authorization flow is terminated. Authlete's [`/auth/authorization/fail`](/api-reference/authorization-endpoint/fail-authorization-request) API supports the termination process in terms of messages to be sent to the client, and transfer method for the response.

To summarize, under most circumstances, the authentication server sends a request to either `/auth/authorization/issue` or `/auth/authorization/fail` API depending on the result of user authentication and consent.

## Token request

Here we assume that the user agent receives the redirection response form the authorization server. It would send the following request (new line for readability) to the client (step #13).

```http theme={null}
GET /cb/example.com?code=GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U HTTP/1.1
Host: client.example.org
```

The client needs to extract the value of the `code` parameter, construct a token request using its value and send it to the authorization server as follows (new lines for readability). `https://as.example.com/token` is the token endpoint URI in this tutorial (step #14).

```http theme={null}
POST /token HTTP/1.1
Host: as.example.com
Authorization: Basic base64(12898884596863:-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg)
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
 &code=GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U
 &redirect_uri=https://client.example.org/cb/example.com
```

Once again, the authorization server passes the request on to the Authlete API to evaluate parameters in the request and get a token response back to the client.

Once again, let's simulate this step using Authlete's  [`/auth/token`](/api-reference/token-endpoint/process-token-request) API to evaluate the request and create the response.

Execute the following `curl` command (step #15), again making sure to replace `<Service ID>`, `<Service Access Token>`, `<Client ID>`, `<Client Secret>` and `<Code>` by your own values generated in the previous step.

<CodeGroup>
  ```text cURL theme={null}
  curl -s -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/token \
  -H 'Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
  -H 'Content-Type: application/json' \
  -d '{ "clientId": "<Client ID e.g. 12898884596863>", "clientSecret": "<Client Secret e.g. -olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg>", "parameters": "grant_type=authorization_code&code=<Code e.g. GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U>&redirect_uri=https://client.example.org/cb/example.com" }'
  ```

  ```powershell PowerShell theme={null}
  $headers = @{ Authorization = "Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>" }
  $body = '{ "clientId": "<Client ID e.g. 12898884596863>", "clientSecret": "<Client Secret e.g. -olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg>", "parameters": "grant_type=authorization_code&code=<Code e.g. GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U>&redirect_uri=https://client.example.org/cb/example.com" }'
  Invoke-RestMethod -Method Post `
    -Uri "https://us.authlete.com/api/<Service" `
    -Headers $headers -ContentType "application/json" -Body $body
  ```

  ```java Java theme={null}
  // Reuse the authleteApi client created in the authorization step.
  TokenRequest request = new TokenRequest()
          .setClientId("12898884596863")
          .setClientSecret("-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg")
          .setParameters("grant_type=authorization_code"
                  + "&code=GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U"
                  + "&redirect_uri=https://client.example.org/cb/example.com");

  TokenResponse response = authleteApi.token(request);
  System.out.println(response.getAction());          // OK
  System.out.println(response.getAccessToken());
  System.out.println(response.getResponseContent());
  ```

  ```typescript TypeScript theme={null}
  // Reuse the `authlete` client and SERVICE_ID created in the authorization step.
  const res = await authlete.token.process({
    serviceId: SERVICE_ID,
    tokenRequest: {
      clientId: "12898884596863",
      clientSecret:
        "-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg",
      parameters:
        "grant_type=authorization_code&code=GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U&redirect_uri=https://client.example.org/cb/example.com",
    },
  });
  console.log(res.action);          // "OK"
  console.log(res.accessToken);
  console.log(res.responseContent);
  ```

  ```ruby Ruby theme={null}
  # Reuse the `client` and SERVICE_ID created in the authorization step.
  req = Authlete::Models::Components::TokenRequest.new(
    client_id:     "12898884596863",
    client_secret: "-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg",
    parameters:    "grant_type=authorization_code&code=GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U&redirect_uri=https://client.example.org/cb/example.com"
  )
  res = client.tokens.process_request(service_id: SERVICE_ID, token_request: req)

  puts res.token_response.action           # "OK"
  puts res.token_response.access_token
  puts res.token_response.response_content
  ```

  ```go Go theme={null}
  // Reuse the `s` client and serviceID created in the authorization step.
  res, err := s.Token.Process(ctx, serviceID, components.TokenRequest{
  	ClientID:     types.String("12898884596863"), // types: github.com/authlete/authlete-go-sdk/types
  	ClientSecret: types.String("-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg"),
  	Parameters:   "grant_type=authorization_code&code=GrYz5vtk6VaF0jxfnDrB2yvmk4deIrnMkrGT07JdM5U&redirect_uri=https://client.example.org/cb/example.com",
  })
  if err != nil {
  	log.Fatal(err)
  }
  log.Printf("action=%v", *res.TokenResponse.Action) // OK
  log.Printf("accessToken=%s", *res.TokenResponse.AccessToken)
  log.Printf("responseContent=%s", *res.TokenResponse.ResponseContent)
  ```
</CodeGroup>

If successful, Authlete will reply with the following response (message #16).

```json theme={null}
{
   "resultMessage" : "[A050001] The token request (grant_type=authorization_code) was processed successfully.",
   "action" : "OK",
   "clientIdAliasUsed" : false,
   "subject" : "testuser01",
   "resultCode" : "A050001",
   "refreshTokenExpiresAt" : 1730552811449,
   "grantType" : "AUTHORIZATION_CODE",
   "accessToken" : "7FfwOnGjVHwxXhs2Wr67XV1-ZhQaoy3ctKcGkLyKxuY",
   "idToken" : "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTU5MTA2ODE1LCJpYXQiOjE1NTkwMjA0MTUsIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.5uSFMTGnubyvtiExHc9l7HT9UsF8a_Qb0STtWzyclBk",
   "responseContent" : "{\"access_token\":\"7FfwOnGjVHwxXhs2Wr67XV1-ZhQaoy3ctKcGkLyKxuY\",\"refresh_token\":\"T1h7fJ6k55CyipDtXNPbzN8ta3FgAAf4QKjo36OVfIE\",\"scope\":\"openid\",\"id_token\":\"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTU5MTA2ODE1LCJpYXQiOjE1NTkwMjA0MTUsIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.5uSFMTGnubyvtiExHc9l7HT9UsF8a_Qb0STtWzyclBk\",\"token_type\":\"Bearer\",\"expires_in\":86400}",
   "scopes" : [
      "openid"
   ],
   "accessTokenDuration" : 86400,
   "type" : "tokenResponse",
   "refreshToken" : "T1h7fJ6k55CyipDtXNPbzN8ta3FgAAf4QKjo36OVfIE",
   "accessTokenExpiresAt" : 1730552811449,
   "refreshTokenDuration" : 864000,
   "clientId" : 12898884596863
}
```

Pay attention to three key/value pairs in the response; `resultMessage`, `action` and `responseContent`.

* `resultMessage` provides human-readable result of the request processing. (See also [Interpreting Authlete's result codes](/configuration-reference/error-handling-debugging/interpreting-authletes-result-codes))
* `action` indicates what the authorization server should do next. The value in this response is `OK`, which means the authorization server should make a token response back to the client. (See also [Action Handling](/get-started/concepts/action-handling))
* `responseContent` is supposed to be content of the response from the authorization server. (See also [Action Handling](/get-started/concepts/action-handling))

The authorization server would then pass the following response to the client (message #17).

```http theme={null}
HTTP/1.1 200 OK
Content-Type: application/json

{
 "access_token":"7FfwOnGjVHwxXhs2Wr67XV1-ZhQaoy3ctKcGkLyKxuY",
 "refresh_token":"T1h7fJ6k55CyipDtXNPbzN8ta3FgAAf4QKjo36OVfIE",
 "scope":"openid",
 "id_token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTU5MTA2ODE1LCJpYXQiOjE1NTkwMjA0MTUsIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.5uSFMTGnubyvtiExHc9l7HT9UsF8a_Qb0STtWzyclBk",
 "token_type":"Bearer",
 "expires_in":86400
}
```

The client now has the tokens which have been generated by the Authlete API and passed back through the authorization server.

## Decoding ID token

The most common next step is for the client to decode the value of `id_token` in the response and verify it.

To perform this function, we're going to decode the token with the free open source tool [Online JWT Verfier](https://kjur.github.io/jsrsasign/tool/tool_jwtveri.html).

Open the link above, and paste the value of the `id_token` into the text area in *(Step 1) Set JWT (JSON Web Token) to verify* on the JWT Verifier UI. In this tutorial, the value is: `eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImlzcyI6Imh0dHBzOi8vYXV0aGxldGUuY29tIiwiZXhwIjoxNTU5MTA2ODE1LCJpYXQiOjE1NTkwMjA0MTUsIm5vbmNlIjoibi0wUzZfV3pBMk1qIn0.5uSFMTGnubyvtiExHc9l7HT9UsF8a_Qb0STtWzyclBk`

Click the **Just Decode JWT** button in *(Step 3) Verify* and see decoded content in the *Parsed JWT* section.

<figure class="figure bg-transparent border-0">
  <img src="https://mintcdn.com/authlete/6e8OPufcWwl4fTPw/get-started/authlete-decoded-id-token-authlete-url.png?fit=max&auto=format&n=6e8OPufcWwl4fTPw&q=85&s=bc8f89d1a5607fdcbb10003a0f8eea48" class="figure-img img-fluid rounded" alt="decoded JWT token showing header and payload" width="866" height="1233" data-path="get-started/authlete-decoded-id-token-authlete-url.png" />
</figure>

The decoded results are as follows.

**Header:**

```json theme={null}
{
  "alg": "HS256"
}
```

**Payload:**

```json theme={null}
{
  "sub": "testuser01",
  "aud": [
    "12898884596863"
  ],
  "iss": "https://authlete.com",
  "exp": 1730552811,
  "iat": 1730552811,
  "nonce": "n-0S6_WzA2Mj"
}
```

Note above there are a couple of items that need to be corrected.

* `iss` is `https://authlete.com`, which is the default value of Authlete. It must be `https://as.example.com`, that is the identifier of the authorization server in this tutorial.
* `sub` is the only attribute related to the user's identity. It may be better to include other user attributes for the client's convenience.

Let's fix the `iss` value and add other claims in the next section.

# Modifying ID token

## Issuer identifier

Login to the Management Console [https://console.authlete.com](https://console.authlete.com) and select the *Demo AS* service previously created during this tutorial. Click the **Service Settings** button to access the Service Settings.

<figure class="figure bg-transparent border-0">
  <img src="https://mintcdn.com/authlete/6e8OPufcWwl4fTPw/get-started/authlete-service-click-service-settings.png?fit=max&auto=format&n=6e8OPufcWwl4fTPw&q=85&s=99462b893f75a8e6805e36d275b86c89" class="figure-img img-fluid rounded" alt="the Authlete service with the service settings button highlighted" width="1659" height="392" data-path="get-started/authlete-service-click-service-settings.png" />
</figure>

Note that the default value of *Issuer Identifier* on the *General* tab is `https://authlete.com`. Change it to `https://as.example.com` and click the **Save Changes** button in the bottom of the page.

<figure class="figure bg-transparent border-0">
  <img src="https://mintcdn.com/authlete/6e8OPufcWwl4fTPw/get-started/authlete-service-issuer-id-url.png?fit=max&auto=format&n=6e8OPufcWwl4fTPw&q=85&s=58a1a563aaf6aa6fade54df58d6c9b70" class="figure-img img-fluid rounded" alt="Authlete service settings with updated issuer identifier URL" width="1659" height="970" data-path="get-started/authlete-service-issuer-id-url.png" />
</figure>

Now that the Token Issuer Identifier `iss` has been fixed.

## Authorization Request

Let's make the same authorization request as the previous one (using the same `nonce` value for convenience) to Authlete's [`/auth/authorization`](/api-reference/authorization-endpoint/process-authorization-request) API (step #5). Make sure to replace `<Service ID>`, `<Service Access Token>` and `<Client ID>` by your own values generated in the previous step.

<CodeGroup>
  ```text cURL theme={null}
  curl -s -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/authorization \
  -H 'Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
  -H 'Content-Type: application/json' \
  -d '{ "parameters": "redirect_uri=https://client.example.org/cb/example.com&response_type=code&client_id=<Client ID e.g. 12898884596863>&scope=openid&nonce=n-0S6_WzA2Mj" }'
  ```

  ```powershell PowerShell theme={null}
  $headers = @{ Authorization = "Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>" }
  $body = '{ "parameters": "redirect_uri=https://client.example.org/cb/example.com&response_type=code&client_id=<Client ID e.g. 12898884596863>&scope=openid&nonce=n-0S6_WzA2Mj" }'
  Invoke-RestMethod -Method Post `
    -Uri "https://us.authlete.com/api/<Service" `
    -Headers $headers -ContentType "application/json" -Body $body
  ```

  ```java Java theme={null}
  // Reuse the authleteApi client created earlier — the same authorization request as before.
  AuthorizationRequest request = new AuthorizationRequest()
          .setParameters("redirect_uri=https://client.example.org/cb/example.com"
                  + "&response_type=code"
                  + "&client_id=12898884596863"
                  + "&scope=openid"
                  + "&nonce=n-0S6_WzA2Mj");

  AuthorizationResponse response = authleteApi.authorization(request);
  System.out.println(response.getAction()); // INTERACTION
  System.out.println(response.getTicket());
  ```

  ```typescript TypeScript theme={null}
  // Reuse the `authlete` client and SERVICE_ID created earlier.
  const res = await authlete.authorization.processRequest({
    serviceId: SERVICE_ID,
    authorizationRequest: {
      parameters:
        "redirect_uri=https://client.example.org/cb/example.com&response_type=code&client_id=12898884596863&scope=openid&nonce=n-0S6_WzA2Mj",
    },
  });
  console.log(res.action); // "INTERACTION"
  console.log(res.ticket);
  ```

  ```ruby Ruby theme={null}
  # Reuse the `client` and SERVICE_ID created earlier.
  req = Authlete::Models::Components::AuthorizationRequest.new(
    parameters: "redirect_uri=https://client.example.org/cb/example.com&response_type=code&client_id=12898884596863&scope=openid&nonce=n-0S6_WzA2Mj"
  )
  res = client.authorization.process_request(service_id: SERVICE_ID, authorization_request: req)

  puts res.authorization_response.action # "INTERACTION"
  puts res.authorization_response.ticket
  ```

  ```go Go theme={null}
  // Reuse the `s` client and serviceID created earlier.
  res, err := s.Authorization.ProcessRequest(ctx, serviceID, components.AuthorizationRequest{
  	Parameters: "redirect_uri=https://client.example.org/cb/example.com&response_type=code&client_id=12898884596863&scope=openid&nonce=n-0S6_WzA2Mj",
  })
  if err != nil {
  	log.Fatal(err)
  }
  log.Printf("action=%v", *res.AuthorizationResponse.Action) // INTERACTION
  log.Printf("ticket=%s", *res.AuthorizationResponse.Ticket)
  ```
</CodeGroup>

You should receive the following response (shortened for brevity).

```json theme={null}
{
   [...]
   "action" : "INTERACTION",
   "resultCode" : "A004001",
   "resultMessage" : "[A004001] Authlete has successfully issued a ticket to the service (API Key = 10738933707579) for the authorization request from the client (ID = 12898884596863). [response_type=code, openid=true]",
   "ticket" : "JjQ_Th1UvZyU5MsdKTLIfLv3VlKwEiYnnULmW6l_d9A",
}
```

## Additional claims

Let's make a request to Authlete's [`/auth/authorization/issue`](/api-reference/authorization-endpoint/issue-authorization-response) for issuance of an authorization code. Make sure to replace `<Service ID>`, `<Service Access Token>` and `<Ticket>` by your own values generated in the previous step.

This time the following additional claims are included on making the request to the API.

| Item             | Value                    |
| ---------------- | ------------------------ |
| `name`           | `Test User`              |
| `email`          | `testuser01@example.com` |
| `email_verified` | true                     |

You can use the `claims` parameter to add claims. The request will be constructed as follows.

<CodeGroup>
  ```text cURL theme={null}
  curl -s -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/authorization/issue \
  -H 'Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
  -H 'Content-Type: application/json' \
  -d '{ "ticket": "<Ticket e.g. JjQ_Th1UvZyU5MsdKTLIfLv3VlKwEiYnnULmW6l_d9A>", "subject": "testuser01", "claims": "{\"name\": \"Test User\", \"email\": \"testuser01@example.com\", \"email_verified\": true}" }'
  ```

  ```powershell PowerShell theme={null}
  $headers = @{ Authorization = "Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>" }
  $body = '{ "ticket": "<Ticket e.g. JjQ_Th1UvZyU5MsdKTLIfLv3VlKwEiYnnULmW6l_d9A>", "subject": "testuser01", "claims": "{\"name\": \"Test User\", \"email\": \"testuser01@example.com\", \"email_verified\": true}" }'
  Invoke-RestMethod -Method Post `
    -Uri "https://us.authlete.com/api/<Service" `
    -Headers $headers -ContentType "application/json" -Body $body
  ```

  ```java Java theme={null}
  // Reuse the authleteApi client created earlier. `claims` is a JSON string.
  AuthorizationIssueRequest request = new AuthorizationIssueRequest()
          .setTicket("JjQ_Th1UvZyU5MsdKTLIfLv3VlKwEiYnnULmW6l_d9A")
          .setSubject("testuser01")
          .setClaims("{\"name\":\"Test User\","
                  + "\"email\":\"testuser01@example.com\","
                  + "\"email_verified\":true}");

  AuthorizationIssueResponse response = authleteApi.authorizationIssue(request);
  System.out.println(response.getAction());           // LOCATION
  System.out.println(response.getAuthorizationCode());
  System.out.println(response.getResponseContent());
  ```

  ```typescript TypeScript theme={null}
  // Reuse the `authlete` client and SERVICE_ID created earlier. `claims` is a JSON string.
  const res = await authlete.authorization.issue({
    serviceId: SERVICE_ID,
    authorizationIssueRequest: {
      ticket: "JjQ_Th1UvZyU5MsdKTLIfLv3VlKwEiYnnULmW6l_d9A",
      subject: "testuser01",
      claims: JSON.stringify({
        name: "Test User",
        email: "testuser01@example.com",
        email_verified: true,
      }),
    },
  });
  console.log(res.action);            // "LOCATION"
  console.log(res.authorizationCode);
  console.log(res.responseContent);
  ```

  ```ruby Ruby theme={null}
  # Reuse the `client` and SERVICE_ID created earlier. `claims` is a JSON string.
  req = Authlete::Models::Components::AuthorizationIssueRequest.new(
    ticket:  "JjQ_Th1UvZyU5MsdKTLIfLv3VlKwEiYnnULmW6l_d9A",
    subject: "testuser01",
    claims:  '{"name":"Test User","email":"testuser01@example.com","email_verified":true}'
  )
  res = client.authorization.issue_response(service_id: SERVICE_ID, authorization_issue_request: req)

  puts res.authorization_issue_response.action            # "LOCATION"
  puts res.authorization_issue_response.authorization_code
  puts res.authorization_issue_response.response_content
  ```

  ```go Go theme={null}
  // Reuse the `s` client and serviceID created earlier. Claims is a *string of JSON.
  res, err := s.Authorization.Issue(ctx, serviceID, components.AuthorizationIssueRequest{
  	Ticket:  "JjQ_Th1UvZyU5MsdKTLIfLv3VlKwEiYnnULmW6l_d9A",
  	Subject: "testuser01",
  	Claims:  types.String(`{"name":"Test User","email":"testuser01@example.com","email_verified":true}`), // types: github.com/authlete/authlete-go-sdk/types
  })
  if err != nil {
  	log.Fatal(err)
  }
  log.Printf("action=%v", *res.AuthorizationIssueResponse.Action) // LOCATION
  log.Printf("authorizationCode=%s", *res.AuthorizationIssueResponse.AuthorizationCode)
  log.Printf("responseContent=%s", *res.AuthorizationIssueResponse.ResponseContent)
  ```
</CodeGroup>

Then you will receive the following response.

```json theme={null}
{
   "responseContent" : "https://client.example.org/cb/example.com?code=ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI",
   "accessTokenDuration" : 0,
   "authorizationCode" : "ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI",
   "accessTokenExpiresAt" : 0,
   "type" : "authorizationIssueResponse",
   "resultMessage" : "[A040001] The authorization request was processed successfully.",
   "resultCode" : "A040001",
   "action" : "LOCATION"
}
```

We assume the authorization server makes a redirection response to the user agent, and then the user agent makes the following HTTP `GET` request to the client.

```shell theme={null}
GET /cb/example.com?code=ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI HTTP/1.1
Host: client.example.org
```

## Token request

The client makes a token request (new lines for readability) to the authorization server.

```http theme={null}
POST /token HTTP/1.1
Host: as.example.com
Authorization: Basic base64(12898884596863:-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg)
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
 &code=ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI
 &redirect_uri=https://client.example.org/cb/example.com
```

The authorization server is supposed to make a request to Authlete's [`/auth/token`](/api-reference/token-endpoint/process-token-request) API.

<CodeGroup>
  ```text cURL theme={null}
  curl -s -X POST https://us.authlete.com/api/<Service ID e.g. 10738933707579>/auth/token \
  -H 'Authorization: Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>' \
  -H 'Content-Type: application/json' \
  -d '{ "clientId": "<Client ID e.g. 12898884596863>", "clientSecret": "<Client Secret e.g. -olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg>", "parameters": "grant_type=authorization_code&code=<Code e.g. ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI>&redirect_uri=https://client.example.org/cb/example.com" }'
  ```

  ```powershell PowerShell theme={null}
  $headers = @{ Authorization = "Bearer <Service Access Token e.g. Xg6jVpJCvsaXvy2ks8R5WzjdMYlvQqOym3slDX0wNhQ>" }
  $body = '{ "clientId": "<Client ID e.g. 12898884596863>", "clientSecret": "<Client Secret e.g. -olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg>", "parameters": "grant_type=authorization_code&code=<Code e.g. ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI>&redirect_uri=https://client.example.org/cb/example.com" }'
  Invoke-RestMethod -Method Post `
    -Uri "https://us.authlete.com/api/<Service" `
    -Headers $headers -ContentType "application/json" -Body $body
  ```

  ```java Java theme={null}
  // Reuse the authleteApi client created earlier.
  TokenRequest request = new TokenRequest()
          .setClientId("12898884596863")
          .setClientSecret("-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg")
          .setParameters("grant_type=authorization_code"
                  + "&code=ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI"
                  + "&redirect_uri=https://client.example.org/cb/example.com");

  TokenResponse response = authleteApi.token(request);
  System.out.println(response.getAction());          // OK
  System.out.println(response.getAccessToken());
  System.out.println(response.getResponseContent());
  ```

  ```typescript TypeScript theme={null}
  // Reuse the `authlete` client and SERVICE_ID created earlier.
  const res = await authlete.token.process({
    serviceId: SERVICE_ID,
    tokenRequest: {
      clientId: "12898884596863",
      clientSecret:
        "-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg",
      parameters:
        "grant_type=authorization_code&code=ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI&redirect_uri=https://client.example.org/cb/example.com",
    },
  });
  console.log(res.action);          // "OK"
  console.log(res.accessToken);
  console.log(res.responseContent);
  ```

  ```ruby Ruby theme={null}
  # Reuse the `client` and SERVICE_ID created earlier.
  req = Authlete::Models::Components::TokenRequest.new(
    client_id:     "12898884596863",
    client_secret: "-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg",
    parameters:    "grant_type=authorization_code&code=ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI&redirect_uri=https://client.example.org/cb/example.com"
  )
  res = client.tokens.process_request(service_id: SERVICE_ID, token_request: req)

  puts res.token_response.action           # "OK"
  puts res.token_response.access_token
  puts res.token_response.response_content
  ```

  ```go Go theme={null}
  // Reuse the `s` client and serviceID created earlier.
  res, err := s.Token.Process(ctx, serviceID, components.TokenRequest{
  	ClientID:     types.String("12898884596863"), // types: github.com/authlete/authlete-go-sdk/types
  	ClientSecret: types.String("-olDIKD9BihRfB8O1JxobUEKBZ7PIV5Z6oaqxAshmoUtUZgB-wjmmxTYDiDV6vM_Mgl267PeNrRftq8cWplvmg"),
  	Parameters:   "grant_type=authorization_code&code=ILePyGjraVgeU_fzaQRfd0gv10pzxgcpHY_vHT2dsPI&redirect_uri=https://client.example.org/cb/example.com",
  })
  if err != nil {
  	log.Fatal(err)
  }
  log.Printf("action=%v", *res.TokenResponse.Action) // OK
  log.Printf("accessToken=%s", *res.TokenResponse.AccessToken)
  log.Printf("responseContent=%s", *res.TokenResponse.ResponseContent)
  ```
</CodeGroup>

Authlete returns the following response.

```json theme={null}
{
   "grantType" : "AUTHORIZATION_CODE",
   "responseContent" : "{\"access_token\":\"R4sd3s02Y1Gj72iI5Md6ZkGapXZ6mSnIEdihTvrM_Ro\",\"refresh_token\":\"k4WqWw2tcDOHxXXo29NxOCwQJyeDOtZ6aw_Y9Ugy-6U\",\"scope\":\"openid\",\"id_token\":\"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVGVzdCBVc2VyIiwiZW1haWwiOiJ0ZXN0dXNlcjAxQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImV4cCI6MTU1OTEzNzMwMSwiaWF0IjoxNTU5MDUwOTAxLCJub25jZSI6Im4tMFM2X1d6QTJNaiJ9.8ngbBoGLUvHXIO4VyGN0-txJfE5Yq86xElMSxqGlLv0\",\"token_type\":\"Bearer\",\"expires_in\":86400}",
   "resultMessage" : "[A050001] The token request (grant_type=authorization_code) was processed successfully.",
   "accessTokenExpiresAt" : 1730554257440,
   "accessToken" : "R4sd3s02Y1Gj72iI5Md6ZkGapXZ6mSnIEdihTvrM_Ro",
   "resultCode" : "A050001",
   "scopes" : [
      "openid"
   ],
   "refreshTokenExpiresAt" : 1730554257440,
   "subject" : "testuser01",
   "action" : "OK",
   "refreshTokenDuration" : 864000,
   "accessTokenDuration" : 86400,
   "refreshToken" : "k4WqWw2tcDOHxXXo29NxOCwQJyeDOtZ6aw_Y9Ugy-6U",
   "clientIdAliasUsed" : false,
   "idToken" : "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVGVzdCBVc2VyIiwiZW1haWwiOiJ0ZXN0dXNlcjAxQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImV4cCI6MTU1OTEzNzMwMSwiaWF0IjoxNTU5MDUwOTAxLCJub25jZSI6Im4tMFM2X1d6QTJNaiJ9.8ngbBoGLUvHXIO4VyGN0-txJfE5Yq86xElMSxqGlLv0",
   "clientId" : 12898884596863
}
```

The authorization server is expected to return the following response to the client (message #17).

```json theme={null}
HTTP/1.1 200 OK
Content-Type: application/json

{
 "access_token":"R4sd3s02Y1Gj72iI5Md6ZkGapXZ6mSnIEdihTvrM_Ro",
 "refresh_token":"k4WqWw2tcDOHxXXo29NxOCwQJyeDOtZ6aw_Y9Ugy-6U",
 "scope":"openid",
 "id_token":"eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVGVzdCBVc2VyIiwiZW1haWwiOiJ0ZXN0dXNlcjAxQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImV4cCI6MTU1OTEzNzMwMSwiaWF0IjoxNTU5MDUwOTAxLCJub25jZSI6Im4tMFM2X1d6QTJNaiJ9.8ngbBoGLUvHXIO4VyGN0-txJfE5Yq86xElMSxqGlLv0",
 "token_type":"Bearer",
 "expires_in":86400
}
```

As the client on receiving the response, let's try to decode the token with [Online JWT Verfier](https://kjur.github.io/jsrsasign/tool/tool_jwtveri.html) again.

Open the link above, and paste the value of the `id_token` to textarea in *Step 1*. In this tutorial, the value is: `eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiVGVzdCBVc2VyIiwiZW1haWwiOiJ0ZXN0dXNlcjAxQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOi8vYXMuZXhhbXBsZS5jb20iLCJzdWIiOiJ0ZXN0dXNlcjAxIiwiYXVkIjpbIjEyODk4ODg0NTk2ODYzIl0sImV4cCI6MTU1OTEzNzMwMSwiaWF0IjoxNTU5MDUwOTAxLCJub25jZSI6Im4tMFM2X1d6QTJNaiJ9.8ngbBoGLUvHXIO4VyGN0-txJfE5Yq86xElMSxqGlLv0`

Click the **Just Decode JWT** button in *(Step 3) Verify* and see decoded content in the *Parsed JWT* section.

<figure class="figure bg-transparent border-0">
  <img src="https://mintcdn.com/authlete/6e8OPufcWwl4fTPw/get-started/authlete-decoded-id-token-example-url.png?fit=max&auto=format&n=6e8OPufcWwl4fTPw&q=85&s=e43b9b49cf5ff79957fed950a852337a" class="figure-img img-fluid rounded" alt="decoded JWT token showing header and payload included added claims" width="866" height="1277" data-path="get-started/authlete-decoded-id-token-example-url.png" />
</figure>

The decoded results are as follows.

**Header:**

```json theme={null}
{
  "alg": "HS256"
}
```

**Payload:**

```json theme={null}
{
  "name": "Test User",
  "email": "testuser01@example.com",
  "email_verified": true,
  "iss": "https://as.example.com",
  "sub": "testuser01",
  "aud": [
    "12898884596863"
  ],
  "exp": 1559137301,
  "iat": 1559050901,
  "nonce": "n-0S6_WzA2Mj"
}
```

Now we can confirm the correct `iss` value exists, and find the additional claims, `name`, `email` and `email_verified` are included as expected.

# Conclusion

In this tutorial, you were able to simulate an authorization server acting as an OpenID Connect Provider, issuing ID Tokens using the authorization code flow with the Authlete API. You completed the following high level steps.

* How to use Authlete APIs to implement authorization code flow into authorization server (OIDC identity provider)
* Set issuer identifier values in the Authlete Management Console including additional claims in an authorization request and see them decoded from the ID Token

While this walk through cut out some key pieces in the whole process, hopefully you have a deeper understanding of how an authorization server, hosted in your own infrastructure, would make use of Authlete as a back end service. Implementing such an authorization server on your own may contain complex logic and require detailed attention to potential secure treatment of codes and secrets. By using the Authlete API as a backend your own authorization server implementation is greatly simplified.

# Next steps

Let's dig deeper on Authlete by playing with the following features.

* [`/auth/authorization/fail`](/api-reference/authorization-endpoint/fail-authorization-request) API (See [Generating error response with "fail" API](/configuration-reference/error-handling-debugging/generating-error-response-using-fail-api))
* [`/auth/userinfo`](/api-reference/userinfo-endpoint/process-userinfo-request) API (See [Access token verification in Userinfo API](/configuration-reference/endpoints/access-token-verification-in-userinfo-api))
* [Token Management](/api-reference/token-operations/list-issued-tokens) API (See [Token Management](/configuration-reference/tokens-and-claims/managing-authorizations-issued-tokens-granted-for-a-client-by-a-user))
* [Authorization server implementations](https://github.com/authlete) (See [Getting Started](/get-started/quickstarts/getting-started))
* Signing an ID token with public key cryptography (See [Changing signing key for ID token](/configuration-reference/tokens-and-claims/changing-signing-key-for-id-tokens))
