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 を検証し、MicroProfile JWT org.eclipse.microprofile.jwt.JsonWebToken として表現し、ベアラートークン認可と ロールベースアクセス制御 を使用して Quarkus HTTP エンドポイントを保護する方法を学習します。

注記

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

Quarkus アプリケーションで OIDC 認可コードフローを使用してユーザーを認証する必要がある場合は、OpenID Connect 拡張機能を使用する必要があります。詳細は、Web アプリケーションを保護するための OIDC コードフローメカニズム を参照してください。

1.1. 前提条件

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

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

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
要求ユーザー/呼び出し元の プリンシパルが null かどうかをチェックして、呼び出しが安全でないかどうかを確認します。
5
JsonWebToken は 現在の Principal を表すため、PrincipalJsonWebToken の名前が一致することを確認します。
6
プリンシパル の名前を取得します。
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-all の curl コマンド

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

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

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

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

  • ユーザー名は匿名です。
  • https が使用されていないため、isHttpsfalse です。
  • authScheme は null です。
  • hasJWT は false です。

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

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

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

/secured/roles-allowed の curl コマンド

$ 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 不正なエラーが発生しました。

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

  1. JWT を検証するために必要な情報を使用して SmallRye JWT 拡張機能を設定します。
  2. 設定に一致する適切なクレームを含む JWT を生成します。

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

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

TokenSecuredResource の application.properties

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
MicroProfile JWT RBAC 仕様では、コンテナーセキュリティー API で プリンシパル を識別するための推奨クレームとして定義されている upn (ユーザープリンシパル名) クレームを指定します。
3
JWT ベアラーに割り当てられたグループメンバーシップと最上位レベルのロールを提供する グループ クレームを定義します。
4
生年月日の クレームを追加します。これは機密情報とみなされる可能性があるため、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-allowed の curl コマンド

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

生成されたトークンを HTTP 認可ベアラースキームの値として必ず使用してください。

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

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

Success! これで次のようになります。

  • 匿名でない発信者名: jdoe@quarkus.io
  • 認証方式: ベアラー
  • null 以外の JsonWebToken
  • 生年月日 請求額

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
生年月日 クレームを 文字列 として挿入できるようにするには、@RequestScoped スコープが必要です。
2
JsonWebToken がここに挿入され、すべてのクレームと JWT 関連情報へのアクセスが提供されます。
3
生年月日の クレームは String として挿入されます。これは、@RequestScoped スコープが必須である理由を強調しています。
4
挿入された 生年月日の クレームは、応答の構築に直接使用されます。

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

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

生成されたトークンを HTTP 認可ベアラースキームの値として必ず使用してください。

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

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ディレクトリー リポジトリーには、このクイックスタートガイドで説明されているすべてのバージョンに加えて、挿入された JsonWebToken トークンとそのクレームを CDI API 経由で使用するサブリソースを示す追加のエンドポイントが含まれています。

SmallRye JWT 拡張機能の機能について詳しく知るには、security-jwt-quickstart ディレクトリーを調べてクイックスタートソリューションを確認することを推奨します。

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 または Elliptic Curve (EC) 鍵を使用してトークンの署名を検証する必要がある場合は、mp.jwt.verify.publickey.location プロパティーを使用してローカルまたはリモート検証鍵を参照します。

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

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

{
 "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 プリンシパルに変換するために使用されるデフォルトの実装です。このファクトリーは、設定 セクションで説明されているように、MP JWTsmallrye-jwt プロパティーに依存して、JWT トークンを検証およびカスタマイズします。

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

  • META-INF/services/io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory リソースを作成して、ServiceLoader メカニズムを使用します。
  • 以下の例のように、代替 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 スレッドが、以下のいずれかの場合にブロックする可能性があることを意味します。

  • デフォルトのキーリゾルバーは、キーを含む JsonWebKey セットを更新します。これには、OIDC エンドポイントへのリモート呼び出しが含まれます。
  • 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 の設定

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

設定プロパティー

デフォルト

lock quarkus.smallrye-jwt.enabled

MP-JWT 設定オブジェクト

環境変数: QUARKUS_SMALLRYE_JWT_ENABLED

boolean

true

lock 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 設定

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

mp.jwt.verify.publickey

none

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

mp.jwt.verify.publickey.location

none

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

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 は、トークン処理をカスタマイズするために使用できる追加のプロパティーを提供します。

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

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 以外の プリンシパル 名を確実に処理するためにこれらのクレームを利用できない場合に、SmallRye JWT は例外をスローします。

smallrye.jwt.path.sub

none

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

smallrye.jwt.claims.sub

none

このプロパティーでは、現在のトークンに使用可能な標準またはカスタムの サブ クレームがない場合に、デフォルトのサブクレーム値を設定できます。実質的に、このプロパティーを使用して、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 署名 (JWS) 構造のペイロードまたは JSON Web 暗号化 (JWE) 構造のプレーンテキストとして使用できます。このメカニズムにより、クレームをデジタル署名したり、メッセージ認証コード (MAC) を使用して整合性を保護したり、暗号化したりできるようになります。

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

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

セキュリティーを強化するために、両方の方法を組み合わせることができます。まずクレームに署名し、次に結果のネストされた JWT を暗号化します。このプロセスにより、請求の機密性と完全性の両方が保証されます。

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

2.1. 依存関係

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

  • Maven を使用:

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

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

quarkus-smallrye-jwt 拡張機能でサポートされている MicroProfile JWT エンドポイントを作成せずに、SmallRye JWT ビルド API を独立して使用できます。

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

最初のステップは、次のいずれかのオプションを使用して 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 は流暢なので、流暢なシーケンスの一部としてビルダーを初期化できます。

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

  • 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 (algorithm) ヘッダーはデフォルトで 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();

署名 ステップと 暗号化 ステップを組み合わせて、内部署名および暗号化された トークンを作成できます。詳細は、クレームに署名し、ネストされた 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 プロパティーが設定されている場合は、リソース、マップ、JsonObjects などの既存のクレームを 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 ビルド 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 セット、または PEM 形式で保存できます。

2.8. SmallRye JWT ビルダーの設定

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

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

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.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.location が KeyStore ファイルを指している場合、一致する証明書の 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 は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

© 2024 Red Hat, Inc.