MicroProfile JSON Web Token (JWT) 認証


Red Hat build of Quarkus 3.20

Red Hat Customer Content Services

概要

このガイドでは、セキュアトークンの生成、ストレージ、および検証メカニズムに焦点を当て、JSON Web Token (JWT) セキュリティーの基本を説明します。また、アプリケーションアーキテクチャー内での JWT インテグレーションに触れ、トークンベースの認証システム用にセキュアなビルドおよびデプロイメントパイプラインを実装するための実践的な手順を提供します。

Red Hat build of Quarkus ドキュメントへのフィードバックの提供

エラーを報告したり、ドキュメントを改善したりするには、Red Hat Jira アカウントにログインし、課題を送信してください。Red Hat Jira アカウントをお持ちでない場合は、アカウントを作成するように求められます。

手順

  1. 次のリンクをクリックして チケットを作成します
  2. Summary に課題の簡単な説明を入力します。
  3. Description に課題や機能拡張の詳細な説明を入力します。問題があるドキュメントのセクションへの URL も記載してください。
  4. Submit をクリックすると、課題が作成され、適切なドキュメントチームに転送されます。

第1章 JWT RBAC の使用

このガイドでは、SmallRye JWT を Quarkus アプリケーションに統合して、MicroProfile JWT 仕様に準拠した JSON Web Token (JWT) セキュリティーを実装する方法を説明します。JWT を検証する方法、JWT を MicroProfile JWT org.eclipse.microprofile.jwt.JsonWebToken として表現する方法、ベアラートークン認可と ロールベースのアクセス制御 を使用して Quarkus HTTP エンドポイントを保護する方法を説明します。

注記

Quarkus OpenID Connect (quarkus-oidc) エクステンションはベアラートークン認可もサポートし、smallrye-jwt を使用してベアラートークンを JsonWebToken として表現します。詳細は、OIDC Bearer Token Authentication ガイドを参照してください。

Quarkus アプリケーションで OIDC Authorization Code Flow を使用してユーザーを認証する必要がある場合は、OpenID Connect エクステンションを使用する必要があります。詳細は、Web アプリケーションを保護するための OIDC Code Flow Mechanism を参照してください。

1.1. 前提条件

このガイドを完了するには、以下が必要です。

  • 約 15 分
  • IDE
  • JAVA_HOME が適切に設定された状態でインストールされた JDK 17 以降
  • Apache Maven 3.8.6 以降
  • オプション: Quarkus CLI (使用する場合)
  • オプション: ネイティブ実行可能ファイルをビルドする場合は、インストールおよび 適切に設定された Mandrel または GraalVM (ネイティブコンテナービルドを使用する場合は Docker)。

1.2. Quickstart

1.2.1. ソリューション

アプリケーションを段階的に作成するには、次のセクションの指示に従うことを推奨します。必要に応じて、完成した例に進むこともできます。

例を利用するには、Git リポジトリーをクローンするか、アーカイブをダウンロードします。

完成したソリューションは、security-jwt-quickstart ディレクトリー にあります。

1.2.2. Maven プロジェクトの作成

まず、以下のコマンドで新しいプロジェクトを作成します。

  • Quarkus CLI を使用する場合:

    quarkus create app org.acme:security-jwt-quickstart \
        --extension='rest-jackson,smallrye-jwt,smallrye-jwt-build' \
        --no-code
    cd security-jwt-quickstart

    Gradle プロジェクトを作成するには、--gradle オプションまたは --gradle-kotlin-dsl オプションを追加します。

    Quarkus CLI のインストール方法と使用方法の詳細は、Quarkus CLI ガイドを参照してください。

  • Maven を使用する場合:

    mvn com.redhat.quarkus.platform:quarkus-maven-plugin:3.20.1:create \
        -DprojectGroupId=org.acme \
        -DprojectArtifactId=security-jwt-quickstart \
        -Dextensions='rest-jackson,smallrye-jwt,smallrye-jwt-build' \
        -DnoCode
    cd security-jwt-quickstart

    Gradle プロジェクトを作成するには、-DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

Windows ユーザーの場合:

  • cmd を使用する場合は、バックスラッシュ \ を使用せず、すべてを同じ行に記述してください。
  • Powershell を使用する場合は、-D パラメーターを二重引用符で囲みます (例: "-DprojectArtifactId=security-jwt-quickstart")。

このコマンドは、Maven プロジェクトを生成し、MicroProfile JWT RBAC サポートを含む smallrye-jwt エクステンションをインポートします。

Quarkus プロジェクトがすでに設定されている場合は、プロジェクトベースディレクトリーで次のコマンドを実行して、smallrye-jwt エクステンションをプロジェクトに追加できます。

  • Quarkus CLI を使用する場合:

    quarkus extension add smallrye-jwt,smallrye-jwt-build
  • Maven を使用する場合:

    ./mvnw quarkus:add-extension -Dextensions='smallrye-jwt,smallrye-jwt-build'
  • Gradle を使用する場合:

    ./gradlew addExtension --extensions='smallrye-jwt,smallrye-jwt-build'

このコマンドは、ビルドファイルに以下の依存関係を追加します。

  • Maven を使用する場合:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-smallrye-jwt</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-smallrye-jwt-build</artifactId>
    </dependency>
  • Gradle を使用する場合:

    implementation("io.quarkus:quarkus-smallrye-jwt")
    implementation("io.quarkus:quarkus-smallrye-jwt-build")

1.2.3. Jakarta REST リソースの検証

以下の内容を含む src/main/java/org/acme/security/jwt/TokenSecuredResource.java に REST エンドポイントを作成します。

REST エンドポイント V1

package org.acme.security.jwt;

import jakarta.annotation.security.PermitAll;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.SecurityContext;

import org.eclipse.microprofile.jwt.JsonWebToken;

@Path("/secured")
public class TokenSecuredResource {

    @Inject
    JsonWebToken jwt; 
1


    @GET
    @Path("permit-all")
    @PermitAll 
2

    @Produces(MediaType.TEXT_PLAIN)
    public String hello(@Context SecurityContext ctx) {
        return getResponseString(ctx); 
3

    }

    private String getResponseString(SecurityContext ctx) {
        String name;
        if (ctx.getUserPrincipal() == null) { 
4

            name = "anonymous";
        } else if (!ctx.getUserPrincipal().getName().equals(jwt.getName())) { 
5

            throw new InternalServerErrorException("Principal and JsonWebToken names do not match");
        } else {
            name = ctx.getUserPrincipal().getName(); 
6

        }
        return String.format("hello %s,"
            + " isHttps: %s,"
            + " authScheme: %s,"
            + " hasJWT: %s",
            name, ctx.isSecure(), ctx.getAuthenticationScheme(), hasJwt()); 
7

    }

    private boolean hasJwt() {
        return jwt.getClaimNames() != null;
    }
}

1
JsonWebToken インターフェイスが注入され、現在の認証済みトークンに関連付けられたクレームへのアクセスが提供されます。このインターフェイスは java.security.Principal を拡張します。
2
@PermitAll は標準の Jakarta セキュリティーアノテーションです。これは、認証されているかどうかに関係なく、指定されたエンドポイントがすべての呼び出し元からアクセスできることを示します。
3
リクエストのセキュリティー状態を検査するために、Jakarta REST SecurityContext が注入されます。getResponseString() 関数は応答を生成します。
4
リクエストのユーザー/呼び出し元の Principal を null と照合して、呼び出しが安全でないかどうかを確認します。
5
JsonWebToken は現在の Principal を表すため、PrincipalJsonWebToken の名前が一致することを確認します。
6
Principal の名前を取得します。
7
呼び出し元の名前、リクエスト SecurityContextisSecure()getAuthenticationScheme() の状態、および null 以外の JsonWebToken が注入されたかどうかを含む応答をビルドします。

1.2.4. 開発モードでのアプリケーションの実行

これで、次のいずれかのコマンドを使用して、アプリケーションを開発モードで実行する準備が整いました。

  • Quarkus CLI を使用する場合:

    quarkus dev
  • Maven を使用する場合:

    ./mvnw quarkus:dev
  • Gradle を使用する場合:

    ./gradlew --console=plain quarkusDev

次に、以下の例のような出力が表示されるはずです。

quarkus:dev の出力

[INFO] Scanning for projects...
[INFO]
[INFO] ----------------------< org.acme:security-jwt-quickstart >-----------------------
[INFO] Building security-jwt-quickstart 1.0.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
...
Listening for transport dt_socket at address: 5005
2020-07-15 16:09:50,883 INFO  [io.quarkus] (Quarkus Main Thread) security-jwt-quickstart 1.0.0-SNAPSHOT on JVM (powered by Quarkus 999-SNAPSHOT) started in 1.073s. Listening on: http://0.0.0.0:8080
2020-07-15 16:09:50,885 INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2020-07-15 16:09:50,885 INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, mutiny, rest, rest-jackson, security, smallrye-context-propagation, smallrye-jwt, vertx, vertx-web]

REST エンドポイントが実行されているので、curl などのコマンドラインツールを使用してアクセスできます。

/secured/permit-allcurl コマンド

$ curl http://127.0.0.1:8080/secured/permit-all; echo

このコマンドは次の応答を返します。

hello anonymous, isHttps: false, authScheme: null, hasJWT: false

リクエストで JWT が提供されていないため、エンドポイントでセキュリティー状態が確認されることはなく、応答もそれと一致しています。

  • username は匿名です。
  • https が使用されていないため、isHttpsfalse です。
  • authSchemenull です。
  • hasJWTfalse です。

Ctrl-C を使用して Quarkus サーバーを停止します。

それでは、実際に何かを保護しましょう。以下の新しいエンドポイントメソッド helloRolesAllowed を確認してください。

REST エンドポイント V2

package org.acme.security.jwt;

import jakarta.annotation.security.PermitAll;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.SecurityContext;

import org.eclipse.microprofile.jwt.JsonWebToken;

@Path("/secured")
public class TokenSecuredResource {

    @Inject
    JsonWebToken jwt; 
1


    @GET
    @Path("permit-all")
    @PermitAll
    @Produces(MediaType.TEXT_PLAIN)
    public String hello(@Context SecurityContext ctx) {
        return getResponseString(ctx);
    }

    @GET
    @Path("roles-allowed") 
2

    @RolesAllowed({ "User", "Admin" }) 
3

    @Produces(MediaType.TEXT_PLAIN)
    public String helloRolesAllowed(@Context SecurityContext ctx) {
        return getResponseString(ctx) + ", birthdate: " + jwt.getClaim("birthdate").toString(); 
4

    }

    private String getResponseString(SecurityContext ctx) {
        String name;
        if (ctx.getUserPrincipal() == null) {
            name = "anonymous";
        } else if (!ctx.getUserPrincipal().getName().equals(jwt.getName())) {
            throw new InternalServerErrorException("Principal and JsonWebToken names do not match");
        } else {
            name = ctx.getUserPrincipal().getName();
        }
        return String.format("hello %s,"
            + " isHttps: %s,"
            + " authScheme: %s,"
            + " hasJWT: %s",
            name, ctx.isSecure(), ctx.getAuthenticationScheme(), hasJwt());
    }

    private boolean hasJwt() {
        return jwt.getClaimNames() != null;
    }
}

1
JWT からのクレームにアクセスするために、JsonWebToken が注入されます。
2
このエンドポイントは /secured/roles-allowed で公開されます。
3
@RolesAllowed アノテーションは、「ユーザー」または「管理者」のロールを持つユーザーへのアクセスを制限します。
4
レスポンスは hello メソッドと同様に構築されますが、注入された JsonWebToken から直接取得された birthdate クレームが追加されます。

TokenSecuredResource にこれを追加した後、./mvnw quarkus:dev コマンドを再実行し、curl -v http://127.0.0.1:8080/secured/roles-allowed; echo を実行して新しいエンドポイントへのアクセスを試みます。

出力は、以下のようになります。

/secured/roles-allowedcurl コマンド

$ curl -v http://127.0.0.1:8080/secured/roles-allowed; echo

このコマンドは次の応答を返します。

*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /secured/roles-allowed HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< Connection: keep-alive
< Content-Type: text/html;charset=UTF-8
< Content-Length: 14
< Date: Sun, 03 Mar 2019 16:32:34 GMT
<
* Connection #0 to host 127.0.0.1 left intact

Excellent.リクエストに JWT が指定されなかったため、エンドポイントへのアクセスが正しく拒否されました。代わりに、HTTP 401 Unauthorized エラーが発生しました。

エンドポイントにアクセスするには、有効な JWT を取得してリクエストに含める必要があります。これには 2 つのステップが含まれます。

  1. JWT を検証するために必要な情報を使用して SmallRye JWT エクステンションを設定します。
  2. 設定に一致する適切なクレームを含む JWT を生成する。

1.2.5. SmallRye JWT エクステンションのセキュリティー情報の設定

以下の内容で security-jwt-quickstart/src/main/resources/application.properties を作成します。

TokenSecuredResource のアプリケーションのプロパティー

mp.jwt.verify.publickey.location=publicKey.pem 
1

mp.jwt.verify.issuer=https://example.com/issuer 
2


quarkus.native.resources.includes=publicKey.pem 
3

1
クラスパス上の公開鍵ファイル publicKey.pem の場所を指定します。このキーを追加するには、公開鍵の追加 を参照してください。
2
予想される発行者を https://example.com/issuer として定義します。
3
publicKey.pem ファイルがネイティブ実行可能ファイルのリソースとして含まれていることを確認します。

1.2.6. 公開鍵の追加

JWT 仕様 では、使用できる JWT のさまざまなセキュリティーレベルが定義されています。MicroProfile JWT RBAC 仕様では、RSA-256 署名アルゴリズムで署名された JWT が必要です。これには、RSA 公開鍵ペアが必要です。REST エンドポイントサーバー側では、リクエストとともに送信された JWT の検証に使用する RSA 公開鍵のロケーションを設定する必要があります。以前に設定された mp.jwt.verify.publickey.location=publicKey.pem 設定は、公開鍵が publicKey.pem としてクラスパスで利用可能であることを想定しています。これを実行するには、以下の内容を security-jwt-quickstart/src/main/resources/publicKey.pem ファイルにコピーします。

RSA 公開鍵 PEM コンテンツ

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEq
Fyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwR
TYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5e
UF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9
AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYn
sIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9x
nQIDAQAB
-----END PUBLIC KEY-----

1.2.7. JWT の生成

多くの場合、Keycloak などのアイデンティティーマネージャーから JWT を取得します。ただし、このクイックスタートでは、smallrye-jwt によって提供される JWT 生成 API を使用して独自の JWT を生成します。詳細は、SmallRye JWT を使用した JWT トークンの生成 を参照してください。

次のリストからコードを取得し、security-jwt-quickstart/src/test/java/org/acme/security/jwt/GenerateToken.java に配置します。

GenerateToken メインドライバークラス

package org.acme.security.jwt;

import java.util.Arrays;
import java.util.HashSet;

import org.eclipse.microprofile.jwt.Claims;
import io.smallrye.jwt.build.Jwt;

/**
 * A utility class to generate and print a JWT token string to stdout.
 */
public class GenerateToken {

    /**
     * Generates and prints a JWT token.
     */
    public static void main(String[] args) {
        String token = Jwt.issuer("https://example.com/issuer") 
1

                .upn("jdoe@quarkus.io") 
2

                .groups(new HashSet<>(Arrays.asList("User", "Admin"))) 
3

                .claim(Claims.birthdate.name(), "2001-07-13") 
4

                .sign();

        System.out.println(token);
        System.exit(0);
    }
}

1
JWT に iss (発行者) クレームを設定します。トークンが有効と見なされるためには、この値がサーバー側の mp.jwt.verify.issuer 設定と一致する必要があります。
2
upn (ユーザープリンシパル名) クレームを指定します。これは、MicroProfile JWT RBAC 仕様では、コンテナーセキュリティー API で Principal を識別するための推奨クレームとして定義されています。
3
JWT ベアラーに割り当てられたグループメンバーシップと最上位レベルのロールを提供する groups クレームを定義します。
4
birthdate クレームを追加します。これは機密情報とみなされる可能性があるため、SmallRye JWT を使用した JWT トークンの生成 の説明に従って、クレームを暗号化することを検討してください。

このコードが機能するには、TokenSecuredResource アプリケーションにある公開鍵に対応する RSA 秘密鍵の内容が必要であることに注意してください。以下の PEM コンテンツを取得し、security-jwt-quickstart/src/test/resources/privateKey.pem に配置します。

RSA 秘密鍵 PEM コンテンツ

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCWK8UjyoHgPTLa
PLQJ8SoXLLjpHSjtLxMqmzHnFscqhTVVaDpCRCb6e3Ii/WniQTWw8RA7vf4djz4H
OzvlfBFNgvUGZHXDwnmGaNVaNzpHYFMEYBhE8VGGiveSkzqeLZI+Y02G6sQAfDtN
qqzM/l5QX8X34oQFaTBW1r49nftvCpITiwJvWyhkWtXP9RP8sXi1im5Vi3dhupOh
nelk5n0BfajUYIbfHA6ORzjHRbt7NtBl0L2J+0/FUdHyKs6KMlFGNw8O0Dq88qnM
uXoLJiewhg9332W3DFMeOveel+//cvDnRsCRtPgd4sXFPHh+UShkso7+DRsChXa6
oGGQD3GdAgMBAAECggEAAjfTSZwMHwvIXIDZB+yP+pemg4ryt84iMlbofclQV8hv
6TsI4UGwcbKxFOM5VSYxbNOisb80qasb929gixsyBjsQ8284bhPJR7r0q8h1C+jY
URA6S4pk8d/LmFakXwG9Tz6YPo3pJziuh48lzkFTk0xW2Dp4SLwtAptZY/+ZXyJ6
96QXDrZKSSM99Jh9s7a0ST66WoxSS0UC51ak+Keb0KJ1jz4bIJ2C3r4rYlSu4hHB
Y73GfkWORtQuyUDa9yDOem0/z0nr6pp+pBSXPLHADsqvZiIhxD/O0Xk5I6/zVHB3
zuoQqLERk0WvA8FXz2o8AYwcQRY2g30eX9kU4uDQAQKBgQDmf7KGImUGitsEPepF
KH5yLWYWqghHx6wfV+fdbBxoqn9WlwcQ7JbynIiVx8MX8/1lLCCe8v41ypu/eLtP
iY1ev2IKdrUStvYRSsFigRkuPHUo1ajsGHQd+ucTDf58mn7kRLW1JGMeGxo/t32B
m96Af6AiPWPEJuVfgGV0iwg+HQKBgQCmyPzL9M2rhYZn1AozRUguvlpmJHU2DpqS
34Q+7x2Ghf7MgBUhqE0t3FAOxEC7IYBwHmeYOvFR8ZkVRKNF4gbnF9RtLdz0DMEG
5qsMnvJUSQbNB1yVjUCnDAtElqiFRlQ/k0LgYkjKDY7LfciZl9uJRl0OSYeX/qG2
tRW09tOpgQKBgBSGkpM3RN/MRayfBtmZvYjVWh3yjkI2GbHA1jj1g6IebLB9SnfL
WbXJErCj1U+wvoPf5hfBc7m+jRgD3Eo86YXibQyZfY5pFIh9q7Ll5CQl5hj4zc4Y
b16sFR+xQ1Q9Pcd+BuBWmSz5JOE/qcF869dthgkGhnfVLt/OQzqZluZRAoGAXQ09
nT0TkmKIvlza5Af/YbTqEpq8mlBDhTYXPlWCD4+qvMWpBII1rSSBtftgcgca9XLB
MXmRMbqtQeRtg4u7dishZVh1MeP7vbHsNLppUQT9Ol6lFPsd2xUpJDc6BkFat62d
Xjr3iWNPC9E9nhPPdCNBv7reX7q81obpeXFMXgECgYEAmk2Qlus3OV0tfoNRqNpe
Mb0teduf2+h3xaI1XDIzPVtZF35ELY/RkAHlmWRT4PCdR0zXDidE67L6XdJyecSt
FdOUH8z5qUraVVebRFvJqf/oGsXc4+ex1ZKUTbY0wqY1y9E39yvB3MaTmZFuuqk8
f3cg+fr8aou7pr9SHhJlZCU=
-----END PRIVATE KEY-----

後で、smallrye.jwt.sign.key.location プロパティーを設定して、秘密署名鍵の場所を指定します。

OpenSSL でのキーの生成

OpenSSL コマンドラインツールを使用して公開鍵と秘密鍵のペアを生成することもできます。

キーを生成するための openssl コマンド

openssl genrsa -out rsaPrivateKey.pem 2048
openssl rsa -pubout -in rsaPrivateKey.pem -out publicKey.pem

秘密鍵を生成し、安全なキーの保管と転送に一般的に使用される PKCS#8 形式に変換するには、追加の手順が必要です。

変換用の openssl コマンド

openssl pkcs8 -topk8 -nocrypt -inform pem -in rsaPrivateKey.pem -outform pem -out privateKey.pem

このクイックスタートで使用されているキーペアの代わりに、生成されたキーペアを使用できます。

TokenSecuredResource エンドポイントの JSON Web Token (JWT) を生成する前に、アプリケーションが実行されていること を確認してください。

次に、次のコマンドを使用して JWT を生成します。

JWT 生成の出力例

$ mvn exec:java -Dexec.mainClass=org.acme.security.jwt.GenerateToken -Dexec.classpathScope=test -Dsmallrye.jwt.sign.key.location=privateKey.pem

JWT 文字列は、. 文字で区切られた 3 つの部分が含まれる Base64 URL エンコードされた文字列です。

  1. 署名アルゴリズムなどのトークンに関するメタデータが含まれるヘッダー。
  2. トークンのクレームまたはデータを含むペイロード (「クレーム」とも呼ばれる)
  3. トークンの整合性を検証する署名。

1.2.8. /secured/roles-allowed へのセキュアなアクセス

次に、これを使用して、/secured/roles-allowed エンドポイントに対してセキュアなリクエストを行います。Quarkus サーバーが引き続き dev モードで実行されていることを確認してから以下のコマンドを実行し、前のステップで生成された JWT のバージョンを使用するようにしてください。

JWT を使用した /secured/roles-allowedcurl コマンド

$ curl -H "Authorization: Bearer eyJraWQ..." http://127.0.0.1:8080/secured/roles-allowed; echo

生成されたトークンを HTTP Authorization Bearer スキームの値として必ず使用してください。

このコマンドは次の応答を返します。

hello jdoe@quarkus.io, isHttps: false, authScheme: Bearer, hasJWT: true, birthdate: 2001-07-13

正常に完了しました。現在、以下の状態になっています。

  • 匿名でない呼び出し元名: jdoe@quarkus.io
  • 認証スキーム: Bearer
  • null 以外の JsonWebToken
  • birthdate クレーム値

1.2.9. JsonWebToken およびクレーム注入の使用

これで、セキュアな REST エンドポイントにアクセスするための JWT を生成できるようになったので、JsonWebToken インターフェイスおよび JWT クレームでさらに何ができるかを確認します。org.eclipse.microprofile.jwt.JsonWebToken インターフェイスは java.security.Principal インターフェイスを拡張し、以前に使用した jakarta.ws.rs.core.SecurityContext#getUserPrincipal() 呼び出しによって返されるオブジェクトタイプです。これは、CDI を使用せずとも、REST コンテナー SecurityContext にアクセスできるコードは、SecurityContext#getUserPrincipal() をキャストすることで、呼び出し元の JsonWebToken インターフェイスを取得できることを意味します。

JsonWebToken インターフェイスは、基礎となる JWT のクレームにアクセスするためのメソッドを定義します。これは、MicroProfile JWT RBAC 仕様に必要な一般的なクレームのアクセサーと、JWT に存在する可能性のある任意のクレームのアクセサーを提供します。

すべての JWT クレームも注入できます。TokenSecuredResource を、(JsonWebToken から取得するのではなく) 注入した birthdate クレームを使用する別のエンドポイント /secured/roles-allowed-admin で拡張します。

package org.acme.security.jwt;

import jakarta.annotation.security.PermitAll;
import jakarta.annotation.security.RolesAllowed;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.SecurityContext;

import org.eclipse.microprofile.jwt.Claim;
import org.eclipse.microprofile.jwt.Claims;
import org.eclipse.microprofile.jwt.JsonWebToken;

@Path("/secured")
@RequestScoped 
1

public class TokenSecuredResource {

    @Inject
    JsonWebToken jwt; 
2

    @Inject
    @Claim(standard = Claims.birthdate)
    String birthdate; 
3


    @GET
    @Path("permit-all")
    @PermitAll
    @Produces(MediaType.TEXT_PLAIN)
    public String hello(@Context SecurityContext ctx) {
        return getResponseString(ctx);
    }

    @GET
    @Path("roles-allowed")
    @RolesAllowed({ "User", "Admin" })
    @Produces(MediaType.TEXT_PLAIN)
    public String helloRolesAllowed(@Context SecurityContext ctx) {
        return getResponseString(ctx) + ", birthdate: " + jwt.getClaim("birthdate").toString();
    }

    @GET
    @Path("roles-allowed-admin")
    @RolesAllowed("Admin")
    @Produces(MediaType.TEXT_PLAIN)
    public String helloRolesAllowedAdmin(@Context SecurityContext ctx) {
        return getResponseString(ctx) + ", birthdate: " + birthdate; 
4

    }

    private String getResponseString(SecurityContext ctx) {
        String name;
        if (ctx.getUserPrincipal() == null) {
            name = "anonymous";
        } else if (!ctx.getUserPrincipal().getName().equals(jwt.getName())) {
            throw new InternalServerErrorException("Principal and JsonWebToken names do not match");
        } else {
            name = ctx.getUserPrincipal().getName();
        }
        return String.format("hello %s,"
            + " isHttps: %s,"
            + " authScheme: %s,"
            + " hasJWT: %s",
            name, ctx.isSecure(), ctx.getAuthenticationScheme(), hasJwt());
    }

    private boolean hasJwt() {
        return jwt.getClaimNames() != null;
    }
}
1
birthdate クレームを String として注入できるようにするには、@RequestScoped スコープが必要です。
2
ここで JsonWebToken が注入され、すべてのクレームと JWT 関連情報へのアクセスが提供されます。
3
birthdate クレームは String として注入されます。これは、@RequestScoped スコープが必須である理由を強調しています。
4
注入された birthdate クレームは、応答を構築するために直接使用されます。

トークンを再度生成し、実行します。

$ curl -H "Authorization: Bearer eyJraWQ..." http://127.0.0.1:8080/secured/roles-allowed-admin; echo

生成されたトークンを HTTP Authorization Bearer スキームの値として必ず使用してください。

このコマンドは次の応答を返します。

hello jdoe@quarkus.io, isHttps: false, authScheme: Bearer, hasJWT: true, birthdate: 2001-07-13

1.2.10. JVM モードでアプリケーションを実行する

アプリケーションを標準の Java アプリケーションとして実行できます。

  1. アプリケーションをコンパイルします。

    • Quarkus CLI を使用する場合:

      quarkus build
    • Maven を使用する場合:

      ./mvnw install
    • Gradle を使用する場合:

      ./gradlew build
  2. アプリケーションを実行します。

    java -jar target/quarkus-app/quarkus-run.jar

1.2.11. ネイティブモードでのアプリケーションの実行

この同じデモを、変更せずにネイティブモードにコンパイルできます。つまり、実稼働環境に JVM をインストールする必要がなくなります。ランタイムテクノロジーは生成されたバイナリーに組み込まれ、最小限のリソースで実行できるように最適化されています。

コンパイルには少し時間がかかるため、この手順はデフォルトで無効になっています。

  1. native プロファイルを有効にしてアプリケーションを再度ビルドします。

    • Quarkus CLI を使用する場合:

      quarkus build --native
    • Maven を使用する場合:

      ./mvnw install -Dnative
    • Gradle を使用する場合:

      ./gradlew build -Dquarkus.native.enabled=true
  2. 次のバイナリーを直接実行します。

    ./target/security-jwt-quickstart-1.0.0-SNAPSHOT-runner

1.2.12. ソリューションの探索

security-jwt-quickstart ディレクトリー リポジトリーには、このクイックスタートガイドで扱うすべてのバージョンが含まれており、さらに CDI API を介して注入された JsonWebToken トークンとそのクレームを使用し、サブリソースの動作を実演する追加のエンドポイントも含まれています。

security-jwt-quickstart ディレクトリーでクイックスタートソリューションを確認し、SmallRye JWT エクステンションの機能に関する情報を確認することを推奨します。

1.3. リファレンスガイド

1.3.1. サポートされている注入スコープ

@ApplicationScoped@Singleton、および @RequestScoped outer Bean インジェクションスコープは、org.eclipse.microprofile.jwt.JsonWebToken を注入するとすべてサポートされ、現在のトークンが表されるように JsonWebToken 用の @RequestScoped スコープが適用されます。

ただし、個々のトークンクレームが String などの単純型として注入される場合は、@RequestScoped を使用する必要があります。以下に例を示します。

package org.acme.security.jwt;

import jakarta.inject.Inject;
import org.eclipse.microprofile.jwt.Claim;
import org.eclipse.microprofile.jwt.Claims;

@Path("/secured")
@RequestScoped
public class TokenSecuredResource {

    @Inject
    @Claim(standard = Claims.birthdate)
    String birthdate;
}

注入された JsonWebToken を使用して個々のクレームにアクセスすることもできますが、この場合は @RequestScoped を設定する必要はありません。

詳細は、MP JWT CDI Injection Requirements を参照してください。

1.3.2. サポートされている公開鍵形式

公開鍵は、優先順位に従って、次のいずれかの形式でフォーマットできます。

  • Public Key Cryptography Standards #8 (PKCS#8) PEM
  • JSON Web Key (JWK)
  • JSON Web Key Set (JWKS)
  • JSON Web Key (JWK) (Base64 URL エンコード)
  • JSON Web Key Set (JWKS) (Base64 URL エンコード)

1.3.3. 検証鍵の扱い

非対称 RSA または楕円曲線 (EC) 鍵を使用してトークンの署名を検証する必要がある場合は、mp.jwt.verify.publickey.location プロパティーを使用してローカルまたはリモートの検証鍵を参照します。

たとえば、EC 鍵を使用する場合は ES256 に設定し、mp.jwt.verify.publickey.algorithm を使用して検証アルゴリズム (デフォルトは RS256) をカスタマイズします。

対称シークレットキーを使用してトークン署名を検証する必要がある場合は、JSON Web Key (JWK) または JSON Web Key Set (JWK セット) 形式のいずれかを使用して、このシークレットキーを表す必要があります。以下はその例です。

{
 "keys": [
   {
     "kty":"oct",
     "kid":"secretKey",
     "k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
   }
 ]
}

このシークレットキー JWK は、smallrye.jwt.verify.key.location でも参照する必要があります。smallrye.jwt.verify.algorithm は、HS256/HS384/HS512 に設定する必要があります。

1.3.4. JWTParser を使用した JsonWebToken の解析および検証

JWT トークンを注入できない場合 (たとえば、サービスリクエストのペイロードに埋め込まれている場合や、サービスエンドポイントが外部手段でそれを取得する場合)、JWTParser を使用できます。

import org.eclipse.microprofile.jwt.JsonWebToken;
import io.smallrye.jwt.auth.principal.JWTParser;
...
@Inject JWTParser parser;

String token = getTokenFromOidcServer();

// Parse and verify the token
JsonWebToken jwt = parser.parse(token);

また、これを使用して、トークンの検証または復号化の方法をカスタマイズすることもできます。たとえば、ローカルの SecretKey を指定できます。

package org.acme.security.jwt;

import io.smallrye.jwt.auth.principal.ParseException;
import jakarta.inject.Inject;
import jakarta.ws.rs.CookieParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.NewCookie;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.jwt.JsonWebToken;
import io.smallrye.jwt.auth.principal.JWTParser;
import io.smallrye.jwt.build.Jwt;

@Path("/secured")
public class SecuredResource {
    private static final String SECRET = "AyM1SysPpbyDfgZld3umj1qzKObwVMko";

    @Inject
    JWTParser parser;

    @GET
    @Produces("text/plain")
    public Response getUserName(@CookieParam("jwt") String jwtCookie) throws ParseException {
        if (jwtCookie == null) {
            // Create a JWT token signed by using the 'HS256' algorithm
            String newJwtCookie = Jwt.upn("Alice").signWithSecret(SECRET);
            // or create a JWT token encrypted by using the 'A256KW' algorithm
            // Jwt.upn("alice").encryptWithSecret(secret);
            return Response.ok("Alice").cookie(new NewCookie("jwt", newJwtCookie)).build();
        } else {
            // All mp.jwt and smallrye.jwt properties are still effective; only the verification key is customized.
            JsonWebToken jwt = parser.verify(jwtCookie, SECRET);
            // or jwt = parser.decrypt(jwtCookie, secret);
            return Response.ok(jwt.getName()).build();
        }
    }
}

quarkus-smallrye-jwt が提供する HTTP サポートなしで JWTParser を使用する方法に関する SmallRye JWT を直接追加する方法 のセクションを参照してください。

1.3.5. トークン復号化

アプリケーションが暗号化されたクレームまたは暗号化された内部署名付きクレームを含むトークンを受け入れる必要がある場合は、復号化キーを指すように smallrye.jwt.decrypt.key.location プロパティーを設定するだけです。

これが唯一のキープロパティーセットである場合、受信トークンには暗号化されたクレームのみが含まれることが予想されます。mp.jwt.verify.publickey または mp.jwt.verify.publickey.location 検証プロパティーのいずれかも設定されている場合、受信トークンには暗号化された内部署名トークンが含まれることが想定されます。

SmallRye JWT を使用した JWT トークンの生成 を参照し、暗号化トークンや内部署名後に暗号化されたトークンを迅速に生成する方法を確認します。

1.3.6. カスタムファクトリー

io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipalFactory は、JWT トークンを解析および検証し、JsonWebToken プリンシパルに変換するために使用されるデフォルトの実装です。このファクトリーは、Configuration セクションで説明されているように、MP JWTsmallrye-jwt プロパティーに依存して、JWT トークンを検証およびカスタマイズします。

ファイアウォールによってすでに検証されているトークンの再検証をスキップするなど、カスタムファクトリーを実装する必要がある場合は、次のいずれかの方法で実装できます。

  • META-INF/services/io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory リソースを作成して、ServiceLoader メカニズムを使用します。
  • 以下の例のように、Alternative CDI Bean 実装を提供します。
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import jakarta.annotation.Priority;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Alternative;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.InvalidJwtException;
import io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipal;
import io.smallrye.jwt.auth.principal.JWTAuthContextInfo;
import io.smallrye.jwt.auth.principal.JWTCallerPrincipal;
import io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory;
import io.smallrye.jwt.auth.principal.ParseException;

@ApplicationScoped
@Alternative
@Priority(1)
public class TestJWTCallerPrincipalFactory extends JWTCallerPrincipalFactory {

    @Override
    public JWTCallerPrincipal parse(String token, JWTAuthContextInfo authContextInfo) throws ParseException {
        try {
            // Token has already been verified; parse the token claims only
            String json = new String(Base64.getUrlDecoder().decode(token.split("\\.")[1]), StandardCharsets.UTF_8);
            return new DefaultJWTCallerPrincipal(JwtClaims.parse(json));
        } catch (InvalidJwtException ex) {
            throw new ParseException(ex.getMessage());
        }
    }
}

1.3.7. 呼び出しのブロック

quarkus-smallrye-jwt エクステンションは、現在リアクティブでない SmallRye JWT ライブラリーを使用します。

これは、quarkus-smallrye-jwt がリアクティブ Quarkus セキュリティーアーキテクチャーの一部として動作する観点から見ると、SmallRye JWT の検証または復号化コードに入る IO スレッドが、以下のいずれかの場合にブロックする可能性があることを意味します。

  • デフォルトのキーリゾルバーが、OIDC エンドポイントへのリモートコールを伴うキーを含む JsonWebKey セットを更新します
  • AWS Application Load Balancer (ALB) キーリゾルバーなどのカスタムキーリゾルバーは、現在のトークンのキー識別子ヘッダー値を使用して、AWS ALB キーエンドポイントに対してキーを解決します。

このような場合、接続が遅い場合 (たとえば、キーエンドポイントへの応答に 3 秒以上かかる場合)、現在のイベントループスレッドがブロックされる可能性があります。

ブロックされないようにするには、quarkus.smallrye-jwt.blocking-authentication=true を設定します。

1.3.8. トークンの伝播

ダウンストリームサービスへの Bearer アクセストークンの伝播は、トークン伝播 セクションを参照してください。

1.3.9. テスト

1.3.9.1. Wiremock

mp.jwt.verify.publickey.location を HTTPS または HTTP ベースの JsonWebKey (JWK) セットを指すように設定した場合は、OpenID Connect Bearer Token インテグレーションテストWiremock セクションで説明されているものと同じアプローチを使用できます。ただし、MP JWT 設定プロパティーを代わりに使用するように application.properties のみを変更します。

# keycloak.url is set by OidcWiremockTestResource
mp.jwt.verify.publickey.location=${keycloak.url}/realms/quarkus/protocol/openid-connect/certs
mp.jwt.verify.issuer=${keycloak.url}/realms/quarkus
1.3.9.2. Keycloak

Keycloak を使用し、mp.jwt.verify.publickey.location を HTTPS または HTTP ベースの JsonWebKey (JWK) セットを指すように設定した場合は、OpenID Connect Bearer Token インテグレーションテスト の Keycloak セクションで説明されているものと同じアプローチを使用できます。ただし、MP JWT 設定プロパティーを代わりに使用するように application.properties のみを変更します。

# keycloak.url is set by DevServices for Keycloak
mp.jwt.verify.publickey.location=${keycloak.url}/realms/quarkus/protocol/openid-connect/certs
mp.jwt.verify.issuer=${keycloak.url}/realms/quarkus

Keycloak によって発行されたトークンには、iss (issuer) クレームがレルムエンドポイントアドレスに設定されていることに注意してください。

Quarkus アプリケーションが Docker コンテナー内で実行される場合、DevServices for Keycloak によって起動された Keycloak コンテナーとネットワークインターフェイスを共有する可能性があります。このシナリオでは、Quarkus アプリケーションと Keycloak は内部の共有 Docker ネットワークを介して通信します。

このような場合は、代わりに以下の設定を使用してください。

# keycloak.url is set by DevServices for Keycloak,
# Quarkus accesses it through an internal shared docker network interface.
mp.jwt.verify.publickey.location=${keycloak.url}/realms/quarkus/protocol/openid-connect/certs

# Issuer is set to the docker bridge localhost endpoint address represented by the `client.quarkus.oidc.auth-server-url` property
mp.jwt.verify.issuer=${client.quarkus.oidc.auth-server-url}
1.3.9.3. ローカル公開鍵

OpenID Connect Bearer Token インテグレーションテストLocal public key セクションで説明されているものと同じ方法を使用できますが、MP JWT 設定プロパティーを代わりに使用するよう application.properties のみを変更します。

mp.jwt.verify.publickey=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEqFyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwRTYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5eUF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYnsIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9xnQIDAQAB
# set it to the issuer value which is used to generate the tokens
mp.jwt.verify.issuer=${keycloak.url}/realms/quarkus

# required to sign the tokens
smallrye.jwt.sign.key.location=privateKey.pem
1.3.9.4. TestSecurity アノテーション

次の依存関係を追加します。

  • Maven を使用する場合:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-test-security-jwt</artifactId>
        <scope>test</scope>
    </dependency>
  • Gradle を使用する場合:

    testImplementation("io.quarkus:quarkus-test-security-jwt")

次に、以下のようなテストコードを記述します。

import static org.hamcrest.Matchers.is;
import org.junit.jupiter.api.Test;
import io.quarkus.test.common.http.TestHTTPEndpoint;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.quarkus.test.security.jwt.Claim;
import io.quarkus.test.security.jwt.JwtSecurity;
import io.restassured.RestAssured;

@QuarkusTest
@TestHTTPEndpoint(ProtectedResource.class)
public class TestSecurityAuthTest {

    @Test
    @TestSecurity(user = "userJwt", roles = "viewer")
    public void testJwt() {
        RestAssured.when().get("test-security-jwt").then()
                .body(is("userJwt:viewer"));
    }

    @Test
    @TestSecurity(user = "userJwt", roles = "viewer")
    @JwtSecurity(claims = {
            @Claim(key = "email", value = "user@gmail.com")
    })
    public void testJwtWithClaims() {
        RestAssured.when().get("test-security-jwt-claims").then()
                .body(is("userJwt:viewer:user@gmail.com"));
    }

}

ここで、ProtectedResource クラスは次のようになります。

@Path("/web-app")
@Authenticated
public class ProtectedResource {

    @Inject
    JsonWebToken accessToken;

    @GET
    @Path("test-security-jwt")
    public String testSecurityOidc() {
        return accessToken.getName() + ":" + accessToken.getGroups().iterator().next();
    }

    @GET
    @Path("test-security-jwt-claims")
    public String testSecurityOidcUserInfoMetadata() {
        return accessToken.getName() + ":" + accessToken.getGroups().iterator().next()
                + ":" + accessToken.getClaim("email");
    }
}

@TestSecurity アノテーションを常に使用する必要があり、その user プロパティーは JsonWebToken.getName() として返され、roles プロパティーは JsonWebToken.getGroups() として返される点に注意してください。@JwtSecurity アノテーションは任意で、追加のトークンクレームの設定に使用可能です。

ヒント

@TestSecurity@JwtSecurity は、以下のようにメタアノテーションに統合できます。

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.METHOD })
    @TestSecurity(user = "userOidc", roles = "viewer")
    @OidcSecurity(introspectionRequired = true,
        introspection = {
            @TokenIntrospection(key = "email", value = "user@gmail.com")
        }
    )
    public @interface TestSecurityMetaAnnotation {

    }

これは、同じセキュリティー設定のセットを複数のテスト方法で使用する必要がある場合に特に便利です。

1.3.10. ログ内のエラーを確認する方法

トークンの検証または復号化エラーの詳細は、io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator TRACE レベルのロギングを有効にして確認してください。

quarkus.log.category."io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator".level=TRACE
quarkus.log.category."io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator".min-level=TRACE

1.3.11. プロアクティブ認証

パブリックエンドポイントメソッドが呼び出されたときにトークンの検証をスキップする場合は、プロアクティブ認証 を無効にします。

トークンの検証が行われていない場合、注入された JsonWebToken にパブリックメソッドを通じてアクセスできないことに注意してください。

1.3.12. SmallRye JWT を直接追加する方法

JWTParser で JsonWebToken を解析および検証 するには、以下の状況で quarkus-smallrye-jwt の代わりに smallrye-jwt を直接使用します。

  • Quarkus GRPC などの HTTP をサポートしない Quarkus エクステンションを使用している。
  • エクステンション固有の HTTP を指定し、そのサポートは Quarkus AWS Lambda などの quarkus-smallrye-jwt および Vert.x HTTP によって提供されるサポートと競合する。

smallrye-jwt 依存関係の追加から開始します。

  • Maven を使用する場合:

    <dependency>
        <groupId>io.smallrye</groupId>
        <artifactId>smallrye-jwt</artifactId>
    </dependency>
  • Gradle を使用する場合:

    implementation("io.smallrye:smallrye-jwt")

さらに、application.properties を更新して、smallrye-jwt によって提供されるすべての CDI プロデューサーを次のように含めます。

quarkus.index-dependency.smallrye-jwt.group-id=io.smallrye
quarkus.index-dependency.smallrye-jwt.artifact-id=smallrye-jwt

1.4. 設定の参照

1.4.1. Quarkus の設定

🔒 ビルド時に固定: 設定プロパティーはビルド時に固定されます。他のすべての設定プロパティーは実行時にオーバーライドできます。

Expand

設定プロパティー

デフォルト

🔒 ビルド時に修正 quarkus.smallrye-jwt.enabled

MP-JWT 設定オブジェクト

環境変数: QUARKUS_SMALLRYE_JWT_ENABLED

boolean

true

🔒 ビルド時に修正 quarkus.smallrye-jwt.rsa-sig-provider

SHA256withRSA 署名をサポートする java.security.Provider の名前

環境変数: QUARKUS_SMALLRYE_JWT_RSA_SIG_PROVIDER

string

SunRsaSign

quarkus.smallrye-jwt.blocking-authentication

リモート鍵の取得が時間のかかる操作になる可能性がある場合は、このプロパティーを有効化します。ローカル鍵を使用する場合は有効化しないでください。

環境変数: QUARKUS_SMALLRYE_JWT_BLOCKING_AUTHENTICATION

boolean

false

quarkus.smallrye-jwt.silent

認証用の認証情報を含まないリクエストであっても、常に HTTP 401 チャレンジを作成します。JWT 認証メカニズムは、認証チャレンジが必要な場合に HTTP 401 を返します。ただし、インタラクティブな認証メカニズムのいずれかと一緒に使用される場合は、ブラウザーからアプリケーションにアクセスするユーザーに HTTP 401 を返す必要がない場合があります。必要な場合は、このプロパティーを 'true' に設定することで、JWT 認証メカニズムがこのような場合に課題を作成しないことをリクエストできます。

環境変数: QUARKUS_SMALLRYE_JWT_SILENT

boolean

false

1.4.2. MicroProfile JWT 設定

Expand
プロパティー名デフォルト説明

mp.jwt.verify.publickey

none

mp.jwt.verify.publickey 設定プロパティーにより、公開鍵テキストを文字列として指定できます。公開鍵は、サポート対象の公開鍵形式 セクションで定義された順序で、提供された文字列から解析されます。

mp.jwt.verify.publickey.location

none

設定プロパティーを使用すると、公開鍵の外部または内部の場所を指定できます。値は相対パスまたは URL にすることができます。値が HTTPS ベースの JWK セットを指している場合、ネイティブモードで動作させるには、quarkus.ssl.native プロパティーも true に設定する必要があります。詳細は、Using SSL With Native Executables を参照してください。

mp.jwt.verify.publickey.algorithm

RS256

署名アルゴリズムのリスト。Elliptic Curve 署名アルゴリズムをサポートするには、ES256 に設定します。

mp.jwt.decrypt.key.location

none

Config プロパティーを使用すると、秘密復号化キーの外部または内部の場所を指定できます。

mp.jwt.decrypt.key.algorithm

RSA-OAEP,RSA-OAEP-256

復号化アルゴリズムのリスト。SHA-256 のみの RSA-OAEP をサポートするには、RSA-OAEP-256 に設定します。

mp.jwt.verify.issuer

none

Config プロパティーは、サーバーが有効として受け入れる JWT の iss (発行者) クレームの値を指定します。

mp.jwt.verify.audiences

none

トークン aud クレームに含まれる可能性のあるオーディエンスのコンマ区切りリスト。

mp.jwt.verify.clock.skew

60

トークンの有効期限と経過時間の検証中に使用されるクロックスキュー (秒単位)。現在の時間が、トークンの有効期限後にこのプロパティーで指定された秒数内にある場合、期限切れのトークンが受け入れられます。デフォルト値は、60 秒です。

mp.jwt.verify.token.age

none

トークンの iat (issued at) 時間以降に経過してはならない秒数。

mp.jwt.token.header

Authorization

Cookie などの別のヘッダーがトークンを渡すために使用される場合は、このプロパティーを設定します。

mp.jwt.token.cookie

none

トークンが含まれるクッキーの名前。このプロパティーは、mp.jwt.token.headerCookie に設定されている場合にのみ有効です。

1.4.3. 追加の SmallRye JWT 設定

SmallRye JWT は、トークン処理のカスタマイズに使用できるプロパティーを他にも提供します。

Expand
プロパティー名デフォルト説明

smallrye.jwt.verify.secretkey

none

シークレットキーは文字列として提供されます。

smallrye.jwt.verify.key.location

NONE

公開鍵とシークレット鍵の両方を指すことができる検証鍵のロケーション。シークレット鍵は JWK 形式のみです。このプロパティーが設定されている場合、'mp.jwt.verify.publickey.location' は無視されることに注意してください。

smallrye.jwt.verify.algorithm

 

署名アルゴリズム。このプロパティーは、HS256 などの対称アルゴリズムを設定する場合にのみ使用してください。これは、ES256 などの非対称アルゴリズムを設定する場合には非推奨となっています。代わりに 'mp.jwt.verify.publickey.algorithm' を使用してください。

smallrye.jwt.verify.key-format

ANY

このプロパティーを PEM_KEYPEM_CERTIFICATEJWK、または JWK_BASE64URL などの特定の鍵形式に設定し、検証鍵のロード方法を最適化します。

smallrye.jwt.verify.key-provider

DEFAULT

デフォルトでは、PEM、JWK、または JWK 鍵セットはローカルファイルシステムから読み取るか、MicroProfile JWT 仕様で必要に応じて URI から取得できます。AWS アプリケーションロードバランサー検証鍵の解決をサポートするには、このプロパティーを AWS_ALB に設定します。

smallrye.jwt.verify.relax-key-validation

false

検証キーの検証を緩和します。このプロパティーを true に設定すると、長さが 2048 ビット未満である公開 RSA 鍵が許可されます。

smallrye.jwt.verify.certificate-thumbprint

false

このプロパティーが有効な場合、署名済みトークンには 'x5t' または 'x5t#S256' X509Certificate サムプリントヘッダーのいずれかが含まれている必要があります。検証鍵として使用できる鍵形式は、JWK または PEM 証明書のみです。JWK 鍵には、'x5c' (Base64 でエンコードされた X509Certificate) プロパティーが設定されている必要があります。

smallrye.jwt.token.header

Authorization

Cookie などの別のヘッダーがトークンを渡すために使用される場合は、このプロパティーを設定します。このプロパティーは非推奨となりました。'mp.jwt.token.header' を使用してください。

smallrye.jwt.key-cache-size

100

キーキャッシュサイズ。このプロパティーおよび smallrye.jwt.key-cache-time-to-live を使用して、鍵を動的に解決するために AWS_ALB などの鍵プロバイダーが smallrye.jwt.verify.key-provider=AWS_ALB で設定されている場合に鍵キャッシュを制御します。

smallrye.jwt.key-cache-time-to-live

10

キーキャッシュエントリーの有効期間 (分単位)。このプロパティーおよび smallrye.jwt.key-cache-size を使用して、鍵を動的に解決するために AWS_ALB などの鍵プロバイダーが smallrye.jwt.verify.key-provider=AWS_ALB で設定されている場合に鍵キャッシュを制御します。

smallrye.jwt.token.cookie

none

トークンが含まれるクッキーの名前。このプロパティーは、smallrye.jwt.token.headerCookie に設定されている場合にのみ有効です。このプロパティーは非推奨となりました。mp.jwt.token.cookie を使用してください。

smallrye.jwt.always-check-authorization

false

smallrye.jwt.token.headerCookie に設定されていても、名前が smallrye.jwt.token.cookie の Cookie が存在しない場合、Authorization ヘッダーがチェックされるようにこのプロパティーを true に設定します。

smallrye.jwt.token.schemes

Bearer

DPoP などの単一または複数の代替スキームを含むコンマ区切りのリスト。

smallrye.jwt.token.kid

none

鍵識別子。検証 JWK 鍵とすべての JWT トークンには、設定されている場合は一致する kid ヘッダーが必要です。

smallrye.jwt.time-to-live

none

JWT を発行して使用できる最大秒数。実質的に、JWT の有効期限と発行日の差は、この値を超えることはできません。このプロパティーを正でない値に設定すると、トークンが有効な 'iat' (issued at) クレームを持つ要件が緩和されます。

smallrye.jwt.require.named-principal

true

アプリケーションが、名前を返す java.security.Principal に依存している場合、トークンには upn または preferred_username あるいは sub クレームを設定する必要があります。このプロパティーを設定する場合、アプリケーションコードが null 以外の Principal 名を確実に処理するために必要なクレームが利用できなければ、SmallRye JWT は例外をスローします。

smallrye.jwt.path.sub

none

サブジェクト名が含まれるクレームへのパス。トップレベルの JSON オブジェクトから開始し、各セグメントが JSON オブジェクト名のみを表す複数のセグメントを含めることができます (例: realms/subject)。このプロパティーは、トークンに 'sub' クレームがないが、サブジェクトが別のクレームに設定されている場合に使用できます。namespace で修飾されたクレームには二重引用符を使用します。

smallrye.jwt.claims.sub

none

このプロパティーは、現在のトークンに利用可能な標準またはカスタムの sub クレームがない場合に、デフォルトのサブクレーム値を設定できます。実質的に、このプロパティーを使用して、upn または preferred_username、あるいは sub クレームが設定されていない場合に java.security.Principal 名をカスタマイズできます。

smallrye.jwt.path.groups

none

グループを含むクレームへのパス。トップレベルの JSON オブジェクトから開始し、各セグメントが JSON オブジェクト名のみを表す複数のセグメントを含めることができます (例: realm/groups)。このプロパティーは、トークンに 'groups' クレームがなく、グループが別のクレームに設定されている場合に使用できます。namespace で修飾されたクレームには二重引用符を使用します。

smallrye.jwt.groups-separator

space

複数のグループ値を含む可能性がある文字列を分割するセパレーター。これは、smallrye.jwt.path.groups プロパティーが文字列値を持つカスタムクレームを指している場合にのみ使用されます。標準の OAuth2 scope クレームにはスペースで区切られたシーケンスが含まれる可能性があるため、デフォルト値は単一のスペースになります。

smallrye.jwt.claims.groups

none

このプロパティーでは、現在のトークンに使用可能な標準またはカスタムのグループクレームがない場合に、デフォルトのグループクレーム値を設定できます。

smallrye.jwt.jwks.refresh-interval

60

JWK キャッシュの更新間隔 (分単位)。mp.jwt.verify.publickey.location が HTTP または HTTPS URL ベースの JWK セットを指し、正の max-age パラメーター値を持つ HTTP Cache-Control 応答ヘッダーが JWK HTTPS エンドポイントから返されない限りは無視されます。

smallrye.jwt.jwks.forced-refresh-interval

30

強制される JWK キャッシュの更新間隔 (分単位)。これは、現在のトークンの kid ヘッダーに一致する kid プロパティーを持つ JWK 鍵がキャッシュにないためにトークンの検証に失敗した場合に発生する可能性がある強制更新試行の頻度を制限するために使用されます。これは、mp.jwt.verify.publickey.location が HTTP または HTTPS URL ベースの JWK セットを指す場合を除き、無視されます。

smallrye.jwt.expiration.grace

0

有効期限の猶予時間 (秒単位)。デフォルトでは、トークンの有効期限後 1 分以内であれば、期限切れのトークンが引き続き受け入れられます。このプロパティーは非推奨にされています。代わりに mp.jwt.verify.clock.skew を使用してください。

smallrye.jwt.verify.aud

none

トークン aud クレームに含まれる可能性のあるオーディエンスのコンマ区切りリスト。このプロパティーは非推奨となりました。mp.jwt.verify.audiences を使用してください。

smallrye.jwt.required.claims

none

トークンに含める必要があるクレームのコンマ区切りリスト。

smallrye.jwt.decrypt.key.location

none

秘密復号鍵の外部または内部の場所を指定するための設定プロパティー。このプロパティーは非推奨となりました。mp.jwt.decrypt.key.location を使用してください。

smallrye.jwt.decrypt.algorithm

RSA_OAEP

復号化アルゴリズム。

smallrye.jwt.decrypt.key

none

復号化鍵は文字列として指定されます。

smallrye.jwt.token.decryption.kid

none

復号化鍵の識別子。これが設定されている場合には、復号化 JWK 鍵とすべての JWT トークンに一致する kid ヘッダーが必要です。

smallrye.jwt.client.tls.certificate.path

none

鍵を HTTPS 経由で取得する必要がある場合に設定する必要がある可能性のある TLS 信頼済み証明書へのパス。

smallrye.jwt.client.tls.trust-all

false

すべてのホスト名を信頼します。鍵を HTTPS 経由で取得する必要があり、このプロパティーを true に設定すると、すべてのホスト名はデフォルトで信頼されます。

smallrye.jwt.client.tls.hosts

none

信頼できるホスト名のセット。鍵を HTTPS 経由で取得する必要があり、smallrye.jwt.client.tls.trust-allfalse に設定すると、このプロパティーを使用して信頼されるホスト名を設定できます。

smallrye.jwt.http.proxy.host

none

HTTP プロキシーホスト。

smallrye.jwt.http.proxy.port

80

HTTP プロキシーポート。

smallrye.jwt.keystore.type

JKS

このプロパティーは、mp.jwt.verify.publickey.location または mp.jwt.decrypt.key.location のいずれかが KeyStore ファイルを指す場合に、キーストアタイプをカスタマイズするために使用できます。設定されていない場合は、ファイル名をチェックしてキーストアタイプを決定し、その後デフォルトで JKS に設定されます。

smallrye.jwt.keystore.provider

 

このプロパティーは、mp.jwt.verify.publickey.location または mp.jwt.decrypt.key.locationKeyStore ファイルを指す場合に、KeyStore プロバイダーをカスタマイズするために使用できます。

smallrye.jwt.keystore.password

 

キーストアパスワードmp.jwt.verify.publickey.location または mp.jwt.decrypt.key.location の場合は、このプロパティーを設定する必要があります。

smallrye.jwt.keystore.verify.key.alias

 

このプロパティーは、mp.jwt.verify.publickey.locationKeyStore ファイルを指している場合に、KeyStore から抽出される公開検証鍵を一致する証明書から識別するために設定する必要があります。

smallrye.jwt.keystore.decrypt.key.alias

 

mp.jwt.decrypt.key.locationKeyStore ファイルを指している場合は、このプロパティーは秘密の復号化鍵を特定するために設定する必要があります。

smallrye.jwt.keystore.decrypt.key.password

 

このプロパティーは、mp.jwt.decrypt.key.locationKeyStore ファイルを指しているときに、KeyStore 内の秘密復号化鍵のパスワードが smallrye.jwt.keystore.password と異なる場合に設定できます。

smallrye.jwt.resolve-remote-keys-at-startup

false

アプリケーションの起動時にリモート鍵を解決するには、このプロパティーを true に設定します。

1.5. 参考資料

第2章 JSON Web Token のビルド、署名、暗号化

JSON Web Token (JWT) は、RFC 7519 仕様で、クレームを表すコンパクトで URL セーフな手段として定義されています。これらのクレームは JSON オブジェクトとしてエンコードされ、JSON Web Signature (JWS) 構造のペイロードまたは JSON Web Encryption (JWE) 構造のプレーンテキストとして使用できます。このメカニズムにより、クレームをデジタル署名したり、Message Authentication Code (MAC) を使用して整合性を保護したり、暗号化したりできるようになります。

クレームに署名することが、クレームを確保するための最も一般的な方法です。通常、JWT トークンは、JSON Web Signature (JWS) 仕様で概説されている手順に従って、JSON としてフォーマットされたクレームに署名することによって生成されます。

クレームに機密情報が含まれている場合、JSON Web Encryption (JWE) 仕様を使用して機密性を確保できます。このアプローチでは、暗号化されたクレームを含む JWT が生成されます。

セキュリティーを強化するために、両方の方法を組み合わせることができます。最初にクレームへ署名し、その結果として生成されるネストされた JWT を次に暗号化します。このプロセスにより、クレームの機密性と整合性の両方が確保されます。

SmallRye JWT Build API は、これらすべてのオプションをサポートすることで、JWT クレームの保護を簡素化します。この機能を提供するために、内部では Jose4J ライブラリーを使用します。

2.1. 依存関係

SmallRye JWT Build API を使用するには、プロジェクトに次の依存関係を追加します。

  • Maven を使用する場合:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-smallrye-jwt-build</artifactId>
    </dependency>
  • Gradle を使用する場合:

    implementation("io.quarkus:quarkus-smallrye-jwt-build")

SmallRye JWT Build API は、quarkus-smallrye-jwt エクステンションがサポートする MicroProfile JWT エンドポイントを作成せずに、単独で使用できます。

2.2. JwtClaimsBuilder を作成し、クレームを設定する

最初のステップとして、以下のオプションの 1 つを使用して JwtClaimsBuilder を初期化し、それにいくつかのクレームを追加します。

import java.util.Collections;
import jakarta.json.Json;
import jakarta.json.JsonObject;
import io.smallrye.jwt.build.Jwt;
import io.smallrye.jwt.build.JwtClaimsBuilder;
import org.eclipse.microprofile.jwt.JsonWebToken;
...
// Create an empty builder and add some claims
JwtClaimsBuilder builder1 = Jwt.claims();
builder1.claim("customClaim", "custom-value").issuer("https://issuer.org");
// Alternatively, start with claims directly:
// JwtClaimsBuilder builder1 = Jwt.upn("Alice");

// Create a builder from an existing claims file
JwtClaimsBuilder builder2 = Jwt.claims("/tokenClaims.json");

// Create a builder from a map of claims
JwtClaimsBuilder builder3 = Jwt.claims(Collections.singletonMap("customClaim", "custom-value"));

// Create a builder from a JsonObject
JsonObject userName = Json.createObjectBuilder().add("username", "Alice").build();
JsonObject userAddress = Json.createObjectBuilder().add("city", "someCity").add("street", "someStreet").build();
JsonObject json = Json.createObjectBuilder(userName).add("address", userAddress).build();
JwtClaimsBuilder builder4 = Jwt.claims(json);

// Create a builder from a JsonWebToken
@Inject JsonWebToken token;
JwtClaimsBuilder builder5 = Jwt.claims(token);

API は Fluent であるため、Fluent Sequence の一部としてビルダーを初期化できます。

明示的に設定されていない場合、ビルダーは次のクレームを自動的に設定します。

  • iat (発行時刻): 現在の時刻
  • exp (有効期限): 現在の時刻から 5 分後 (smallrye.jwt.new-token.lifespan プロパティーでカスタマイズ可能)
  • jti (一意のトークン識別子)

ビルダーで直接設定しなくても済むように、次のプロパティーをグローバルに設定できます。

  • smallrye.jwt.new-token.issuer: デフォルトの発行者を指定します。
  • smallrye.jwt.new-token.audience: デフォルトのオーディエンスを指定します。

クレームを初期化して設定した後、次のステップとして、クレームを保護する方法を決定します。

2.3. クレームの署名

クレームは、すぐに署名することも、JSON Web Signature (JWS) ヘッダーを設定した後に署名することもできます。

import io.smallrye.jwt.build.Jwt;
...

// Sign the claims using an RSA private key loaded from the location specified by the 'smallrye.jwt.sign.key.location' property.
// No 'jws()' transition is required. The default algorithm is RS256.
String jwt1 = Jwt.claims("/tokenClaims.json").sign();

// Set the headers and sign the claims by using an RSA private key loaded in the code (the implementation of this method is omitted).
// Includes a 'jws()' transition to a 'JwtSignatureBuilder'. The default algorithm is RS256.

String jwt2 = Jwt.claims("/tokenClaims.json")
                 .jws()
                 .keyId("kid1")
                 .header("custom-header", "custom-value")
                 .sign(getPrivateKey());

デフォルトの動作:

  • alg (アルゴリズム) ヘッダーはデフォルトで RS256 に設定されます。
  • kid プロパティーを含む単一の JSON Web Key (JWK) が使用される場合、署名鍵の識別子 (kid ヘッダー) を設定する必要はありません。

サポートされているキーとアルゴリズム:

  • クレームに署名するには、RSA 秘密鍵、楕円曲線 (EC) 秘密鍵、対称シークレットキーを使用できます。
  • RS256 はデフォルトの RSA 秘密鍵署名アルゴリズムです。
  • ES256 はデフォルトの EC 秘密鍵署名アルゴリズムです。
  • HS256 はデフォルトの対称鍵署名アルゴリズムです。

署名アルゴリズムをカスタマイズするには、JwtSignatureBuilder API を使用します。以下に例を示します。

import io.smallrye.jwt.SignatureAlgorithm;
import io.smallrye.jwt.build.Jwt;

// Sign the claims using an RSA private key loaded from the location set with a 'smallrye.jwt.sign.key.location' property. The algorithm is PS256.
String jwt = Jwt.upn("Alice").jws().algorithm(SignatureAlgorithm.PS256).sign();

または、次のプロパティーを使用して署名アルゴリズムをグローバルに設定することもできます。

smallrye.jwt.new-token.signature-algorithm=PS256

このアプローチにより、よりシンプルな API シーケンスが実現します。

import io.smallrye.jwt.build.Jwt;

// Sign the claims using an RSA private key loaded from the location set with a 'smallrye.jwt.sign.key.location' property. The algorithm is PS256.
String jwt = Jwt.upn("Alice").sign();

sign ステップと 暗号化 ステップを組み合わせて、inner-signed and encrypted トークンを作成できます。詳細は、クレームに署名し、ネストされた JWT トークンを暗号化する セクションを参照してください。

2.4. クレームの暗号化

クレームの署名方法と同様に、クレームをすぐに暗号化することも、JSON Web Encryption (JWE) ヘッダーを設定した後に暗号化することもできます。ただし、API は署名および内部署名操作をサポートするように最適化されているため、クレームを暗号化するには、常に JwtEncryptionBuilder への jwe() 遷移が必要です。

import io.smallrye.jwt.build.Jwt;
...

// Encrypt the claims using an RSA public key loaded from the location specified by the 'smallrye.jwt.encrypt.key.location' property.
// The default key encryption algorithm is RSA-OAEP.

String jwt1 = Jwt.claims("/tokenClaims.json").jwe().encrypt();

// Set the headers and encrypt the claims by using an RSA public key loaded in the code (the implementation of this method is omitted).
// The default key encryption algorithm is A256KW.
String jwt2 = Jwt.claims("/tokenClaims.json").jwe().header("custom-header", "custom-value").encrypt(getSecretKey());

デフォルトの動作:

  • alg (キー管理アルゴリズム) ヘッダーのデフォルトは RSA-OAEP です。
  • enc (コンテンツ暗号化) ヘッダーのデフォルトは A256GCM です。

サポートされているキーとアルゴリズム:

  • クレームを暗号化するには、RSA 公開鍵、楕円曲線 (EC) 公開鍵、対称シークレットキーを使用できます。
  • RSA-OAEP はデフォルトの RSA 公開鍵暗号化アルゴリズムです。
  • ECDH-ES はデフォルトの EC 公開鍵暗号化アルゴリズムです。
  • A256KW はデフォルトの対称鍵暗号化アルゴリズムです。

暗号化されたトークンの作成時に、2 つの暗号化操作が実行されることに注意してください。

  1. 生成されたコンテンツ暗号鍵は、提供されたキーと RSA-OAEP などのキー暗号化アルゴリズムを使用して暗号化されます。
  2. クレームは、コンテンツ暗号鍵と A256GCM などのコンテンツ暗号化アルゴリズムを使用して暗号化されます。

JwtEncryptionBuilder API を使用して、キーとコンテンツの暗号化アルゴリズムをカスタマイズできます。以下に例を示します。

import io.smallrye.jwt.KeyEncryptionAlgorithm;
import io.smallrye.jwt.ContentEncryptionAlgorithm;
import io.smallrye.jwt.build.Jwt;

// Encrypt the claims using an RSA public key loaded from the location set with a 'smallrye.jwt.encrypt.key.location' property.
// Key encryption algorithm is RSA-OAEP-256. The content encryption algorithm is A256CBC-HS512.

String jwt = Jwt.subject("Bob").jwe()
    .keyAlgorithm(KeyEncryptionAlgorithm.RSA_OAEP_256)
    .contentAlgorithm(ContentEncryptionAlgorithm.A256CBC_HS512)
    .encrypt();

または、次のプロパティーを使用してアルゴリズムをグローバルに設定することもできます。

smallrye.jwt.new-token.key-encryption-algorithm=RSA-OAEP-256
smallrye.jwt.new-token.content-encryption-algorithm=A256CBC-HS512

この設定により、API シーケンスが簡素化されます。

import io.smallrye.jwt.build.Jwt;

// Encrypt the claims by using an RSA public key loaded from the location set with a 'smallrye.jwt.encrypt.key.location' property.
// Key encryption algorithm is RSA-OAEP-256. The content encryption algorithm is A256CBC-HS512.
String jwt = Jwt.subject("Bob").encrypt();

安全なトークン暗号化に関する推奨事項:

  • トークンが公開 RSA または EC 鍵で直接暗号化されると、どの当事者がトークンを送信したかを確認できません。これに対処するには、特に Quarkus エンドポイントによってのみ管理される Cookie として JWT を使用する場合、直接暗号化には対称シークレットキーが推奨されます。
  • RSA または EC 公開鍵を使用してトークンを暗号化するには、署名鍵が使用可能な場合は最初にトークンに署名することを推奨します。詳細は、クレームに署名し、ネストされた JWT トークンを暗号化する セクションを参照してください。

2.5. クレームに署名し、ネストされた JWT トークンを暗号化する

クレームに署名し、署名と暗号化のステップを組み合わせてネストされた JWT トークンを暗号化できます。

import io.smallrye.jwt.build.Jwt;
...

// Sign the claims and encrypt the nested token using the private and public keys loaded from the locations
// specified by the 'smallrye.jwt.sign.key.location' and 'smallrye.jwt.encrypt.key.location' properties, respectively.
// The signature algorithm is RS256, and the key encryption algorithm is RSA-OAEP-256.
String jwt = Jwt.claims("/tokenClaims.json").innerSign().encrypt();

2.6. JWT の高速生成

smallrye.jwt.sign.key.location または smallrye.jwt.encrypt.key.location プロパティーが設定されている場合は、リソース、マップ、JsonObject などの既存のクレームを 1 回の呼び出しで保護できます。

// More compact than Jwt.claims("/claims.json").sign();
Jwt.sign("/claims.json");

// More compact than Jwt.claims("/claims.json").jwe().encrypt();
Jwt.encrypt("/claims.json");

// More compact than Jwt.claims("/claims.json").innerSign().encrypt();
Jwt.signAndEncrypt("/claims.json");

前述のように、iat (発行時刻)、exp (有効期限)、jti (トークン識別子)、iss (発行者)、および aud (オーディエンス) などのクレームは、まだ設定されていない場合は自動的に追加されます。

2.7. 鍵の処理

smallrye.jwt.sign.key.location および smallrye.jwt.encrypt.key.location プロパティーを使用して、署名鍵と暗号鍵の場所を指定できます。これらの鍵は、ローカルファイルシステム、クラスパス上に配置することも、リモートエンドポイントから取得することもできます。鍵は PEM または JSON Web Key (JWK) 形式にすることができます。以下に例を示します。

smallrye.jwt.sign.key.location=privateKey.pem
smallrye.jwt.encrypt.key.location=publicKey.pem

または、MicroProfile ConfigSourcesmallrye.jwt.sign.key、および smallrye.jwt.encrypt.key プロパティーを使用して、HashiCorp Vault やその他のシークレットマネージャーなどの外部サービスから鍵を取得することもできます。

smallrye.jwt.sign.key=${private.key.from.vault}
smallrye.jwt.encrypt.key=${public.key.from.vault}

この例では、private.key.from.vaultpublic.key.from.vault は、カスタム ConfigSource によって提供される PEM または JWK 形式のキー値です。

smallrye.jwt.sign.key および smallrye.jwt.encrypt.key プロパティーには、Base64 でエンコードされた秘密鍵または公開鍵の値を直接含めることもできます。

ただし、設定に秘密鍵を直接インライン化することは推奨されないことに注意してください。smallrye.jwt.sign.key プロパティーは、リモートシークレットマネージャーから署名鍵値を取得する必要がある場合にのみ使用してください。

キーは、トークンをビルドするコードによって読み込まれ、トークン作成のために JWT Build API に渡すこともできます。

対称シークレットキーを使用してトークンに署名または暗号化する必要がある場合は、io.smallrye.jwt.util.KeyUtils を使用して必要な長さの SecretKey を生成することを検討してください。

たとえば、HS512 アルゴリズム (512/8) を使用してトークンに署名するには 64 バイトのキーが、A256KW アルゴリズム (256/8) を使用してコンテンツ暗号鍵を暗号化するには 32 バイトのキーが必要です。

import javax.crypto.SecretKey;
import io.smallrye.jwt.KeyEncryptionAlgorithm;
import io.smallrye.jwt.SignatureAlgorithm;
import io.smallrye.jwt.build.Jwt;
import io.smallrye.jwt.util.KeyUtils;

SecretKey signingKey = KeyUtils.generateSecretKey(SignatureAlgorithm.HS512);
SecretKey encryptionKey = KeyUtils.generateSecretKey(KeyEncryptionAlgorithm.A256KW);
String jwt = Jwt.claim("sensitiveClaim", getSensitiveClaim()).innerSign(signingKey).encrypt(encryptionKey);

シークレットキーをセキュアなファイルシステムに保存するには、JSON Web Key (JWK) または JSON Web Key Set (JWK Set) 形式の使用も検討できます。smallrye.jwt.sign.key.location または smallrye.jwt.encrypt.key.location プロパティーを使用して鍵を参照できます。

JWK の例

{
 "kty":"oct",
 "kid":"secretKey",
 "k":"Fdh9u8rINxfivbrianbbVT1u232VQBZYKx1HGAGPt2I"
}

JWK セットの例

{
 "keys": [
   {
     "kty":"oct",
     "kid":"secretKey1",
     "k":"Fdh9u8rINxfivbrianbbVT1u232VQBZYKx1HGAGPt2I"
   },
   {
     "kty":"oct",
     "kid":"secretKey2",
     "k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
   }
 ]
}

io.smallrye.jwt.util.KeyUtils を使用して、非対称 RSA 鍵または EC 鍵のペアを生成することもできます。これらの鍵は、JWKJWK Set、または PEM 形式で保存できます。

2.8. SmallRye JWT ビルダーの設定

SmallRye JWT は、クレームの署名または暗号化の方法をカスタマイズするために使用できる次のプロパティーをサポートしています。

Expand
プロパティー名デフォルト説明

smallrye.jwt.sign.key.location

none

引数なしの sign() または innerSign() メソッドが呼び出されたときにクレームに署名するために使用される秘密鍵の場所です。

smallrye.jwt.sign.key

none

引数なしの sign() または innerSign() メソッドが呼び出されたときにクレームに署名するために使用されるキー値。

smallrye.jwt.sign.key.id

none

署名キー識別子。JWK キーが使用される場合にのみチェックされます。

smallrye.jwt.encrypt.key.location

none

引数なしの encrypt() メソッドが呼び出されたときに、クレームまたは内部 JWT を暗号化するために使用される公開鍵の場所です。

smallrye.jwt.sign.relax-key-validation

false

署名鍵の検証を緩和します。

smallrye.jwt.encrypt.key

none

引数なしの encrypt() メソッドが呼び出されたときにクレームまたは内部 JWT を暗号化するために使用されるキー値。

smallrye.jwt.encrypt.key.id

none

暗号鍵識別子。JWK キーが使用される場合にのみチェックされます。

smallrye.jwt.encrypt.relax-key-validation

false

暗号化鍵の検証を緩和します。

smallrye.jwt.new-token.signature-algorithm

RS256

署名アルゴリズム。JWT 署名ビルダーが署名アルゴリズムをまだ設定していないかが確認されます。

smallrye.jwt.new-token.key-encryption-algorithm

RSA-OAEP

鍵暗号化アルゴリズム。JWT 暗号化ビルダーがキー暗号化アルゴリズムをまだ設定していないかが確認されます。

smallrye.jwt.new-token.content-encryption-algorithm

A256GCM

コンテンツ暗号化アルゴリズム。JWT 暗号化ビルダーがコンテンツ暗号化アルゴリズムをまだ設定していないかが確認されます。

smallrye.jwt.new-token.lifespan

300

このクレームがまだ設定されていない場合に、exp (有効期限) クレーム値を計算するために使用されるトークンの有効期間 (秒単位)。

smallrye.jwt.new-token.issuer

none

このクレームがまだ設定されていない場合に、iss (発行者) クレーム値を設定するために使用されるトークン発行者。

smallrye.jwt.new-token.audience

none

このクレームがまだ設定されていない場合に、aud (オーディエンス) クレーム値を設定するために使用されるトークンオーディエンス。

smallrye.jwt.new-token.override-matching-claims

false

このプロパティーの smallrye.jwt.new-token.issuer および smallrye.jwt.new-token.audience 値を true に設定して、初期化済みの iss (issuer) および aud (audience) クレームをオーバーライドします。

smallrye.jwt.new-token.add-default-claims

true

このプロパティーを false に設定すると、iat (発行時刻)、exp (有効期限)、および jti (トークン識別子) クレームがまだ設定されていない場合に、これらのクレームの自動追加が無効になります。

smallrye.jwt.keystore.type

JKS

This property can be used to customize a keystore type if either smallrye.jwt.sign.key.location or smallrye.jwt.encrypt.key.location or both of these properties point to a KeyStore file.設定されていない場合、ファイル名をチェックして、デフォルトで JKS になる前にキーストアタイプを判断します。

smallrye.jwt.keystore.provider

 

このプロパティーは、smallrye.jwt.sign.key.location または smallrye.jwt.encrypt.key.locationKeyStore ファイルを指す場合に、KeyStore プロバイダーをカスタマイズするために使用できます。

smallrye.jwt.keystore.password

 

キーストアパスワードsmallrye.jwt.sign.key.location または smallrye.jwt.encrypt.key.locationKeyStore ファイルを指す場合、このプロパティーを設定する必要があります。

smallrye.jwt.keystore.encrypt.key.alias

 

smallrye.jwt.encrypt.key.locationKeyStore ファイルを指している場合、一致する証明書の KeyStore から抽出された公開暗号鍵を識別するには、このプロパティーを設定する必要があります。

smallrye.jwt.keystore.sign.key.alias

 

このプロパティーは、smallrye.jwt.sign.key.locationKeyStore ファイルを指している場合、秘密署名鍵を特定するために設定する必要があります。

smallrye.jwt.keystore.sign.key.password

 

このプロパティーは、smallrye.jwt.sign.key.locationKeyStore ファイルを指しているときに、KeyStore 内の秘密署名鍵のパスワードが smallrye.jwt.keystore.password と異なる場合に設定できます。

2.9. 参考資料

法律上の通知

Copyright © 2025 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.
Red Hat logoGithubredditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。 最新の更新を見る.

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

Theme

© 2026 Red Hat
トップに戻る