> ## 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 認可グラント (RFC 7523 2.1)

> RFC 7523 Section 2.1 で定義されている JWT 認可グラントの仕様と Authlete の実装の説明です。

<Info>
  For **Authlete 2.x** documentation, see [2.x version](/ja/v2/protocols-and-flows/grant-types/jwt-authorization-grant).
</Info>

# 概要

[RFC 7523 JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants](https://www.rfc-editor.org/rfc/rfc7523.html) の [Section 2.1. Using JWTs as Authorization Grants](https://www.rfc-editor.org/rfc/rfc7523.html#section-2.1) では、[RFC 6749](https://www.rfc-editor.org/rfc/rfc6749.html) で定義されている OAuth 2.0 標準フロー群とは異なる、アクセストークン発行のためのフローを定義しています。我々はそれを **JWT 認可グラント**フローと呼んでいます。

そのフローでは、JWT ([RFC 7519](https://www.rfc-editor.org/rfc/rfc7519.html)) が**認可グラント**として使用されます。認可グラントは、その保持者がアクセストークンを取得する認可を得ていることを示すものです。**認可グラントとしての JWT** は、認可コードフロー ([RFC 6749](https://www.rfc-editor.org/rfc/rfc6749.html) [Section 4.1](https://www.rfc-editor.org/rfc/rfc6749.html#section-4.1)) の**認可コード**と同じ概念です。

アクセストークン要求者は、**トークンエンドポイント** ([RFC 6749](https://www.rfc-editor.org/rfc/rfc6749.html) [Section 3.2](https://www.rfc-editor.org/rfc/rfc6749.html#section-3.2)) で JWT を提示することによりアクセストークンを取得できます。次の図はそのフローを示しています。

<img src="https://mintcdn.com/authlete/WGQFc11Y4wUplGrc/protocols-and-flows/advanced-flows/jwt_authorization_grant.ja.png?fit=max&auto=format&n=WGQFc11Y4wUplGrc&q=85&s=feadb21407501fe06dafd2941e8f0f89" alt="" width="1920" height="1080" data-path="protocols-and-flows/advanced-flows/jwt_authorization_grant.ja.png" />

# 仕様

## JWT の出所

\*\*認可グラントとしての JWT が誰によってどのように生成されるかに関する詳細を [RFC 7523](https://www.rfc-editor.org/rfc/rfc7523.html) では定義していません。\*\*従って、JWT の署名を検証するのに用いる鍵の入手方法が仕様では定義されていません。そのため、署名検証用鍵を特定するのに必要な独自規則をそれぞれの運用が定義しなければなりません。

例えば、システムは *「JWT は `https://example.com` が発行した ID トークンでなければならない」* という規則を定めるかもしれません。JWT が ID トークンであれば、認可サーバーの実装は標準的な仕組み (つまりディスカバリーエンドポイントと `jwks_uri` [サーバーメタデータ](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata)) を使って署名検証用鍵を見つけることができます。他のシステムは、[OpenID Connect Federation 1.0](https://openid.net/specs/openid-connect-federation-1_0.html) のエンティティーステートメントと同じように、JWT 自身に署名検証用鍵を埋め込むことを選択するかもしれません。

いずれにしても、[RFC 7523](https://www.rfc-editor.org/rfc/rfc7523.html) を採用する際は、同仕様を補完するための追加規則を定義しなければなりません。

## トークンリクエスト

### グラントタイプ

JWT 認可グラントフローと他のフローを区別するため、新しいグラントタイプ `urn:ietf:params:oauth:grant-type:jwt-bearer` が仕様で定義されています。この値はトークンリクエストの `grant_type` リクエストパラメーターの値として使用されます。

### クライアントの特定と認証

仕様は、トークンエンドポイントにおける\*\*[クライアント認証](https://qiita.com/TakahikoKawasaki/items/63ed4a9d8d6e5109e401)**を要求しておらず、さらには**クライアントの特定\*\*すら要求していません。仕様は次のように述べています。

> JWT authorization grants may be used with or without client authentication or identification.
>
> JWT 認可グラントの使用に際し、クライアント認証やクライアント特定が伴いうる。

技術的には *『クライアント認証が伴いうる』* とは、クライアントアプリケーションの**クライアントタイプ** ([RFC 6749](https://www.rfc-editor.org/rfc/rfc6749.html) [Section 2.1](https://www.rfc-editor.org/rfc/rfc6749.html#section-2.1)) が**パブリック**なのか**コンフィデンシャル**なのかについて仕様は気にしないということを意味しています。また *『クライアント未特定』* とは、トークンリクエストがクライアントを特定するための情報を含んでいないことを意味します (例えば `client_id` リクエストパラメーターの欠如など)。

### スコープ

OAuth 2.0 標準フロー群でも可能なように、JWT 認可グラントフローのトークンリクエストにおいても、要求するスコープ群を `scope` リクエストパラメーターで指定することができます。

### アサーション

認可グラントとして用いる JWT は `assertion` リクエストパラメーターで指定されます。このリクエストパラメーターは、[RFC 7521 Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants](https://www.rfc-editor.org/rfc/rfc7521.html) の [Section 4.1. Using Assertions as Authorization Grants](https://www.rfc-editor.org/rfc/rfc7521.html#section-4.1) で定義されています。

次の表は、JWT クレーム群の要否を要約したものです。クレーム群に対する詳細な要求事項は [RFC 7523](https://www.rfc-editor.org/rfc/rfc7523.html) の [Section 3](https://www.rfc-editor.org/rfc/rfc7523.html#section-3) で説明されています。

|  クレーム |  要否 |
| :---: | :-: |
| `iss` |  必須 |
| `sub` |  必須 |
| `aud` |  必須 |
| `exp` |  必須 |
| `nbf` |  任意 |
| `iat` |  任意 |
| `jti` |  任意 |

### リクエストの例

次のものは、[RFC 7523](https://www.rfc-editor.org/rfc/rfc7523.html) の [Section 2.1](https://www.rfc-editor.org/rfc/rfc7523.html#section-2.1) に掲載されている例です。

```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...]
```

## トークンレスポンス

JWT 認可グラントフローのトークンレスポンスは [RFC 6749](https://www.rfc-editor.org/rfc/rfc6749.html) に準拠します。[RFC 7523](https://www.rfc-editor.org/rfc/rfc7523.html) では追加のレスポンスパラメーターは定義されていません。

唯一の注意点は、与えられた JWT が無効の際、`error` レスポンスパラメーターの値として `invalid_grant` を用いなければならないということです。

# 実装

JWT 認可グラントフローは Authlete 2.3 以降でサポートされます。

## `/auth/token` API のレスポンス

JWT 認可グラントフローをサポートするため、新しいアクション値 `JWT_BEARER` が追加されました。トークンリクエストの `grant_type` パラメーターの値が `urn:ietf:params:oauth:grant-type:jwt-bearer` で、当リクエストが Authlete サーバー側で実行される基本的なバリデーション処理をパスした場合、Authlete の `/auth/token` API からのレスポンス内の `action` レスポンスパラメーターの値は `JWT_BEARER` になります。

JWT 認可グラントフローをサポートするためには、認可サーバーの実装は `JWT_BEARER` アクションを処理しなければなりません。次に示す `switch` 文は [authlete-java-jaxrs](https://github.com/authlete/authlete-java-jaxrs/) ライブラリの [TokenRequestHandler.java](https://github.com/authlete/authlete-java-jaxrs/blob/master/src/main/java/com/authlete/jaxrs/TokenRequestHandler.java) から抜粋したもので、`JWT_BEARER` アクション処理の一つの例です。当 `switch` 文には `JWT_BEARER` 用の `case` エントリーがあります。

```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);
}
```

次の表は `/auth/token` API からのレスポンスに含まれる JWT 認可グラント関連のレスポンスパラメーターのリストです。

| レスポンスパラメーター | 型     | 説明                                    |
| :---------- | :---- | :------------------------------------ |
| `assertion` | 文字列   | トークンリクエストの `assertion` リクエストパラメーターの値。 |
| `scopes`    | 文字列配列 | トークンリクエストの `scope` リクエストパラメーターの値。     |

## リクエストバリデーション

トークンリクエストのグラントタイプが `urn:ietf:params:oauth:grant-type:jwt-bearer` のとき、Authlete は (正確には Authlete の `/auth/token` API の実装は) 下記に示すバリデーション処理をこの順番で実施します。そのため、認可サーバーの実装は同じバリデーション処理を省略できます。

|  番号 | バリデーション                                                                                                                             |
| :-: | :---------------------------------------------------------------------------------------------------------------------------------- |
|  1  | `assertion` リクエストパラメーターが与えられていること、その値が空でないことを確認する。                                                                                  |
|  2  | フォーマットが JWT 仕様 ([RFC 7519 JSON Web Token (JWT)](https://www.rfc-editor.org/rfc/rfc7519.html)) に従っていることを確認する。                        |
|  3  | 当 JWT が暗号化されている場合、(a) サービスの `jwtGrantEncryptedJwtRejected` フラグが `true` であればトークンリクエストを拒否し、(b) 当フラグが `false` であれば以降のバリデーション処理をスキップする。 |
|  4  | 当 JWT が `iss` クレームを含んでおり、その値が JSON 文字列であることを確認する。                                                                                   |
|  5  | 当 JWT が `sub` クレームを含んでおり、その値が JSON 文字列であることを確認する。                                                                                   |
|  6  | 当 JWT が `aud` クレームを含んでおり、その値が JSON 文字列または JSON 文字列の配列であることを確認する。                                                                    |
|  7  | サービスの発行者識別子 (`issuer` サーバーメタデータ) またはトークンエンドポイントの URL (`token_endpoint` サーバーメタデータ) が `aud` クレームにリストされていることを確認する。                     |
|  8  | 当 JWT が `exp` クレームを含んでおり、現在時刻が当クレームで示される時刻に達していないことを確認する。                                                                           |
|  9  | 当 JWT が `iat` クレームを含んでいる場合、現在時刻が当クレームで示される時刻以降であることを確認する。                                                                           |
|  10 | 当 JWT が `nbf` クレームを含んでいる場合、現在時刻が当クレームで示される時刻以降であることを確認する。                                                                           |
|  11 | 当 JWT が無署名の場合、(a) サービスの `jwtGrantUnsignedJwtRejected` フラグが `true` であればトークンリクエストを拒否し、(b) 当フラグが `false` であれば入力トークンに対するバリデーション処理を終了する。 |

<Note>
  復号化用鍵を取得する標準的な方法が存在しないため、Authlete は暗号化された JWT のバリデーションをおこないません。これは、**あなた自身で暗号化された JWT のバリデーションを実施しなければならない**ということを意味します。
</Note>

<Note>
  JWT の署名を検証するための鍵を入手する標準的な方法が存在しないため、**Authlete は JWT の署名検証をおこないません**。これは、**あなた自身で JWT の署名を検証しなければならない**ということを意味します。
</Note>

## 設定

Authlete は、JWT 認可グラントに関連する設定項目を幾つか提供しています。認可サーバー実装者はこれらを活用してもよいですし、独自規則を実装してもかまいません。

### サービス設定

| 設定項目           |  型  | 説明                                                                                                                                                                                                                   |
| :------------- | :-: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 特定可能なクライアントのみ  | 真偽値 | 特定不能クライアントによるトークンリクエストを拒否するか否か - `Service.jwtGrantByIdentifiableClientsOnly` ([JavaDoc](https://authlete.github.io/authlete-java-common/com/authlete/common/dto/Service.html#isJwtGrantByIdentifiableClientsOnly--)) |
| 暗号化された JWT を拒否 | 真偽値 | 暗号化された JWT を認可グラントとして使うトークンリクエストを拒否するか否か - `Service.jwtGrantEncryptedJwtRejected` ([JavaDoc](https://authlete.github.io/authlete-java-common/com/authlete/common/dto/Service.html#isJwtGrantEncryptedJwtRejected--)) |
| 無署名の JWT を拒否   | 真偽値 | 無署名の JWT を認可グラントとして使うトークンリクエストを拒否するか否か - `Service.jwtGrantUnsignedJwtRejected` ([JavaDoc](https://authlete.github.io/authlete-java-common/com/authlete/common/dto/Service.html#isJwtGrantUnsignedJwtRejected--))     |

# 例

## 認可サーバー実装の例

Java で書かれたオープンソースの認可サーバー実装サンプルである **[java-oauth-server](https://github.com/authlete/java-oauth-server)** の [JwtAuthzGrantProcessor.java](https://github.com/authlete/java-oauth-server/blob/master/src/main/java/com/authlete/jaxrs/server/api/JwtAuthzGrantProcessor.java) が、JWT 認可グラントフローのトークンリクエスト処理の実装サンプルとなっています。

当実装は一例に過ぎず、商用利用可能な完璧さは意図していないのでご注意ください。

## リクエストとレスポンスの例

**1. 何らかの方法で JWT を用意する。**

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

**2. トークンリクエストを行う。**

```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. トークンレスポンスを受け取る。**

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