The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

OpenID Connect (OIDC) および OAuth2 クライアントとフィルターのリファレンスガイド

このリファレンスガイドは、以下の使用方法について説明しています。

  • quarkus-oidc-clientquarkus-oidc-client-reactive-filter、および quarkus-oidc-client-filter エクステンションを使用して、OpenId Connect および Keycloak などの OAuth 2.0 準拠の認可サーバーからアクセストークンを取得し、更新する方法

  • 現在の Bearer または Authorization Code Flow アクセストークンを伝播する quarkus-oidc-token-propagation-reactive エクステンションと quarkus-oidc-token-propagation エクステンション

これらのエクステンションで管理されているアクセストークンをHTTP Authorization Bearerトークンとして使用して、リモートサービスにアクセスすることができます。

OidcClient

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

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-oidc-client</artifactId>
</dependency>

quarkus-oidc-client エクステンションは、SmallRye Mutiny Uni および Vert.xWebClient を使用してトークンを取得および更新するために使用できるリアクティブな io.quarkus.oidc.client.OidcClient を提供します。

OidcClient は自動検出または手動で構成することができる IDP トークンのエンドポイント URL でビルド時に初期化され、このエンドポイントを使用して client_credentials または password トークングラントを使用してアクセストークンを取得し、 refresh_token グラントを使用してトークンを更新します。

トークンエンドポイントの設定

デフォルトでは、トークンのエンドポイントアドレスは、設定された quarkus.oidc-client.auth-server-url/.well-known/openid-configuration パスを追加することによって検出されます。

たとえば、次の KeycloakURL を指定した場合:

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus

OidcClient` は、トークンのエンドポイント URL が http://localhost:8180/auth/realms/quarkus/protocol/openid-connect/tokens であることを検出します。

また、ディスカバリーエンドポイントが利用できない場合や、ディスカバリーエンドポイントのラウンドトリップを節約したい場合は、ディスカバリーを無効にして、相対パス値でトークンエンドポイントアドレスを設定することもできます。例えば:

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus
quarkus.oidc-client.discovery-enabled=false
# Token endpoint: http://localhost:8180/auth/realms/quarkus/protocol/openid-connect/tokens
quarkus.oidc-client.token-path=/protocol/openid-connect/tokens

検出せずにトークンエンドポイント URL を設定するよりコンパクトな方法は、 quarkus.oidc-client.token-path を絶対 URL に設定することです。

quarkus.oidc-client.token-path=http://localhost:8180/auth/realms/quarkus/protocol/openid-connect/tokens

この場合、'quarkus.oidc-client.auth-server-url' および 'quarkus.oidc-client.discovery-enabled' の設定は必要ありません。

サポートされるトークングラント

OidcClient がトークンを取得するために使用できる主なトークングラントは、 client_credentials (デフォルト) と password グラントです。

クライアントクレデンシャル・グラント

OidcClientclient_credentials グラントを使用するように設定する方法は以下の通りです。

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret

client_credentials グラントにより、 quarkus.oidc-client.grant-options.client.<param-name>=<value> を介してトークンリクエストに追加のパラメータを設定できます。 audience パラメータを使用して目的のトークン受信者を設定する方法は次のとおりです。

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret
# 'client' is a shortcut for `client_credentials`
quarkus.oidc-client.grant.type=client
quarkus.oidc-client.grant-options.client.audience=https://example.com/api

パスワード・グラント

OidcClientpassword グラントを使用するように設定する方法は以下の通りです。

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret
quarkus.oidc-client.grant.type=password
quarkus.oidc-client.grant-options.password.username=alice
quarkus.oidc-client.grant-options.password.password=alice

これは、クライアント認証情報のグラントをカスタマイズする方法と同様に、 quarkus.oidc-client.grant-options.password 設定接頭辞を使用してさらにカスタマイズできます。

その他の助成金

OidcClient は設定にはない特別な入力パラメータを必要とするグラントを使用して、トークンの取得を支援することもできます。これらのグラントとは、 refresh_token (外部リフレッシュ・トークン付き)、 authorization_code 、および現在のアクセストークンを交換するために使用できる2つのグラント`urn:ietf:params:oauth:grant-type:token-exchange` および `urn:ietf:params:oauth:grant-type:jwt-bearer`です。

アクセストークンを取得するために、既存のリフレッシュトークンが現在の Quarkus エンドポイントにポストされた場合、帯域外リフレッシュトークンを使用して新しいトークンセットを取得する refresh_token グラントを使用する必要があります。この場合、 OidcClient を次のように設定する必要があります。

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret
quarkus.oidc-client.grant.type=refresh

続いて、提供されたリフレッシュトークンを使って OidcClient.refreshTokens メソッドを使用して、アクセストークンを取得することができます。

Using the urn:ietf:params:oauth:grant-type:token-exchange or urn:ietf:params:oauth:grant-type:jwt-bearer grants may be required if you are building a complex microservices application and would like to avoid the same Bearer token be propagated to and used by more than one service. Please see Token Propagation in MicroProfile RestClient Reactive filter and Token Propagation in MicroProfile RestClient filter for more details.

何らかの理由で Quarkus OpenID Connect extension を使用して認可コードフローをサポートできない場合は、 OidcClient を使用した authorization code グラントのサポートが必要な場合があります。認可コードフローを実装する正当な理由がある場合は、 OidcClient を以下のように設定することができます。

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret
quarkus.oidc-client.grant.type=code

次に、追加のプロパティーのマップを受け入れる OidcClient.accessTokens メソッドを使用し、現在の code パラメーターと redirect_uri パラメーターを渡して、トークンの認可コードを交換できます。

スコープのグラント

スコープの特定のセットが発行されたアクセストークンに関連付けられるように要求する必要がある場合があります。専用の quarkus.oidc-client.scopes リストプロパティーを使用してください (例: quarkus.oidc-client.scopes=email,phone)。

OidcClient を直接使用する

以下のように OidcClient を直接使用することができます。

import javax.inject.PostConstruct;
import javax.inject.Inject;
import javax.ws.rs.GET;

import io.quarkus.oidc.client.OidcClient;
import io.quarkus.oidc.client.Tokens;

@Path("/service")
public class OidcClientResource {

    @Inject
    OidcClient client;

    volatile Tokens currentTokens;

    @PostConstruct
    public void init() {
        currentTokens = client.getTokens().await().indefinitely();
    }

    @GET
    public String getResponse() {

        Tokens tokens = currentTokens;
        if (tokens.isAccessTokenExpired()) {
            // Add @Blocking method annotation if this code is used with Reactive RestClient
            tokens = client.refreshTokens(tokens.getRefreshToken()).await().indefinitely();
            currentTokens = tokens;
        }
        // Use tokens.getAccessToken() to configure MP RestClient Authorization header/etc
    }
}

トークンを注入する

内部で OidcClient を使用する Tokens を注入することができます。 Tokens を使用してアクセストークンを取得し、必要に応じて更新することができます。

import javax.inject.PostConstruct;
import javax.inject.Inject;
import javax.ws.rs.GET;

import io.quarkus.oidc.client.Tokens;

@Path("/service")
public class OidcClientResource {

    @Inject Tokens tokens;

    @GET
    public String getResponse() {
        //  Get the access token which may have been refreshed.
        String accessToken = tokens.getAccessToken();
        // Use the access token to configure MP RestClient Authorization header/etc
    }
}

OidcClientsの使用

io.quarkus.oidc.client.OidcClients は、 OidcClients のコンテナーです。デフォルトの OidcClient と名前付きクライアントを含み、以下のように設定することができます。

quarkus.oidc-client.client-enabled=false

quarkus.oidc-client.jwt-secret.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.jwt-secret.client-id=quarkus-app
quarkus.oidc-client.jwt-secret.credentials.jwt.secret=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow

この場合、デフォルトのクライアントは client-enabled=false プロパティーで無効になっていることに注意してください。 jwt-secret クライアントは以下のようにアクセスできます。

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

import io.quarkus.oidc.client.OidcClient;
import io.quarkus.oidc.client.OidcClients;

@Path("/clients")
public class OidcClientResource {

    @Inject
    OidcClients clients;

    @GET
    public String getResponse() {
        OidcClient client = clients.getClient("jwt-secret");
        // use this client to get the token
    }
}

OIDC multitenancy を使用し、各 OIDC テナントが独自の関連する OidcClient を持っている場合は、Vert.x RoutingContext tenantId 属性を使用することができます。以下に例を示します。

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

import io.quarkus.oidc.client.OidcClient;
import io.quarkus.oidc.client.OidcClients;
import io.vertx.ext.web.RoutingContext;

@Path("/clients")
public class OidcClientResource {

    @Inject
    OidcClients clients;
    @Inject
    RoutingContext context;

    @GET
    public String getResponse() {
        String tenantId = context.get("tenantId");
        // named OIDC tenant and client configurations use the same key:
        OidcClient client = clients.getClient(tenantId);
        // use this client to get the token
    }
}

必要であれば、このようにプログラム的に新しい OidcClient を作成することもできます。

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

import io.quarkus.oidc.client.OidcClient;
import io.quarkus.oidc.client.OidcClients;
import io.quarkus.oidc.client.OidcClientConfig;

import io.smallrye.mutiny.Uni;

@Path("/clients")
public class OidcClientResource {

    @Inject
    OidcClients clients;

    @GET
    public String getResponse() {
        OidcClientConfig cfg = new OidcClientConfig();
        cfg.setId("myclient");
        cfg.setAuthServerUrl("http://localhost:8081/auth/realms/quarkus/");
        cfg.setClientId("quarkus");
        cfg.getCredentials().setSecret("secret");
        Uni<OidcClient> client = clients.newClient(cfg);
        // use this client to get the token
    }
}

名前付き OidcClient とトークンの挿入

複数の設定済みの OidcClients の場合は、 OidcClients で作業する代わりに、追加の修飾子 @NamedOidcClientOidcClient 注入ターゲットを指定できます。

package io.quarkus.oidc.client;

import javax.inject.Inject;
import javax.ws.rs.GET;
import javax.ws.rs.Path;

@Path("/clients")
public class OidcClientResource {

    @Inject
    @NamedOidcClient("jwt-secret")
    OidcClient client;

    @GET
    public String getResponse() {
        // use client to get the token
    }
}

同じ修飾子を使用して、 Tokens インジェクションに使用される OidcClient を指定できます。

@Provider
@Priority(Priorities.AUTHENTICATION)
@RequestScoped
public class OidcClientRequestCustomFilter implements ClientRequestFilter {

    @Inject
    @NamedOidcClient("jwt-secret")
    Tokens tokens;

    @Override
    public void filter(ClientRequestContext requestContext) throws IOException {
        requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, "Bearer " + tokens.getAccessToken());
    }
}

RestClient の Reactive ClientFilter で OidcClient を使用する

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

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-oidc-client-reactive-filter</artifactId>
</dependency>

io.quarkus:quarkus-oidc-client も表示されることに注意してください。

quarkus-oidc-client-reactive-filter エクステンションは、 io.quarkus.oidc.client.filter.OidcClientRequestReactiveFilter を提供します。

これは OidcClientRequestFilter と同じように機能します (Use OidcClient in MicroProfile RestClient client filter を参照) - OidcClient を使用してアクセストークンを取得し、必要に応じてリフレッシュして、HTTP Authorization Bearer スキームの値としてセットします。違いは、Reactive RestClient で機能することと、トークンの取得や更新時に現在の IO スレッドをブロックしないノンブロッキングクライアントフィルターを実装している点です。

IOスレッドのブロックを避けるために、 OidcClientRequestReactiveFilter は実行されるまで最初のトークン取得を遅らせます。

io.quarkus.oidc.client.filter.OidcClientFilter または org.eclipse.microprofile.rest.client.annotation.RegisterProvider アノテーションを使用して OidcClientRequestFilter を選択的に登録することができます。

import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.client.filter.OidcClientFilter;
import io.smallrye.mutiny.Uni;

@RegisterRestClient
@OidcClientFilter
@Path("/")
public interface ProtectedResourceService {

    @GET
    Uni<String> getUserName();
}

or

import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.client.reactive.filter.OidcClientRequestReactiveFilter;
import io.smallrye.mutiny.Uni;

@RegisterRestClient
@RegisterProvider(OidcClientRequestReactiveFilter.class)
@Path("/")
public interface ProtectedResourceService {

    @GET
    Uni<String> getUserName();
}

OidcClientRequestReactiveFilter uses a default OidcClient by default. A named OidcClient can be selected with a quarkus.oidc-client-reactive-filter.client-name configuration property. You can also select OidcClient by setting value attribute of the @OidcClientFilter annotation. The client name set through annotation has higher priority than the quarkus.oidc-client-reactive-filter.client-name configuration property. For example, given this jwt-secret named OIDC client declaration, you can refer to this client like this:

import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.client.filter.OidcClientFilter;
import io.smallrye.mutiny.Uni;

@RegisterRestClient
@OidcClientFilter("jwt-secret")
@Path("/")
public interface ProtectedResourceService {

    @GET
    Uni<String> getUserName();
}

RestClient の ClientFilter で OidcClient を使用する

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

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-oidc-client-filter</artifactId>
</dependency>

io.quarkus:quarkus-oidc-client も表示されることに注意してください。

quarkus-oidc-client-filter エクステンションは io.quarkus.oidc.client.filter.OidcClientRequestFilter JAX-RS ClientRequestFilter を提供します。このフィルターは、 OidcClient を使用してアクセストークンを取得し、必要に応じて更新し、HTTP Authorization Bearer スキーム値として設定します。

デフォルトでは、このフィルタは初期化時に OidcClient を取得してアクセストークンとリフレッシュトークンの最初のペアを取得します。アクセストークンが短命でリフレッシュトークンが利用できない場合は、 quarkus.oidc-client.early-tokens-acquisition=false でトークンの取得を遅延させるべきです。

io.quarkus.oidc.client.filter.OidcClientFilter または org.eclipse.microprofile.rest.client.annotation.RegisterProvider アノテーションを使用して OidcClientRequestFilter を選択的に登録することができます。

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.client.filter.OidcClientFilter;

@RegisterRestClient
@OidcClientFilter
@Path("/")
public interface ProtectedResourceService {

    @GET
    String getUserName();
}

or

import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.client.filter.OidcClientRequestFilter;

@RegisterRestClient
@RegisterProvider(OidcClientRequestFilter.class)
@Path("/")
public interface ProtectedResourceService {

    @GET
    String getUserName();
}

または、 quarkus.oidc-client-filter.register-filter=true プロパティーが設定されている場合、すべての MP Rest または JAX-RS クライアントで OidcClientRequestFilter を自動的に登録することができます。

OidcClientRequestFilter uses a default OidcClient by default. A named OidcClient can be selected with a quarkus.oidc-client-filter.client-name configuration property. You can also select OidcClient by setting value attribute of the @OidcClientFilter annotation. The client name set through annotation has higher priority than the quarkus.oidc-client-filter.client-name configuration property. For example, given this jwt-secret named OIDC client declaration, you can refer to this client like this:

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.client.filter.OidcClientFilter;

@RegisterRestClient
@OidcClientFilter("jwt-secret")
@Path("/")
public interface ProtectedResourceService {

    @GET
    String getUserName();
}

カスタム RestClient ClientFilter の使用

ご希望の場合は、独自のカスタムフィルターを使用して、 Tokens を注入することができます。

import io.quarkus.oidc.client.Tokens;

@Provider
@Priority(Priorities.AUTHENTICATION)
public class OidcClientRequestCustomFilter implements ClientRequestFilter {

    @Inject
    Tokens tokens;

    @Override
    public void filter(ClientRequestContext requestContext) throws IOException {
        requestContext.getHeaders().add(HttpHeaders.AUTHORIZATION, "Bearer " + tokens.getAccessToken());
    }
}

Tokens プロデューサーがトークンを取得・更新し、カスタムフィルターが何時、どのようにトークンを使用するかを決定します。

名前付きの Tokens を挿入することもできます。Inject named OidcClient and Tokens を参照してください。

アクセストークンの更新

OidcClientRequestReactiveFilterOidcClientRequestFilter および Tokens プロデューサーは、リフレッシュトークンが利用可能な場合、現在の期限切れアクセストークンをリフレッシュします。さらに、 quarkus.oidc-client.refresh-token-time-skew プロパティーは、HTTP 401 エラーの原因となる可能性のある期限切れ間近のアクセストークンの送信を避けるために、アクセストークンのリフレッシュを先取りして行うことに使用できます。たとえば、このプロパティーが 3S に設定されていて、アクセストークンが 3 秒以内に期限切れになる場合、このトークンは自動的にリフレッシュされます。

アクセストークンの更新が必要なのにリフレッシュトークンがない場合は、 client_credentials のように設定されたグラントを使って新しいトークンの取得を試みます。

一部の OpenID Connect プロバイダーは、 client_credentials グラントレスポンスでリフレッシュトークンを返さない点にご注意ください。たとえば、Keycloak 12 以降、 client_credentials のリフレッシュトークンはデフォルトでは返されません。また、プロバイダーは、リフレッシュトークンを使用できる回数を制限する場合もあります。

アクセストークンの失効

Keycloak などの OpenId Connect プロバイダがトークンの失効エンドポイントをサポートしている場合、 OidcClient#revokeAccessToken を使うことで現在のアクセストークンを失効させることができます。失効エンドポイントの URL は、トークン要求 URI と共に検出されるか、または quarkus.oidc-client.revoke-path で設定することができます。

RESTクライアントで使用するとHTTP 401 で失敗するアクセストークンを使っている場合や、長い時間使用されているアクセストークンをリフレッシュしたい場合は、アクセストークンを失効させることができます。

リフレッシュトークンを使用してトークンのリフレッシュを要求することができます。リフレッシュトークンが利用できない場合は、まずそれを失効させてから、新しいアクセストークンをリクエストすることでリフレッシュできます。

OidcClient 認証

OidcClient は、 client_credentials および他のグラントリクエストが成功するために OpenID Connect プロバイダーに対して認証する必要があります。 OIDC Client Authentication オプションはすべてサポートされています。以下に例を示します。

client_secret_basic .

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=mysecret

or

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.client-secret.value=mysecret

または、CredentialsProvider: から取得したシークレットを使用します。

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app

# This is a key which will be used to retrieve a secret from the map of credentials returned from CredentialsProvider
quarkus.oidc-client.credentials.client-secret.provider.key=mysecret-key
# Set it only if more than one CredentialsProvider can be registered
quarkus.oidc-client.credentials.client-secret.provider.name=oidc-credentials-provider

client_secret_post:

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.client-secret.value=mysecret
quarkus.oidc-client.credentials.client-secret.method=post

client_secret_jwt、署名アルゴリズムは HS256 です。

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.jwt.secret=AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow

または、CredentialsProvider から取得したシークレットを使用すると、署名アルゴリズムは HS256 になります。

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app

# This is a key which will be used to retrieve a secret from the map of credentials returned from CredentialsProvider
quarkus.oidc-client.credentials.jwt.secret-provider.key=mysecret-key
# Set it only if more than one CredentialsProvider can be registered
quarkus.oidc-client.credentials.jwt.secret-provider.name=oidc-credentials-provider

PEM キーファイルを使用した`private_key_jwt`、署名アルゴリズムは RS256 です。

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.jwt.key-file=privateKey.pem

キーストアファイルを使用した`private_key_jwt`、署名アルゴリズムは RS256 です。

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.jwt.key-store-file=keystore.jks
quarkus.oidc-client.credentials.jwt.key-store-password=mypassword
quarkus.oidc-client.credentials.jwt.key-password=mykeypassword

# Private key alias inside the keystore
quarkus.oidc-client.credentials.jwt.key-id=mykeyAlias

client_secret_jwt または private_key_jwt 認証方法を使用することで、クライアントシークレットが漏れることはありません。

追加の JWT 認証オプション

client_secret_jwt または private_key_jwt のいずれかの認証方法を使用する場合は、JWT 署名アルゴリズム、鍵識別子、オーディエンス、サブジェクト、および発行者をカスタマイズすることができます。以下に例を示します。

# private_key_jwt client authentication

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.jwt.key-file=privateKey.pem

# This is a token key identifier 'kid' header - set it if your OpenID Connect provider requires it.
# Note if the key is represented in a JSON Web Key (JWK) format with a `kid` property then
# using 'quarkus.oidc-client.credentials.jwt.token-key-id' is not necessary.
quarkus.oidc-client.credentials.jwt.token-key-id=mykey

# Use RS512 signature algorithm instead of the default RS256
quarkus.oidc-client.credentials.jwt.signature-algorithm=RS512

# The token endpoint URL is the default audience value, use the base address URL instead:
quarkus.oidc-client.credentials.jwt.audience=${quarkus.oidc-client.auth-server-url}

# custom subject instead of the client id :
quarkus.oidc-client.credentials.jwt.subject=custom-subject

# custom issuer instead of the client id :
quarkus.oidc-client.credentials.jwt.issuer=custom-issuer

Apple POST JWT

Apple OpenID Connect プロバイダーは client_secret_post メソッドを使用します。ここで、secret は private_key_jwt 認証メソッドで生成された JWT ですが、Apple アカウント固有の発行者とサブジェクトプロパティーを使用します。

quarkus-oidc-client は、以下のように設定できる標準外の client_secret_post_jwt 認証方法をサポートしています。

quarkus.oidc-client.auth-server-url=${apple.url}
quarkus.oidc-client.client-id=${apple.client-id}
quarkus.oidc-client.credentials.client-secret.method=post-jwt

quarkus.oidc-client.credentials.jwt.key-file=ecPrivateKey.pem
quarkus.oidc-client.credentials.jwt.signature-algorithm=ES256
quarkus.oidc-client.credentials.jwt.subject=${apple.subject}
quarkus.oidc-client.credentials.jwt.issuer=${apple.issuer}

相互 TLS

OpenID Connect プロバイダーによっては、クライアントが Mutual TLS (mTLS) 認証プロセスの一部として認証されることを要求する場合があります。

mTLS をサポートする為に quarkus-oidc-client は以下のように設定出来ます :

quarkus.oidc.tls.verification=certificate-validation

# Keystore configuration
quarkus.oidc.client.tls.key-store-file=client-keystore.jks
quarkus.oidc.client.tls.key-store-password=${key-store-password}

# Add more keystore properties if needed:
#quarkus.oidc.client.tls.key-store-alias=keyAlias
#quarkus.oidc.client.tls.key-store-alias-password=keyAliasPassword

# Truststore configuration
quarkus.oidc-client.tls.trust-store-file=client-truststore.jks
quarkus.oidc-client.tls.trust-store-password=${trust-store-password}
# Add more truststore properties if needed:
#quarkus.oidc.client.tls.trust-store-alias=certAlias

テスト

テストプロジェクトに以下の依存関係を追加することから始めます。

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-junit5</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.awaitility</groupId>
    <artifactId>awaitility</artifactId>
    <scope>test</scope>
</dependency>

Wiremock

テストプロジェクトに以下の依存関係を追加します。

<dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock-jre8</artifactId>
    <scope>test</scope>
</dependency>

Wiremockベースの QuarkusTestResourceLifecycleManager を例えば以下のように書きます。

package io.quarkus.it.keycloak;

import static com.github.tomakehurst.wiremock.client.WireMock.matching;
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;

import java.util.HashMap;
import java.util.Map;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.Options.ChunkedEncodingPolicy;

import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;

public class KeycloakRealmResourceManager implements QuarkusTestResourceLifecycleManager {
    private WireMockServer server;

    @Override
    public Map<String, String> start() {

        server = new WireMockServer(wireMockConfig().dynamicPort().useChunkedTransferEncoding(ChunkedEncodingPolicy.NEVER));
        server.start();

        server.stubFor(WireMock.post("/tokens")
                .withRequestBody(matching("grant_type=password&username=alice&password=alice"))
                .willReturn(WireMock
                        .aResponse()
                        .withHeader("Content-Type", "application/json")
                        .withBody(
                                "{\"access_token\":\"access_token_1\", \"expires_in\":4, \"refresh_token\":\"refresh_token_1\"}")));
        server.stubFor(WireMock.post("/tokens")
                .withRequestBody(matching("grant_type=refresh_token&refresh_token=refresh_token_1"))
                .willReturn(WireMock
                        .aResponse()
                        .withHeader("Content-Type", "application/json")
                        .withBody(
                                "{\"access_token\":\"access_token_2\", \"expires_in\":4, \"refresh_token\":\"refresh_token_1\"}")));


        Map<String, String> conf = new HashMap<>();
        conf.put("keycloak.url", server.baseUrl());
        return conf;
    }

    @Override
    public synchronized void stop() {
        if (server != null) {
            server.stop();
            server = null;
        }
    }
}

RESTテストエンドポイントを用意します。注入されたMP RESTクライアントを登録されたOidcClientフィルターで使用するテスト用フロントエンドエンドポイントが、トークンをエコーバックするダウンストリームエンドポイントを呼び出すことができます。例として、 main Quarkusリポジトリの integration-tests/oidc-client-wiremock を参照してください。

application.properties を次のように設定します。

# Use 'keycloak.url' property set by the test KeycloakRealmResourceManager
quarkus.oidc-client.auth-server-url=${keycloak.url}
quarkus.oidc-client.discovery-enabled=false
quarkus.oidc-client.token-path=/tokens
quarkus.oidc-client.client-id=quarkus-service-app
quarkus.oidc-client.credentials.secret=secret
quarkus.oidc-client.grant.type=password
quarkus.oidc-client.grant-options.password.username=alice
quarkus.oidc-client.grant-options.password.password=alice

そして最後にテストコードを書きます。上記の Wiremock ベースのリソースがある場合、最初のテスト起動では access_token_1 アクセストークンが返却されますが、このアクセストークンは 4 秒で期限切れになります。 awaitility を使用して約 5 秒間待つと、次のテスト起動時に access_token_2 アクセストークンが返され、期限切れの access_token_1 アクセストークンがリフレッシュされたことが確認できます。

Keycloak

Keycloak を使用する場合は、OpenID Connect Bearer Token 結合テスト Keycloak セクションで説明したのと同じ方法を使用することができます。

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

トークンの取得および更新エラーの詳細を確認するには、 io.quarkus.oidc.client.runtime.OidcClientImpl TRACE レベルのロギングを有効にしてください。

quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".level=TRACE
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".min-level=TRACE

OidcClient 初期化エラーの詳細を確認するには、 io.quarkus.oidc.client.runtime.OidcClientRecorder TRACE レベルのログを有効にしてください。

quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientRecorder".level=TRACE
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientRecorder".min-level=TRACE

トークン伝播リアクティブ

The quarkus-oidc-token-propagation-reactive extension provides RestEasy Reactive Client io.quarkus.oidc.token.propagation.reactive.AccessTokenRequestReactiveFilter that simplifies the propagation of authentication information by propagating the Bearer token present in the current active request or the token acquired from the Authorization Code Flow, as the HTTP Authorization header’s Bearer scheme value.

io.quarkus.oidc.token.propagation.AccessToken または org.eclipse.microprofile.rest.client.annotation.RegisterProvider のいずれかを使用して、 AccessTokenRequestFilter を選択的に登録できます。例:

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.token.propagation.AccessToken;

@RegisterRestClient
@AccessToken
@Path("/")
public interface ProtectedResourceService {

    @GET
    String getUserName();
}

or

import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.token.propagation.reactive.AccessTokenRequestReactiveFilter;

@RegisterRestClient
@RegisterProvider(AccessTokenRequestReactiveFilter.class)
@Path("/")
public interface ProtectedResourceService {

    @GET
    String getUserName();
}

さらに、 AccessTokenRequestReactiveFilter 、トークンを伝播する前に交換する必要がある複雑なアプリケーションをサポートすることができます。

もし、現在のアクセストークンを伝播する前に交換する必要があり、かつ Keycloak やその他の Token Exchange トークングラントをサポートする OpenID Connect Provider で作業する場合は、 AccessTokenRequestFilter をこのように設定することが可能です。

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret
quarkus.oidc-client.grant.type=exchange
quarkus.oidc-client.grant-options.exchange.audience=quarkus-app-exchange

quarkus.oidc-token-propagation.exchange-token=true

AccessTokenRequestReactiveFilterOidcClient を使用して現在のトークンを交換することに注意してください。また、 quarkus.oidc-client.grant-options.exchange を使用して OpenID Connect プロバイダーが期待する追加の交換プロパティーを設定できます。

Azure のように、 JWTベアラートークングラント を使用して現在のトークンを交換する 必要がある プロバイダを使用する場合、 AccessTokenRequestReactiveFilter をトークンを交換するように設定することができます:

quarkus.oidc-client.auth-server-url=${azure.provider.url}
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret

quarkus.oidc-client.grant.type=jwt
quarkus.oidc-client.grant-options.jwt.requested_token_use=on_behalf_of
quarkus.oidc-client.scopes=https://graph.microsoft.com/user.read,offline_access

quarkus.oidc-token-propagation-reactive.exchange-token=true

AccessTokenRequestReactiveFilter はデフォルトでデフォルトの OidcClient を使用します。名前付きの OidcClientquarkus.oidc-token-propagation-reactive.client-name 設定プロパティーで選択することができます。

トークンの伝播

quarkus-oidc-token-propagation エクステンションは、認証情報の伝搬を簡素化する 2 つの JAX-RS javax.ws.rs.client.ClientRequestFilter クラスの実装を提供します。 io.quarkus.oidc.token.propagation.AccessTokenRequestFilter は、現在のアクティブなリクエストに存在する Bearer トークン、または HTTP Authorization ヘッダーの Bearer スキーム値として Authorization Code Flow から取得したトークンを伝播させます。 io.quarkus.oidc.token.propagation.JsonWebTokenRequestFilter は同じ機能を提供しますが、これに加えて JWT トークンのサポートも提供します。

現在の認可コードフローアクセストークンを伝播する必要がある場合は、即時トークン伝播はうまく機能します - コードフローアクセストークン (ID トークンとは対照的に) は、現在認証されているユーザーに代わってリモートサービスにアクセスするように、現在の Quarkus エンドポイントに伝搬されることが意図されています。

ただし、可能であれば、エンドツーエンドのベアラートークンの直接伝播は避ける必要があります。たとえば、 Client → Service A → Service B で、 Service BClient から Service A に送信されたトークンを受け取ります。このような場合、 Service B は、トークンが Service A からのものか、直接 Client からのものかを区別できません。トークンが Service A からのものであることを Service B が確認するには、新しい発行者とオーディエンスのクレームをアサートできる必要があります。

さらに、複雑なアプリケーションでは、トークンを伝搬する前に交換または更新する必要がある場合があります。たとえば、 Service AService B にアクセスするとき、アクセスコンテキストが異なるかもしれません。この場合、 Service A には Service B にアクセスするための狭いスコープまたは完全に異なるスコープのセットがグラントされることがあります。

次のセクションでは、 AccessTokenRequestFilter および JsonWebTokenRequestFilter がどのように役立つかを示します。

RestClient AccessTokenRequestFilter

AccessTokenRequestFilter は、すべてのトークンをStringとして扱うため、JWTトークンと不透明なトークンの両方を扱うことができます。

io.quarkus.oidc.token.propagation.AccessToken または org.eclipse.microprofile.rest.client.annotation.RegisterProvider のいずれかを使用して、 AccessTokenRequestFilter を選択的に登録できます。例:

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.token.propagation.AccessToken;

@RegisterRestClient
@AccessToken
@Path("/")
public interface ProtectedResourceService {

    @GET
    String getUserName();
}

or

import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.token.propagation.AccessTokenRequestFilter;

@RegisterRestClient
@RegisterProvider(AccessTokenRequestFilter.class)
@Path("/")
public interface ProtectedResourceService {

    @GET
    String getUserName();
}

または、 quarkus.oidc-token-propagation.register-filter プロパティが true に設定され、 quarkus.oidc-token-propagation.json-web-token プロパティが false に設定されている場合(デフォルト値です)、すべての MP Rest または JAX-RS クライアントで AccessTokenRequestFilter を自動的に登録することができます。

伝搬前のトークンの交換

もし、現在のアクセストークンを伝搬する前に交換する必要があり、かつ Keycloak または他の Token Exchange トークングラントをサポートする OpenID Connect プロバイダーで作業する場合は、 AccessTokenRequestFilter を以下のように設定することが可能です。

quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret
quarkus.oidc-client.grant.type=exchange
quarkus.oidc-client.grant-options.exchange.audience=quarkus-app-exchange

quarkus.oidc-token-propagation.exchange-token=true

Azure のように、 JWTベアラートークングラント を使用して現在のトークンを交換する 必要がある プロバイダを使用する場合、 AccessTokenRequestFilter のようにトークンを交換するように設定することができます:

quarkus.oidc-client.auth-server-url=${azure.provider.url}
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret

quarkus.oidc-client.grant.type=jwt
quarkus.oidc-client.grant-options.jwt.requested_token_use=on_behalf_of
quarkus.oidc-client.scopes=https://graph.microsoft.com/user.read,offline_access

quarkus.oidc-token-propagation.exchange-token=true

AccessTokenRequestFilterOidcClient を使用して現在のトークンを交換することに注意してください。また、 quarkus.oidc-client.grant-options.exchange を使用して OpenID Connect プロバイダーが期待する追加の交換プロパティーを設定できます。

AccessTokenRequestFilter はデフォルトで OidcClient を使用します。名前付きの OidcClient は、 quarkus.oidc-token-propagation.client-name 設定プロパティーで選択することができます。

RestClient JsonWebTokenRequestFilter

JsonWebTokenRequestFilter の使用は、ベアラー JWT トークンで作業する場合に推奨されます。これらのトークンは issueraudience などのクレームを変更し、更新されたトークンを再度保護 (再署名など) することができます。注入された org.eclipse.microprofile.jwt.JsonWebToken を想定しているため、不透明なトークンでは機能しません。また、OpenID Connect プロバイダーが Token Exchange プロトコルをサポートしている場合は、代わりに AccessTokenRequestFilter を使用することが推奨されます。JWT と不透明なベアラートークンの両方を AccessTokenRequestFilter と安全に交換することができるからです。

JsonWebTokenRequestFilter は、 Service A の実装が、注入された org.eclipse.microprofile.jwt.JsonWebToken を新しい issueraudience のクレーム値で更新し、更新されたトークンを新しい署名で再度保護することを容易にします。唯一の難しいステップは、 Service A に署名鍵を持たせることです。署名鍵は、安全なファイルシステムまたは Vault などのリモートの安全なストレージからプロビジョニングする必要があります。

たとえば、 io.quarkus.oidc.token.propagation.JsonWebToken または org.eclipse.microprofile.rest.client.annotation.RegisterProvider を使用して、 JsonWebTokenRequestFilter を選択的に登録することが可能です。

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.token.propagation.JsonWebToken;

@RegisterRestClient
@JsonWebToken
@Path("/")
public interface ProtectedResourceService {

    @GET
    String getUserName();
}

or

import org.eclipse.microprofile.rest.client.annotation.RegisterProvider;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.quarkus.oidc.token.propagation.JsonWebTokenRequestFilter;

@RegisterRestClient
@RegisterProvider(JsonWebTokenRequestFilter.class)
@Path("/")
public interface ProtectedResourceService {

    @GET
    String getUserName();
}

または、 quarkus.oidc-token-propagation.register-filter プロパティーおよび quarkus.oidc-token-propagation.json-web-token プロパティーの両方が true に設定されている場合、 JsonWebTokenRequestFilter は、すべての MP Rest または JAX-RS クライアントで自動的に登録することができます。

伝搬前のトークンの更新

注入されたトークンの iss (発行者) や aud (オーディエンス) のクレームを更新して、新しい署名で保護する必要がある場合は、 JsonWebTokenRequestFilter を以下のように設定できます。

quarkus.oidc-token-propagation.secure-json-web-token=true
smallrye.jwt.sign.key.location=/privateKey.pem
# Set a new issuer
smallrye.jwt.new-token.issuer=http://frontend-resource
# Set a new audience
smallrye.jwt.new-token.audience=http://downstream-resource
# Override the existing token issuer and audience claims if they are already set
smallrye.jwt.new-token.override-matching-claims=true

前述のように、Token Exchange プロトコルをサポートする Keycloak または OpenID Connect プロバイダーを使用する場合は、 AccessTokenRequestFilter を使用してください。

テスト

OpenID Connect Bearer Token Integration testing のセクションで説明したように、トークンを生成することができます。REST テストエンドポイントを準備します。登録されたトークン伝搬フィルターで注入された MP REST クライアントを使用するテストフロントエンドエンドポイントは、ダウンストリームエンドポイントで呼び出すことができます。たとえば、 main Quarkus リポジトリーの integration-tests/oidc-token-propagation を参照してください。

トークン伝播リアクティブ

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

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-oidc-token-propagation-reactive</artifactId>
</dependency>

quarkus-oidc-token-propagation-reactive エクステンションは、 io.quarkus.oidc.token.propagation.reactive.AccessTokenRequestReactiveFilter を提供します。これは、現在の Bearer または Authorization Code Flow アクセストークンを伝播するために使用することができます。

(非リアクティブの quarkus-oidc-token-propagation エクステンションとは対照的に) quarkus-oidc-token-propagation-reactive エクステンションは現在、伝播の前にトークンを交換したり放棄することをサポートしていません。しかし、これらの機能は将来的に追加される可能性があります。