第7章 OpenID Connect (OIDC) と OAuth2 クライアントおよびフィルター
Quarkus エクステンションは、トークンの取得、更新、伝播に重点を置いて、OpenID Connect および OAuth 2.0 アクセストークンの管理に使用できます。
これには、以下のパラメーターが含まれます。
-
quarkus-oidc-client
、quarkus-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_credentials
や password
などのトークングラントを使用してアクセストークンを取得し、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-url
と quarkus.oidc-client.discovery-enabled
を設定する必要はありません。
7.1.2. サポートされているトークングラント
OidcClient
がトークンを取得するために使用できる主なトークングラントは、client_credentials
グラント (デフォルト) と password
グラントです。
7.1.2.1. クライアントクレデンシャルのグラント
OidcClient
が client_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
メソッドを使用して、追加プロパティーのマップを受け入れ、現在の code
と redirect_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.OidcClients
は OidcClient
のコンテナーです。デフォルトの 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. アクセストークンの更新
OidcClientRequestReactiveFilter
、OidcClientRequestFilter
、および 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