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

# JWT Authorization Grant (RFC 7523 2.1)

> Explanation about JWT Authorization Grant defined in RFC 7523 Section 2.1 and Authlete's implementation.

<Note>
  This page is for **Authlete 2.x**. For current (3.0) documentation, see [this page](/protocols-and-flows/advanced-flows/jwt-authorization-grant-rfc-7523-2-1).
</Note>

# Overview

[Section 2.1. Using JWTs as Authorization Grants](https://www.rfc-editor.org/rfc/rfc7523.html#section-2.1) of [RFC 7523 JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants](https://www.rfc-editor.org/rfc/rfc7523.html) defines another flow for access token issuance which is different from OAuth 2.0 standard flows defined in [RFC 6749](https://www.rfc-editor.org/rfc/rfc6749.html). We call it **JWT Authorization Grant** flow.

In the flow, a JWT ([RFC 7519](https://www.rfc-editor.org/rfc/rfc7519.html)) is used as an **authorization grant**, which indicates that its holder has been authorized to get an access token. The **JWT as an authorization grant** is the same concept as an **authorization code** in the authorization code flow ([RFC 6749](https://www.rfc-editor.org/rfc/rfc6749.html) [Section 4.1](https://www.rfc-editor.org/rfc/rfc6749.html#section-4.1)).

An access token requester can obtain an access token by presenting a JWT at the **token endpoint** ([RFC 6749](https://www.rfc-editor.org/rfc/rfc6749.html) [Section 3.2](https://www.rfc-editor.org/rfc/rfc6749.html#section-3.2)). The diagram below illustrates the flow.

<img src="https://mintcdn.com/authlete/Z6xXwx0zbVgSByug/img/developers/jwt_authorization_grant/jwt_authorization_grant.png?fit=max&auto=format&n=Z6xXwx0zbVgSByug&q=85&s=e2578f48084fecd8367eaa5a9b9e5a38" alt="" width="1920" height="1080" data-path="img/developers/jwt_authorization_grant/jwt_authorization_grant.png" />

# Specification

## Source of JWT

**[RFC 7523](https://www.rfc-editor.org/rfc/rfc7523.html) does not define details about how the JWT as an authorization grant is generated by whom**. Consequently, it is not defined in the specification how to obtain the key whereby to verify the signature of the JWT. Therefore, each deployment has to define their own rules which are necessary to identify the key for signature verification.

For example, some systems may define a rule like *"The JWT must be an ID Token issued by `https://example.com`"*. If a JWT is an ID Token, authorization server implementations can find the key for signature verification by using the standard mechanism (i.e. the discovery endpoint and the `jwks_uri` [server metadata](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata)). Other systems may choose to embed the key for signature verification in the JWT itself as entity statements of [OpenID Connect Federation 1.0](https://openid.net/specs/openid-connect-federation-1_0.html) do.

In any case, systems must define additional rules to complement [RFC 7523](https://www.rfc-editor.org/rfc/rfc7523.html) when they employ the specification.

## Token Request

### Grant Type

To distinguish the JWT authorization grant flow from others, the specification has defined a new grant type `urn:ietf:params:oauth:grant-type:jwt-bearer`. The value is used as the value of the `grant_type` request parameter of a token request.

### Client Identification and Authentication

The specification does not require **[client authentication](https://darutk.medium.com/oauth-2-0-client-authentication-4b5f929305d4)** and even **client identification** at the token endpoint. The specification states it as follows.

> JWT authorization grants may be used with or without client authentication or identification.

Technically speaking, *"with or without client authentication"* means that the specification does not care about whether the **client type** ([RFC 6749](https://www.rfc-editor.org/rfc/rfc6749.html) [Section 2.1](https://www.rfc-editor.org/rfc/rfc6749.html#section-2.1)) of the client application is **public** or **confidential**, and *"without client identification"* means that a token request does not contain information whereby to identify the client application making the request (e.g. lack of the `client_id` request parameter).

### Scopes

A token request of the JWT authorization grant flow may have the `scope` request parameter to specify scopes to request as the standard OAuth 2.0 flows may do.

### Assertion

A JWT used as an authorization grant is specified by the `assertion` request parameter, which is defined in [Section 4.1. Using Assertions as Authorization Grants](https://www.rfc-editor.org/rfc/rfc7521.html#section-4.1) of [RFC 7521 Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants](https://www.rfc-editor.org/rfc/rfc7521.html).

The table below is a summary about necessity of JWT claims. Detailed requirements on the claims are described in [Section 3](https://www.rfc-editor.org/rfc/rfc7523.html#section-3) of [RFC 7523](https://www.rfc-editor.org/rfc/rfc7523.html).

| Claim | Necessity |
| :---: | :-------: |
| `iss` |  REQUIRED |
| `sub` |  REQUIRED |
| `aud` |  REQUIRED |
| `exp` |  REQUIRED |
| `nbf` |  OPTIONAL |
| `iat` |  OPTIONAL |
| `jti` |  OPTIONAL |

### Example Request

The following is an example listed in [Section 2.1](https://www.rfc-editor.org/rfc/rfc7523.html#section-2.1) of [RFC 7523](https://www.rfc-editor.org/rfc/rfc7523.html).

```http theme={null}
POST /token.oauth2 HTTP/1.1
Host: as.example.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer
&assertion=eyJhbGciOiJFUzI1NiIsImtpZCI6IjE2In0.
eyJpc3Mi[...omitted for brevity...].
J9l-ZhwP[...omitted for brevity...]
```

## Token Response

Token responses in the JWT authorization grant flow conform to [RFC 6749](https://www.rfc-editor.org/rfc/rfc6749.html). No additional response parameters are defined by [RFC 7523](https://www.rfc-editor.org/rfc/rfc7523.html).

Only point to note is that `invalid_grant` must be used as the value of the `error` response parameter when the given JWT is invalid.

# Implementation

JWT authorization grant flow is supported by Authlete 2.3 onwards.

## Response from the `/auth/token` API

To support JWT authorization grant flow, a new action value `JWT_BEARER` was added. When the value of the `grant_type` request parameter of a token request is `urn:ietf:params:oauth:grant-type:jwt-bearer` and the request passes basic validation steps which are performed on Authlete server side, the value of the `action` response parameter in the response from Authlete's `/auth/token` API holds `JWT_BEARER`.

Authorization server implementations have to process the `JWT_BEARER` action to support JWT authorization grant flow. The `switch` statement below excerpted from [TokenRequestHandler.java](https://github.com/authlete/authlete-java-jaxrs/blob/master/src/main/java/com/authlete/jaxrs/TokenRequestHandler.java) in the [authlete-java-jaxrs](https://github.com/authlete/authlete-java-jaxrs/) library is an example of processing the `JWT_BEARER` action. The `switch` statement has a `case` entry for `JWT_BEARER`.

```java theme={null}
// Dispatch according to the action.
switch (action)
{
    case INVALID_CLIENT:
        // 401 Unauthorized
        return ResponseUtil.unauthorized(content, CHALLENGE);

    case INTERNAL_SERVER_ERROR:
        // 500 Internal Server Error
        return ResponseUtil.internalServerError(content);

    case BAD_REQUEST:
        // 400 Bad Request
        return ResponseUtil.badRequest(content);

    case PASSWORD:
        // Process the token request whose flow is "Resource Owner Password Credentials".
        return handlePassword(response);

    case OK:
        // 200 OK
        return ResponseUtil.ok(content);

    case TOKEN_EXCHANGE:
        // Process the token exchange request (RFC 8693)
        return handleTokenExchange(response);

    case JWT_BEARER:
        // Process the token request which uses the grant type
        // urn:ietf:params:oauth:grant-type:jwt-bearer (RFC 7523).
        return handleJwtBearer(response);

    default:
        // This never happens.
        throw getApiCaller().unknownAction("/api/auth/token", action);
}
```

The following table lists response parameters related to JWT authorization grant in a response from the `/auth/token` API.

| Response Parameter | Type         | Description                                                          |
| :----------------- | :----------- | :------------------------------------------------------------------- |
| `assertion`        | string       | The value of the `assertion` request parameter of the token request. |
| `scopes`           | string array | The value of the `scope` request parameter of the token request.     |

## Request Validation

When the grant type of a token request is `urn:ietf:params:oauth:grant-type:jwt-bearer`, Authlete (to be exact, the implementation of Authlete's `/auth/token` API) performs validation steps listed below in the order. Therefore, authorization server implementations can omit the same validation steps.

| No. | Validation                                                                                                                                                                                                                     |
| :-: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|  1  | Confirm that the `assertion` request parameter is given and its value is not empty.                                                                                                                                            |
|  2  | Confirm that the format conforms to the JWT specification ([RFC 7519 JSON Web Token (JWT)](https://www.rfc-editor.org/rfc/rfc7519.html)).                                                                                      |
|  3  | Check if the JWT is encrypted and if it is encrypted, then (a) reject the token request when the `jwtGrantEncryptedJwtRejected` flag of the service is `true` or (b) skip remaining validation steps when the flag is `false`. |
|  4  | Confirm that the JWT contains the `iss` claim and its value is a JSON string.                                                                                                                                                  |
|  5  | Confirm that the JWT contains the `sub` claim and its value is a JSON string.                                                                                                                                                  |
|  6  | Confirm that the JWT contains the `aud` claim and its value is either a JSON string or an array of JSON strings.                                                                                                               |
|  7  | Confirm that the issuer identifier of the service (the `issuer` server metadata) or the URL of the token endpoint (the `token_endpoint` server metadata) is listed as audience in the `aud` claim.                             |
|  8  | Confirm that the JWT contains the `exp` claim and the current time has not reached the time indicated by the claim.                                                                                                            |
|  9  | Confirm that the current time is equal to or after the time indicated by the `iat` claim if the JWT contains the claim.                                                                                                        |
|  10 | Confirm that the current time is equal to or after the time indicated by the `nbf` claim if the JWT contains the claim.                                                                                                        |
|  11 | Check if the JWT is signed and if it is not signed, then (a) reject the token request when the `jwtGrantUnsignedJwtRejected` flag of the service is `true` or (b) finish validation on the JWT.                                |

<Note>
  Authlete does not validate an encrypted JWT because there is no standard way to obtain the key to decrypt the JWT with. This means that **you must validate an encrypted JWT by yourself**.
</Note>

<Note>
  **Authlete does not verify the signature of the JWT** because there is no standard way to obtain the key to verify the signature of a JWT with. This means that **you must verify the signature of the JWT by yourself**.
</Note>

## Configuration

Authlete provides some configuration options related to JWT authorization grant as listed below. Authorization server implementers may utilize them and/or implement their own rules.

### Service Configuration

| Configuration Option      |   Type  | Description                                                                                                                                                                                                                                                       |
| :------------------------ | :-----: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Identifiable Clients Only | boolean | Whether to reject token requests by unidentifiable clients - `Service.jwtGrantByIdentifiableClientsOnly` ([JavaDoc](https://authlete.github.io/authlete-java-common/com/authlete/common/dto/Service.html#isJwtGrantByIdentifiableClientsOnly--))                  |
| Encrypted JWT Rejected    | boolean | Whether to reject token requests which use an encrypted JWT as an authorization grant - `Service.jwtGrantEncryptedJwtRejected` ([JavaDoc](https://authlete.github.io/authlete-java-common/com/authlete/common/dto/Service.html#isJwtGrantEncryptedJwtRejected--)) |
| Unsigned JWT Rejected     | boolean | Whether to reject token requests which use an unsigned JWT as an authorization grant - `Service.jwtGrantUnsignedJwtRejected` ([JavaDoc](https://authlete.github.io/authlete-java-common/com/authlete/common/dto/Service.html#isJwtGrantUnsignedJwtRejected--))    |

# Example

## Authorization Server Implementation Example

[JwtAuthzGrantProcessor.java](https://github.com/authlete/java-oauth-server/blob/master/src/main/java/com/authlete/jaxrs/server/api/JwtAuthzGrantProcessor.java) in **[java-oauth-server](https://github.com/authlete/java-oauth-server)**, an open-source sample implementation of authorization server written in Java, is a sample implementation of processing a token request of the JWT authorization grant flow.

Note that the implementation is just an example and does not intend to be perfect for commercial use.

## Request and Response Example

**1. Prepare a JWT in some way or other.**

```shell theme={null}
$ JWT=eyJraWQiOiJhdXRobGV0ZS1mYXBpZGV2LWFwaS0yMDE4MDUyNCIsImFsZyI6IlJTMjU2In0.eyJpc3MiOiJodHRwczovL2ZhcGlkZXYtYXMuYXV0aGxldGUubmV0LyIsInN1YiI6IjEwMDQiLCJhdWQiOlsiNTg5OTQ2MzYxNDQ0ODA2MyJdLCJleHAiOjE2NTg2NzExMzAsImlhdCI6MTY1ODY3MDgzMCwiYXV0aF90aW1lIjoxNjU4NjcwODMwLCJub25jZSI6IjEyMzQ1Njc4OSIsInZlcmlmaWVkX2NsYWltcyI6eyJ2ZXJpZmljYXRpb24iOnsidHJ1c3RfZnJhbWV3b3JrIjoibmlzdF84MDBfNjNBIn0sImNsYWltcyI6eyJnaXZlbl9uYW1lIjoiSW5nYSIsImZhbWlseV9uYW1lIjoiU2lsdmVyc3RvbmUiLCJiaXJ0aGRhdGUiOiIxOTkxLTExLTA2IiwiOmFnZV8xOF9vcl9vdmVyIjpudWxsfX19.mxE8FQaDb0edY_rWasSQ7pEMXbFon7oWr-Ccv1dB15q8eh2MaKRGrgvwPw_XjAdXlMNzkcV6iEUjRUvLGTvzm7_45cdoOxRX1xWzQw-vwvRbM46xd3Yht3EVjyRUUBJ_92J1yBmu7Nn93rygcnCE-fC_bSTSIJWgEnoC7dpxHYnoJ2QHrIOYFMBAA_3ZYCLGpgiWbIZnB2D1ib2eqwJ9zoJqeFNEBhXo9ThYkASHYaG-ZWofy7364lgeV4Rqy1r4XqzchFRW4yzWs_IM72bTtXTUkstlNOxZU12KEz50uVhtcOXv06iI71I9vceRP-ZVICpq7Knt0vEKWTM41E3ziw
```

**2. Make a token request.**

```shell theme={null}
$ curl http://localhost:8080/api/token -d grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer -d assertion=$JWT -d client_id=5908895171 -d scope=email
```

**3. Receive a token response.**

```json theme={null}
{
  "access_token":"NEdL-q9EfOI4S5XzaMeimXAXVqS139Jm9DTYeLUAd5o",
  "token_type":"Bearer",
  "expires_in":86400,
  "scope":"email"
}
```
