検索

第7章 OpenID Connect (OIDC) と OAuth2 クライアントおよびフィルター

download PDF

Quarkus エクステンションは、トークンの取得、更新、伝播に重点を置いて、OpenID Connect および OAuth 2.0 アクセストークンの管理に使用できます。

これには、以下のパラメーターが含まれます。

  • quarkus-oidc-clientquarkus-oidc-client-reactive-filter、および quarkus-oidc-client-filter エクステンションを使用して、OpenID Connect および Keycloak などの OAuth 2.0 準拠の認可サーバーからアクセストークンを取得および更新します。
  • quarkus-oidc-token-propagation-reactive および quarkus-oidc-token-propagation エクステンションを使用して、現在の Bearer または Authorization Code Flow アクセストークンを伝播します。

これらのエクステンションによって管理されるアクセストークンは、リモートサービスにアクセスするための HTTP 認証ベアラートークンとして使用できます。

OpenID Connect クライアントとトークンの伝播クイックスタート も参照してください。

7.1. OidcClient

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

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

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

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

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

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

たとえば、次の Keycloak URL があるとします。

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-urlquarkus.oidc-client.discovery-enabled を設定する必要はありません。

7.1.2. サポートされているトークングラント

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

7.1.2.1. クライアントクレデンシャルのグラント

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

7.1.2.2. パスワードグラント

password グラントを使用するように 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=password
quarkus.oidc-client.grant-options.password.username=alice
quarkus.oidc-client.grant-options.password.password=alice

クライアントクレデンシャルのグラントをカスタマイズする方法と同様に、quarkus.oidc-client.grant-options.password 設定接頭辞を使用してさらにカスタマイズできます。

7.1.2.3. その他のグラント

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 メソッドを使用してアクセストークンを取得できます。

複雑なマイクロサービスアプリケーションを構築していて、同じ Bearer トークンが複数のサービスに伝播されて使用されるのを避ける必要がある場合、urn:ietf:params:oauth:grant-type:token-exchange または urn:ietf:params:oauth:grant-type:jwt-bearer グラントの使用が必要になることがあります。詳細は、MicroProfile RestClient Reactive フィルターでのトークンの伝播 および MicroProfile RestClient フィルターでのトークンの伝播 を参照してください。

何らかの理由で、Quarkus OIDC エクステンション を使用して認可コードフローをサポートできない場合は、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 メソッドを使用して、追加プロパティーのマップを受け入れ、現在の coderedirect_uri パラメーターを渡して、トークンの認可コードを交換できます。

OidcClient は、urn:openid:params:grant-type:ciba グラントもサポートします。

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=ciba

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

7.1.2.4. スコープの付与

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

7.1.3. OidcClient の直接使用

次のように OidcClient を直接使用できます。

import jakarta.inject.PostConstruct;
import jakarta.inject.Inject;
import jakarta.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
    }
}

7.1.4. トークンの注入

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

import jakarta.inject.PostConstruct;
import jakarta.inject.Inject;
import jakarta.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 might have been refreshed.
        String accessToken = tokens.getAccessToken();
        // Use the access token to configure MP RestClient Authorization header/etc
    }
}

7.1.5. OidcClients の使用

io.quarkus.oidc.client.OidcClientsOidcClient のコンテナーです。デフォルトの 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 jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.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 マルチテナンシー も使用しており、各 OIDC テナントに独自の関連付けたれた OidcClient がある場合は、Vert.x RoutingContext tenantId 属性を使用できます。以下に例を示します。

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.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 jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.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
    }
}

7.1.6. 名前付き OidcClient とトークンの注入

複数の OidcClient オブジェクトが設定されている場合は、OidcClients を使用する代わりに、追加の修飾子 @NamedOidcClient によって OidcClient 注入ターゲットを指定できます。

package io.quarkus.oidc.client;

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

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

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

    @GET
    public String getResponse() {
        //Use the 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());
    }
}

7.1.7. 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 と同様に機能します (MicroProfile RestClient クライアントフィルターで OidcClient を使用する を参照)。OidcClient を使用してアクセストークンを取得し、必要に応じて更新し、HTTP Authorization Bearer スキーム値として設定します。違いは、Reactive RestClient と連携し、トークンを取得または更新するときに現在の IO スレッドをブロックしない非ブロッキングクライアントフィルターを実装することです。

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

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

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

あるいは、以下のような場合もあります。

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 はデフォルトの OidcClient を使用します。名前付き OidcClient は、quarkus.oidc-client-reactive-filter.client-name 設定プロパティーを使用して選択できます。@OidcClientFilter アノテーションの value 属性を設定して、OidcClient を選択することもできます。アノテーションを通じて設定されたクライアント名は、quarkus.oidc-client-reactive-filter.client-name 設定プロパティーよりも優先されます。たとえば、OIDC クライアント宣言という名前の こちらjwt-secret がある場合、このクライアントを次のように参照できます。

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

7.1.8. 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 エクステンションは、OidcClient を使用してアクセストークンを取得し、必要に応じて更新し、HTTP Authorization Bearer スキーム値として設定する io.quarkus.oidc.client.filter.OidcClientRequestFilter Jakarta REST ClientRequestFilter を提供します。

デフォルトでは、このフィルターは、初期化時に 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();
}

あるいは、以下のような場合もあります。

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 プロパティーが設定されていると、OidcClientRequestFilter はすべての MP Rest または Jakarta REST クライアントに自動的に登録できます。

OidcClientRequestFilter はデフォルトの OidcClient を使用します。名前付き OidcClient は、quarkus.oidc-client-filter.client-name 設定プロパティーを使用して選択できます。@OidcClientFilter アノテーションの value 属性を設定して、OidcClient を選択することもできます。アノテーションを通じて設定されたクライアント名は、quarkus.oidc-client-filter.client-name 設定プロパティーよりも優先されます。たとえば、OIDC クライアント宣言という名前の こちらjwt-secret がある場合、このクライアントを次のように参照できます。

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

7.1.9. カスタム 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 を注入することもできます。名前付きの OidcClient とトークンの注入 を参照してください。

7.1.10. アクセストークンの更新

OidcClientRequestReactiveFilterOidcClientRequestFilter、および Tokens プロデューサーは、更新トークンが利用可能な場合、現在の期限切れのアクセストークンを更新します。さらに、quarkus.oidc-client.refresh-token-time-skew プロパティーを使用して、アクセストークンをプリエンプティブに更新し、HTTP 401 エラーの原因となる可能性のある期限切れに近いアクセストークンの送信を回避することもできます。たとえば、このプロパティーが 3S に設定され、アクセストークンの有効期限が 3 秒未満の場合、このトークンは自動的に更新されます。

アクセストークンを更新する必要があるが、更新トークンが利用できない場合は、client_credentials などの設定された許可を使用して新しいトークンを取得しようとします。

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

7.1.11. アクセストークンの取り消し

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

このトークンを REST クライアントで使用すると HTTP 401 ステータスコードで失敗した場合、またはアクセストークンがすでに長期間使用されていて更新したい場合は、アクセストークンの取り消しが必要になる場合があります。

これは、更新トークンを使用して、トークンの更新をリクエストすることによって実現できます。ただし、更新トークンが利用できない場合は、まず更新トークンを取り消してから新しいアクセストークンを要求することで更新できます。

7.1.12. OidcClient 認証

OidcClient は、client_credentials およびその他の許可要求が成功するために、OpenID Connect Provider に対して認証する必要があります。すべての OIDC クライアント認証 オプションがサポートされています。以下に例を示します。

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

あるいは、以下のような場合もあります。

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 key is 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 that 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 認証方法を使用すると、クライアントシークレットがネットワーク上に送信されなくなります。

7.1.12.1. 追加の JWT 認証オプション

client_secret_jwt または private_key_jwt のいずれかの認証方法を使用する場合は、JWT 署名アルゴリズム、キー識別子、audience、サブジェクト、発行者をカスタマイズできます。次に例を示します。

# 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 that 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 unnecessary.
quarkus.oidc-client.credentials.jwt.token-key-id=mykey

# Use the 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

7.1.12.2. Apple POST JWT

Apple OpenID Connect プロバイダーは client_secret_post メソッドを使用します。ここで、シークレットは 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}

7.1.12.3. 相互 TLS

一部の OpenID Connect Provider では、相互 TLS (mTLS) 認証プロセスの一部としてクライアントが認証されることが要求されます。

quarkus-oidc-client は、mTLS をサポートするために次のように設定できます。

quarkus.oidc-client.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

7.1.13. テスト

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

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

7.1.13.1. Wiremock

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

<dependency>
    <groupId>org.wiremock</groupId>
    <artifactId>wiremock</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 テストエンドポイントを準備します。登録された OidcClient フィルターを使用して挿入された MP REST クライアントを使用するテストフロントエンドエンドポイントで、ダウンストリームエンドポイントを呼び出すことができます。このエンドポイントはトークンをエコーバックします。たとえば、main の Quarkus リポジトリーの integration-tests/oidc-client-wiremock を参照してください。

application.properties を設定します。以下に例を示します。

# Use the '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 アクセストークンが更新されたことが確認されます。

7.1.13.2. Keycloak

Keycloak を使用する場合は、Keycloak の OpenID Connect Bearer トークン結合テスト セクションで説明されているのと同じアプローチを使用できます。

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

トークンの取得と更新エラーの詳細を確認するには、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
Red Hat logoGithubRedditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

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

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

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

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

会社概要

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

© 2024 Red Hat, Inc.