The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
このページを編集

JWT RBAC の使用

This guide explains how to integrate SmallRye JWT into your Quarkus application to implement JSON Web Token (JWT) security in compliance with the MicroProfile JWT specification. You’ll learn how to verify JWTs, represent them as MicroProfile JWT org.eclipse.microprofile.jwt.JsonWebToken, and secure Quarkus HTTP endpoints using bearer token authorization and Role-Based Access Control.

The Quarkus OpenID Connect (quarkus-oidc) extension also supports bearer token authorization and uses smallrye-jwt to represent bearer tokens as JsonWebToken. For details, see the OIDC Bearer Token Authentication guide.

If your Quarkus application needs to authenticate users using the OIDC Authorization Code Flow, you must use the OpenID Connect extension. For more information, refer to the OIDC Code Flow Mechanism for Protecting Web Applications.

前提条件

このガイドを完成させるには、以下が必要です:

  • 約15分

  • IDE

  • JDK 17+がインストールされ、 JAVA_HOME が適切に設定されていること

  • Apache Maven 3.9.9

  • 使用したい場合は、 Quarkus CLI

  • ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること

クイックスタート

ソリューション

We recommend following the instructions in the upcoming sections to create the application step by step. If you prefer, you can skip ahead to the completed example.

To access the example, either clone the Git repository or download an archive:

The completed solution is located in the security-jwt-quickstart directory.

Maven プロジェクトの作成

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

コマンドラインインタフェース
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 io.quarkus.platform:quarkus-maven-plugin:3.17.4: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"

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

If you already have your Quarkus project configured, you can add the smallrye-jwt extension to your project by running the following command in your project base directory:

コマンドラインインタフェース
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'

This command adds the following dependencies to your build file:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-smallrye-jwt</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-smallrye-jwt-build</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-smallrye-jwt")
implementation("io.quarkus:quarkus-smallrye-jwt-build")

Jakarta REST リソースの調査

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

REST endpoint 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 The JsonWebToken interface is injected, providing access to claims associated with the current authenticated token. This interface extends java.security.Principal.
2 The @PermitAll is a standard Jakarta security annotation. It indicates that the given endpoint is accessible by all callers, whether authenticated or not.
3 The Jakarta REST SecurityContext is injected to inspect the security state of the request. The getResponseString() function generates the response.
4 Checks if the call is insecure by checking if the request user/caller Principal against null.
5 Ensures the names in the Principal and JsonWebToken match because the JsonWebToken represents the current Principal.
6 Retrieves the name of the Principal.
7 Builds a response containing the caller’s name, the isSecure() and getAuthenticationScheme() states of the request SecurityContext, and whether a non-null JsonWebToken was injected.

アプリケーションの実行

Now you are ready to run our application. Use:

コマンドラインインタフェース
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

Then, you should see output similar to the following example:

quarkus:dev output
[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]

Now that the REST endpoint is running, you can access it by using a command line tool such as curl:

curl command for /secured/permit-all
$ curl http://127.0.0.1:8080/secured/permit-all; echo
hello anonymous, isHttps: false, authScheme: null, hasJWT: false

You have not provided any JWT in our request, so you would not expect the endpoint to see any security state, and the response is consistent with that:

  • username is anonymous.

  • isHttps is false because https is not used.

  • authScheme is null.

  • hasJWT is false.

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

では実際に何かをセキュア化してみましょう。下記の新しいエンドポイントメソッド helloRolesAllowed を見てみましょう:

REST endpoint 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 The JsonWebToken is injected to access claims from the JWT.
2 This endpoint is exposed at /secured/roles-allowed.
3 The @RolesAllowed annotation restricts access to users with either the "User" or "Admin" role.
4 The response is constructed similarly to the hello method, with the addition of the birthdate claim retrieved directly from the injected JsonWebToken.

After you make this addition to your TokenSecuredResource, rerun the ./mvnw quarkus:dev command, and then try curl -v http://127.0.0.1:8080/secured/roles-allowed; echo to attempt to access the new endpoint.

出力は以下のようになるはずです:

curl command for /secured/roles-allowed
$ 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. You have not provided any JWT in the request, so you should not be able to access the endpoint, and you were not able to. Instead, you received an HTTP 401 Unauthorized error. You need to obtain and pass in a valid JWT to access that endpoint. There are two steps to this, 1) configuring our SmallRye JWT extension with information on how to validate a JWT, and 2) generating a matching JWT with the appropriate claims.

Configuring the SmallRye JWT extension security information

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

Application properties for 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 Specifies the location of the public key file publicKey.pem on the classpath. See Adding a public key for adding this key.
2 Defines the expected issuer as https://example.com/issuer.
3 Ensures the publicKey.pem file is included as a resource in the native executable.

Adding a public key

The JWT specification defines various levels of security of JWTs that one can use. The MicroProfile JWT RBAC specification requires JWTs signed with the RSA-256 signature algorithm. This in turn requires an RSA public key pair. On the REST endpoint server side, you need to configure the location of the RSA public key to use to verify the JWT sent along with requests. The mp.jwt.verify.publickey.location=publicKey.pem setting configured previously expects that the public key is available on the classpath as publicKey.pem. To accomplish this, copy the following content to a security-jwt-quickstart/src/main/resources/publicKey.pem file.

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

JWT の生成

Often, one obtains a JWT from an identity manager such as Keycloak. But for this quickstart, you generate our own by using the JWT generation API provided by smallrye-jwt. For more information, see Generate JWT tokens with SmallRye JWT.

Take the code from the following listing and place it into security-jwt-quickstart/src/test/java/org/acme/security/jwt/GenerateToken.java:

GenerateToken main driver class
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;

public class GenerateToken {
    /**
     * Generate 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);
    }
}
1 The iss claim is the issuer of the JWT. This must match the server side mp.jwt.verify.issuer for the token to be accepted as valid.
2 The upn claim is defined by the MicroProfile JWT RBAC spec as the preferred claim to use for the Principal seen by the container security APIs.
3 group クレームは、JWT ベアラーに関連付けられたグループとトップレベルのロールを提供します。
4 The birthday claim. It can be considered a sensitive claim, so consider encrypting the claims, as described in Generate JWT tokens with SmallRye JWT.

Note that for this code to work, you need the content of the RSA private key corresponding to the public key you have in the TokenSecuredResource application. Take the following PEM content and place it into security-jwt-quickstart/src/test/resources/privateKey.pem:

RSA private key PEM content
-----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-----

Later, you configure the smallrye.jwt.sign.key.location property to specify the location of the private signing key.

Generating keys with OpenSSL

It is also possible to generate a public and private key pair by using the OpenSSL command line tool.

openssl commands to generate keys
openssl genrsa -out rsaPrivateKey.pem 2048
openssl rsa -pubout -in rsaPrivateKey.pem -out publicKey.pem

An additional step is required to generate and convert the private key to the PKCS#8 format, commonly used for secure key storage and transport.

openssl commands to perform the conversion
openssl pkcs8 -topk8 -nocrypt -inform pem -in rsaPrivateKey.pem -outform pem -out privateKey.pem

You can use the generated key pair instead of those used in this quickstart.

Now, you can generate a JWT to use with the TokenSecuredResource endpoint. To do this, run the following command:

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

eyJraWQiOiJcL3ByaXZhdGVLZXkucGVtIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJqZG9lLXVzaW5nLWp3dC1yYmFjIiwiYXVkIjoidXNpbmctand0LXJiYWMiLCJ1cG4iOiJqZG9lQHF1YXJrdXMuaW8iLCJiaXJ0aGRhdGUiOiIyMDAxLTA3LTEzIiwiYXV0aF90aW1lIjoxNTUxNjU5Njc2LCJpc3MiOiJodHRwczpcL1wvcXVhcmt1cy5pb1wvdXNpbmctand0LXJiYWMiLCJyb2xlTWFwcGluZ3MiOnsiZ3JvdXAyIjoiR3JvdXAyTWFwcGVkUm9sZSIsImdyb3VwMSI6Ikdyb3VwMU1hcHBlZFJvbGUifSwiZ3JvdXBzIjpbIkVjaG9lciIsIlRlc3RlciIsIlN1YnNjcmliZXIiLCJncm91cDIiXSwicHJlZmVycmVkX3VzZXJuYW1lIjoiamRvZSIsImV4cCI6MTU1MTY1OTk3NiwiaWF0IjoxNTUxNjU5Njc2LCJqdGkiOiJhLTEyMyJ9.O9tx_wNNS4qdpFhxeD1e7v4aBNWz1FCq0UV8qmXd7dW9xM4hA5TO-ZREk3ApMrL7_rnX8z81qGPIo_R8IfHDyNaI1SLD56gVX-NaOLS2OjfcbO3zOWJPKR_BoZkYACtMoqlWgIwIRC-wJKUJU025dHZiNL0FWO4PjwuCz8hpZYXIuRscfFhXKrDX1fh3jDhTsOEFfu67ACd85f3BdX9pe-ayKSVLh_RSbTbBPeyoYPE59FW7H5-i8IE-Gqu838Hz0i38ksEJFI25eR-AJ6_PSUD0_-TV3NjXhF3bFIeT4VSaIZcpibekoJg0cQm-4ApPEcPLdgTejYHA-mupb8hSwg

The JWT string is a Base64 URL encoded string with three parts separated by '.' characters. First part - JWT headers, second part - JWT claims, third part - JWT signature.

Finally, secured access to /secured/roles-allowed

Now, let’s use this to make a secured request to the /secured/roles-allowed endpoint. Make sure you have the Quarkus server still running in dev mode, and then run the following command, making sure to use your version of the generated JWT from the previous step:

curl -H "Authorization: Bearer eyJraWQiOiJcL3ByaXZhdGVLZXkucGVtIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJqZG9lLXVzaW5nLWp3dC1yYmFjIiwiYXVkIjoidXNpbmctand0LXJiYWMiLCJ1cG4iOiJqZG9lQHF1YXJrdXMuaW8iLCJiaXJ0aGRhdGUiOiIyMDAxLTA3LTEzIiwiYXV0aF90aW1lIjoxNTUxNjUyMDkxLCJpc3MiOiJodHRwczpcL1wvcXVhcmt1cy5pb1wvdXNpbmctand0LXJiYWMiLCJyb2xlTWFwcGluZ3MiOnsiZ3JvdXAyIjoiR3JvdXAyTWFwcGVkUm9sZSIsImdyb3VwMSI6Ikdyb3VwMU1hcHBlZFJvbGUifSwiZ3JvdXBzIjpbIkVjaG9lciIsIlRlc3RlciIsIlN1YnNjcmliZXIiLCJncm91cDIiXSwicHJlZmVycmVkX3VzZXJuYW1lIjoiamRvZSIsImV4cCI6MTU1MTY1MjM5MSwiaWF0IjoxNTUxNjUyMDkxLCJqdGkiOiJhLTEyMyJ9.aPA4Rlc4kw7n_OZZRRk25xZydJy_J_3BRR8ryYLyHTO1o68_aNWWQCgpnAuOW64svPhPnLYYnQzK-l2vHX34B64JySyBD4y_vRObGmdwH_SEufBAWZV7mkG3Y4mTKT3_4EWNu4VH92IhdnkGI4GJB6yHAEzlQI6EdSOa4Nq8Gp4uPGqHsUZTJrA3uIW0TbNshFBm47-oVM3ZUrBz57JKtr0e9jv0HjPQWyvbzx1HuxZd6eA8ow8xzvooKXFxoSFCMnxotd3wagvYQ9ysBa89bgzL-lhjWtusuMFDUVYwFqADE7oOSOD4Vtclgq8svznBQ-YpfTHfb9QEcofMlpyjNA" http://127.0.0.1:8080/secured/roles-allowed; echo
curl command for /secured/roles-allowed with JWT
$ curl -H "Authorization: Bearer eyJraWQ..." http://127.0.0.1:8080/secured/roles-allowed; echo
hello jdoe@quarkus.io, isHttps: false, authScheme: Bearer, hasJWT: true, birthdate: 2001-07-13

Success! You now have the following:

  • A non-anonymous caller name: jdoe@quarkus.io

  • An authentication scheme: Bearer

  • A non-null JsonWebToken

  • The birthdate claim value

Using the JsonWebToken and claim injection

Now that you can generate a JWT to access our secured REST endpoints, let’s see what more you can do with the JsonWebToken interface and the JWT claims. The org.eclipse.microprofile.jwt.JsonWebToken interface extends the java.security.Principal interface, and is the object type returned by the jakarta.ws.rs.core.SecurityContext#getUserPrincipal() call you used previously. This means that code that does not use CDI but does have access to the REST container SecurityContext can get hold of the caller JsonWebToken interface by casting the SecurityContext#getUserPrincipal().

The JsonWebToken interface defines methods for accessing claims in the underlying JWT. It provides accessors for common claims that are required by the MicroProfile JWT RBAC specification and arbitrary claims that might exist in the JWT.

All the JWT claims can also be injected. Let’s expand our TokenSecuredResource with another endpoint /secured/roles-allowed-admin which uses the injected birthdate claim (as opposed to getting it from JsonWebToken):

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 The @RequestScoped scope is required to enable injection of the birthdate claim as a String.
2 The JsonWebToken is injected here, providing access to all claims and JWT-related information.
3 The birthdate claim is injected as a String. This highlights why the @RequestScoped scope is mandatory.
4 The injected birthdate claim is directly used to construct the response.

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

curl -H "Authorization: Bearer eyJraWQiOiJcL3ByaXZhdGVLZXkucGVtIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJqZG9lLXVzaW5nLWp3dC1yYmFjIiwiYXVkIjoidXNpbmctand0LXJiYWMiLCJ1cG4iOiJqZG9lQHF1YXJrdXMuaW8iLCJiaXJ0aGRhdGUiOiIyMDAxLTA3LTEzIiwiYXV0aF90aW1lIjoxNTUxNjUyMDkxLCJpc3MiOiJodHRwczpcL1wvcXVhcmt1cy5pb1wvdXNpbmctand0LXJiYWMiLCJyb2xlTWFwcGluZ3MiOnsiZ3JvdXAyIjoiR3JvdXAyTWFwcGVkUm9sZSIsImdyb3VwMSI6Ikdyb3VwMU1hcHBlZFJvbGUifSwiZ3JvdXBzIjpbIkVjaG9lciIsIlRlc3RlciIsIlN1YnNjcmliZXIiLCJncm91cDIiXSwicHJlZmVycmVkX3VzZXJuYW1lIjoiamRvZSIsImV4cCI6MTU1MTY1MjM5MSwiaWF0IjoxNTUxNjUyMDkxLCJqdGkiOiJhLTEyMyJ9.aPA4Rlc4kw7n_OZZRRk25xZydJy_J_3BRR8ryYLyHTO1o68_aNWWQCgpnAuOW64svPhPnLYYnQzK-l2vHX34B64JySyBD4y_vRObGmdwH_SEufBAWZV7mkG3Y4mTKT3_4EWNu4VH92IhdnkGI4GJB6yHAEzlQI6EdSOa4Nq8Gp4uPGqHsUZTJrA3uIW0TbNshFBm47-oVM3ZUrBz57JKtr0e9jv0HjPQWyvbzx1HuxZd6eA8ow8xzvooKXFxoSFCMnxotd3wagvYQ9ysBa89bgzL-lhjWtusuMFDUVYwFqADE7oOSOD4Vtclgq8svznBQ-YpfTHfb9QEcofMlpyjNA" http://127.0.0.1:8080/secured/roles-allowed-admin; echo
$ curl -H "Authorization: Bearer eyJraWQ..." http://127.0.0.1:8080/secured/roles-allowed-admin; echo
hello jdoe@quarkus.io, isHttps: false, authScheme: Bearer, hasJWT: true, birthdate: 2001-07-13

アプリケーションのパッケージ化と実行

As usual, the application can be packaged by using:

コマンドラインインタフェース
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

And executed by using java -jar target/quarkus-app/quarkus-run.jar:

Runner jar example
$ java -jar target/quarkus-app/quarkus-run.jar
2019-03-28 14:27:48,839 INFO  [io.quarkus] (main) Quarkus 3.17.4 started in 0.796s. Listening on: http://[::]:8080
2019-03-28 14:27:48,841 INFO  [io.quarkus] (main) Installed features: [cdi, rest, rest-jackson, security, smallrye-jwt]

次のようにネイティブ実行可能ファイルを生成することもできます。

コマンドラインインタフェース
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.native.enabled=true
Native executable example
[INFO] Scanning for projects...
...
[security-jwt-quickstart-runner:25602]     universe:     493.17 ms
[security-jwt-quickstart-runner:25602]      (parse):     660.41 ms
[security-jwt-quickstart-runner:25602]     (inline):   1,431.10 ms
[security-jwt-quickstart-runner:25602]    (compile):   7,301.78 ms
[security-jwt-quickstart-runner:25602]      compile:  10,542.16 ms
[security-jwt-quickstart-runner:25602]        image:   2,797.62 ms
[security-jwt-quickstart-runner:25602]        write:     988.24 ms
[security-jwt-quickstart-runner:25602]      [total]:  43,778.16 ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  51.500 s
[INFO] Finished at: 2019-03-28T14:30:56-07:00
[INFO] ------------------------------------------------------------------------

$ ./target/security-jwt-quickstart-runner
2019-03-28 14:31:37,315 INFO  [io.quarkus] (main) Quarkus 0.12.0 started in 0.006s. Listening on: http://[::]:8080
2019-03-28 14:31:37,316 INFO  [io.quarkus] (main) Installed features: [cdi, rest, rest-jackson, security, smallrye-jwt]

Explore the solution

The security-jwt-quickstart directory repository contains all the versions covered in this quickstart guide, along with additional endpoints that demonstrate subresources using injected `JsonWebToken`s and their claims via CDI APIs.

We encourage you to explore the security-jwt-quickstart directory and review the quickstart solutions to learn more about the features of the SmallRye JWT extension.

Reference guide

Supported injection scopes

org.eclipse.microprofile.jwt.JsonWebToken が注入される場合、@ApplicationScoped@Singleton、および @RequestScoped の外部 Bean 注入スコープがすべてサポートされます。また、現在のトークンが示されていることを確認するために、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;
}

Note you can also use the injected JsonWebToken to access the individual claims, but setting @RequestScoped is unnecessary in this case.

詳細については、 MP JWT CDI 注入要件 を参照してください。

Supported public key formats

Public keys can be formatted in any of the following formats, specified in order of precedence:

  • 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 エンコード

Dealing with verification keys

If you need to verify the token signature by using the asymmetric RSA or Elliptic Curve (EC) key, use the mp.jwt.verify.publickey.location property to refer to the local or remote verification key.

Use mp.jwt.verify.publickey.algorithm to customize the verification algorithm (default is RS256); for example, set it to ES256 when working with the EC keys.

If you need to verify the token signature by using the symmetric secret key, then either a JSON Web Key (JWK) or JSON Web Key Set (JWK Set) format must be used to represent this secret key, for example:

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

This secret key JWK must also be referred to with smallrye.jwt.verify.key.location. smallrye.jwt.verify.algorithm should be set to HS256/HS384/HS512.

Parse and verify JsonWebToken with JWTParser

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

You can also use it to customize how the token is verified or decrypted. For example, one can supply a local 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();
        }
    }
}

Please also see the How to Add SmallRye JWT directly section about using JWTParser without the HTTP support provided by quarkus-smallrye-jwt.

Token decryption

If your application needs to accept tokens with encrypted claims or encrypted inner-signed claims, simply set the smallrye.jwt.decrypt.key.location property to point to the decryption key.

If this is the only key property set, the incoming token is expected to contain only encrypted claims. If either mp.jwt.verify.publickey or mp.jwt.verify.publickey.location verification properties are also set, then the incoming token is expected to contain the encrypted inner-signed token.

See Generate JWT tokens with SmallRye JWT and learn how to generate the encrypted or inner-signed and then encrypted tokens quickly.

Custom factories

The io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipalFactory is the default implementation used to parse and verify JWT tokens, converting them into JsonWebToken principals. This factory relies on the MP JWT and smallrye-jwt properties, as described in the Configuration section, to validate and customize JWT tokens.

If you need to implement a custom factory—such as to skip re-verifying tokens that have already been validated by a firewall—you can do so in one of the following ways:

  • Use the ServiceLoader mechanism by creating a META-INF/services/io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory resource.

  • Provide an Alternative CDI bean implementation, like the example below:

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

ブロッキング呼出

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

What it means from the perspective of quarkus-smallrye-jwt, which operates as part of the reactive Quarkus security architecture, is that an IO thread entering the SmallRye JWT verification or decryption code might block in one of the following cases:

  • The default key resolver refreshes the JsonWebKey set containing the keys, which involves a remote call to the OIDC endpoint.

  • The custom key resolver, such as AWS Application Load Balancer (ALB) key resolver, resolves the keys against the AWS ALB key endpoint by using the current token’s key identifier header value.

In such cases, if connections are slow—for instance, taking more than 3 seconds to respond to the key endpoint—the current event loop thread is likely to become blocked.

To prevent it from blocking, set quarkus.smallrye-jwt.blocking-authentication=true.

トークンの伝播

Please see the Token Propagation section about the Bearer access token propagation to the downstream services.

テスト

Wiremock

If you configure mp.jwt.verify.publickey.location to point to HTTPS or HTTP-based JsonWebKey (JWK) set, then you can use the same approach as described in the OpenID Connect Bearer Token Integration testing Wiremock section but only change the application.properties to use MP JWT configuration properties instead:

# 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

Keycloak

If you work with Keycloak and configure mp.jwt.verify.publickey.location to point to HTTPS or HTTP-based JsonWebKey (JWK) set, you can use the same approach as described in the OpenID Connect Bearer Token Integration testing Keycloak section but only change the application.properties to use MP JWT configuration properties instead:

# 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 (発行者)クレームに設定されていることに注目してください。

If your Quarkus application runs in a Docker container, it might share a network interface with a Keycloak container started by DevServices for Keycloak. In this scenario, the Quarkus application and Keycloak communicate through an internal shared Docker network.

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

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

ローカル公開鍵

You can use the same approach as described in the OpenID Connect Bearer Token Integration testing Local public key section but only change the application.properties to use MP JWT configuration properties instead:

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

TestSecurity annotation

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

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-test-security-jwt</artifactId>
    <scope>test</scope>
</dependency>
build.gradle
testImplementation("io.quarkus:quarkus-test-security-jwt")

Then, write test code such as this:

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

}

where the ProtectedResource class might look like this:

@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");
    }
}

Note that the @TestSecurity annotation must always be used, and its user property is returned as JsonWebToken.getName() and roles property - as JsonWebToken.getGroups(). @JwtSecurity annotation is optional and can be used to set the additional token claims.

@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 {

    }

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

ログでエラーを確認する方法

トークンの検証または復号化エラーの詳細を確認するには、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

プロアクティブ認証

パブリックエンドポイントメソッド呼び出し時のトークン検証を省略したい場合は、 プロアクティブ認証 を無効にします。

Note that you can’t access the injected JsonWebToken through public methods if token verification has not been done.

How to add SmallRye JWT directly

To parse and verify JsonWebToken with JWTParser, use smallrye-jwt instead of quarkus-smallrye-jwt directly for the following situations:

  • HTTP をサポートしていないQuarkusエクステンション、例えば Quarkus GRPC などを使用している場合。

  • You provide an extension-specific HTTP, the support of which conflicts with the support of those offered by quarkus-smallrye-jwt and Vert.x HTTP, such as Quarkus AWS Lambda.

まず、 smallrye-jwt の依存関係を追加することから始めます:

pom.xml
<dependency>
    <groupId>io.smallrye</groupId>
    <artifactId>smallrye-jwt</artifactId>
</dependency>
build.gradle
implementation("io.smallrye:smallrye-jwt")

Then, update application.properties to get all the CDI producers provided by smallrye-jwt included as follows:

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

設定リファレンス

Quarkus の設定

ビルド時に固定される構成プロパティ - 他のすべての構成プロパティは実行時にオーバーライド可能

Configuration property

デフォルト

The MP-JWT configuration object

Environment variable: QUARKUS_SMALLRYE_JWT_ENABLED

Show more

boolean

true

The name of the java.security.Provider that supports SHA256withRSA signatures

Environment variable: QUARKUS_SMALLRYE_JWT_RSA_SIG_PROVIDER

Show more

string

SunRsaSign

Enable this property if fetching the remote keys can be a time-consuming operation. Do not enable it if you use the local keys.

Environment variable: QUARKUS_SMALLRYE_JWT_BLOCKING_AUTHENTICATION

Show more

boolean

false

Always create HTTP 401 challenge, even for requests containing no authentication credentials. JWT authentication mechanism will return HTTP 401 when an authentication challenge is required. However if it is used alongside one of the interactive authentication mechanisms then returning HTTP 401 to the users accessing the application from a browser may not be desired. If you prefer you can request that JWT authentication mechanism does not create a challenge in such cases by setting this property to 'true'.

Environment variable: QUARKUS_SMALLRYE_JWT_SILENT

Show more

boolean

false

MicroProfile JWT の設定

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

mp.jwt.verify.publickey

none

The mp.jwt.verify.publickey config property allows the public key text to be supplied as a string. The public key is parsed from the supplied string in the order defined in the Supported public key formats section.

mp.jwt.verify.publickey.location

none

Config property allows for a specified external or internal location of the public key. The value can be a relative path or a URL. If the value points to an HTTPS-based JWK set, then, for it to work in native mode, the quarkus.ssl.native property must also be set to true. See Using SSL With Native Executables for more details.

mp.jwt.verify.publickey.algorithm

RS256

List of signature algorithms. Set it to ES256 to support the Elliptic Curve signature algorithm.

mp.jwt.decrypt.key.location

none

Config property allows for a specified external or internal location of the Private Decryption Key.

mp.jwt.decrypt.key.algorithm

RSA-OAEP,RSA-OAEP-256

List of decryption algorithms. Set it to RSA-OAEP-256 to support RSA-OAEP with SHA-256 only.

mp.jwt.verify.issuer

none

Config property specifies the value of the iss (issuer) claim of the JWT that the server accepts as valid.

mp.jwt.verify.audiences

none

Comma-separated list of audiences a token aud claim might contain.

mp.jwt.verify.clock.skew

60

トークンの有効期限と年齢確認時に使用されるクロックスキュー(秒)。トークンの有効期限切れ後、現在時刻がこのプロパティで指定された秒数以内であれば、期限切れのトークンは受理されます。デフォルト値は60秒です。

mp.jwt.verify.token.age

none

トークン発行時刻 iat から経過してはならない秒数です。

mp.jwt.token.header

Authorization

Set this property if another header, such as Cookie, is used to pass the token.

mp.jwt.token.cookie

none

Name of the cookie containing a token. This property is effective only if mp.jwt.token.header is set to Cookie.

追加の SmallRye JWT 設定

SmallRye JWT provides more properties that can be used to customize the token processing:

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

smallrye.jwt.verify.secretkey

none

Secret key supplied as a string.

smallrye.jwt.verify.key.location

NONE

Location of the verification key, which can point to both public and secret keys. Secret keys can only be in the JWK format. Note that 'mp.jwt.verify.publickey.location' is ignored if this property is set.

smallrye.jwt.verify.algorithm

Signature algorithm. This property should only be used to set a symmetric algorithm such as HS256. It is deprecated for setting asymmetric algorithms such as ES256 - use 'mp.jwt.verify.publickey.algorithm' instead.

smallrye.jwt.verify.key-format

ANY

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

smallrye.jwt.verify.key-provider

DEFAULT

By default, PEM, JWK, or JWK key sets can be read from the local file system or fetched from URIs as required by MicroProfile JWT specification. Set this property to AWS_ALB to support an AWS Application Load Balancer verification key resolution.

smallrye.jwt.verify.relax-key-validation

false

Relax the validation of the verification keys; setting this property to true allows public RSA keys with a length of less than 2048 bits.

smallrye.jwt.verify.certificate-thumbprint

false

If this property is enabled, a signed token must contain either 'x5t' or 'x5t#S256' X509Certificate thumbprint headers. Verification keys can only be in JWK or PEM Certificate key formats. JWK keys must have an 'x5c' (Base64-encoded X509Certificate) property set.

smallrye.jwt.token.header

Authorization

Set this property if another header, such as Cookie, is used to pass the token. This property is deprecated - use 'mp.jwt.token.header'.

smallrye.jwt.key-cache-size

100

Key cache size. Use this property and smallrye.jwt.key-cache-time-to-live to control the key cache when a key provider such as AWS_ALB is configured with smallrye.jwt.verify.key-provider=AWS_ALB for resolving the keys dynamically.

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

10

Key cache entry time-to-live in minutes. Use this property and smallrye.jwt.key-cache-size to control the key cache when a key provider such as AWS_ALB is configured with smallrye.jwt.verify.key-provider=AWS_ALB for resolving the keys dynamically.

smallrye.jwt.token.cookie

none

Name of the cookie containing a token. This property is effective only if smallrye.jwt.token.header is set to Cookie. This property is deprecated - use mp.jwt.token.cookie.

smallrye.jwt.always-check-authorization

false

Set this property to true for the Authorization header to be checked even if the smallrye.jwt.token.header is set to Cookie but no cookie with a smallrye.jwt.token.cookie name exists.

smallrye.jwt.token.schemes

Bearer

Comma-separated list containing alternative single or multiple schemes, such as DPoP.

smallrye.jwt.token.kid

none

Key identifier. The verification JWK key and every JWT token must have a matching kid header if it is set.

smallrye.jwt.time-to-live

none

The maximum number of seconds a JWT can be issued for use. Effectively, the difference between the expiration date of the JWT and the issued at date must not exceed this value. Setting this property to a non-positive value relaxes the requirement for the token to have a valid 'iat' (issued at) claim.

smallrye.jwt.require.named-principal

true

If an application relies on java.security.Principal returning a name, then a token must have a upn or preferred_username or sub claim set. Setting this property results in SmallRye JWT throwing an exception if none of these claims is available for the application code to deal with a non-null Principal name reliably.

smallrye.jwt.path.sub

none

Path to the claim containing the subject name. It starts from the top-level JSON object and can contain multiple segments where each segment only represents a JSON object name, for example, ' realms/subject`. This property can be used if a token has no 'sub' claim but has the subject set in a different claim. Use double quotes with the namespace-qualified claims.

smallrye.jwt.claims.sub

none

This property can set a default sub claim value when the current token has no standard or custom sub claim available. Effectively, this property can be used to customize the java.security.Principal name if no upn or preferred_username or sub claim is set.

smallrye.jwt.path.groups

none

Path to the claim containing the groups. It starts from the top-level JSON object and can contain multiple segments where each segment represents a JSON object name only, for example: realm/groups. This property can be used if a token has no 'groups' claim but has the groups set in a different claim. Use double quotes with the namespace-qualified claims.

smallrye.jwt.groups-separator

space

Separator for splitting a string which might contain multiple group values. It is only used if the smallrye.jwt.path.groups property points to a custom claim with a string value. The default value is a single space because a standard OAuth2 scope claim might contain a space-separated sequence.

smallrye.jwt.claims.groups

none

This property can set a default groups claim value when the current token has no standard or custom groups claim available.

smallrye.jwt.jwks.refresh-interval

60

JWK cache refresh interval in minutes. It is ignored unless the mp.jwt.verify.publickey.location points to the HTTP or HTTPS URL-based JWK set and no HTTP Cache-Control response header with a positive max-age parameter value is returned from a JWK HTTPS endpoint.

smallrye.jwt.jwks.forced-refresh-interval

30

Forced JWK cache refresh interval in minutes, which is used to restrict the frequency of the forced refresh attempts that might happen when the token verification fails due to the cache having no JWK key with a kid property matching the current token’s kid header. It is ignored unless the mp.jwt.verify.publickey.location points to the HTTP or HTTPS URL-based JWK set.

smallrye.jwt.expiration.grace

0

Expiration grace in seconds. By default, an expired token is still accepted if the current time is no more than 1 min after the token expiry time. This property is deprecated. Use mp.jwt.verify.clock.skew instead.

smallrye.jwt.verify.aud

none

Comma-separated list of audiences a token aud claim might contain. This property is deprecated - use mp.jwt.verify.audiences.

smallrye.jwt.required.claims

none

Comma-separated list of the claims a token must contain.

smallrye.jwt.decrypt.key.location

none

Config property to specify the external or internal location of Private Decryption Key. This property is deprecated - use 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

Path to TLS trusted certificate which might need to be configured if the keys have to be fetched over HTTPS.

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

This property can be used to customize a keystore type if either mp.jwt.verify.publickey.location or mp.jwt.decrypt.key.location` points to a KeyStore file. If it is not set, the file name is checked to determine the keystore type before defaulting to JKS.

smallrye.jwt.keystore.provider

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

smallrye.jwt.keystore.password

Keystore password. If mp.jwt.verify.publickey.location or mp.jwt.decrypt.key.location, this property must be set.

smallrye.jwt.keystore.verify.key.alias

This property has to be set to identify a public verification key which is extracted from KeyStore from a matching certificate if mp.jwt.verify.publickey.location points to a KeyStore file.

smallrye.jwt.keystore.decrypt.key.alias

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

smallrye.jwt.keystore.decrypt.key.password

This property can be set if a private decryption key’s password in KeyStore is different from smallrye.jwt.keystore.password when mp.jwt.decrypt.key.location points to a KeyStore file.

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

false

Set this property to true to resolve the remote keys at the application startup.

関連コンテンツ