OpenID Connect(OIDC)およびOAuth2クライアントとフィルターリファレンスガイド
このリファレンスガイドは、以下の使用方法について説明しています。
-
quarkus-oidc-client
,quarkus-oidc-client-reactive-filter
andquarkus-oidc-client-filter
extensions to acquire and refresh access tokens from OpenID Connect and OAuth 2.0 compliant Authorization Servers such as Keycloak -
現在の
Bearer
またはAuthorization Code Flow
アクセストークンを伝播するquarkus-oidc-token-propagation-reactive
エクステンションとquarkus-oidc-token-propagation
エクステンション
これらのエクステンションで管理されているアクセストークンをHTTP Authorization ベアラートークンとして使用して、リモートサービスにアクセスすることができます。
OpenID Connect Clientとトークン伝搬クイックスタート も参照してください。
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
パスを追加することによって検出されます。
例えば、この 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' の設定は必要ありません。
トークングラントをサポート
OidcClient
がトークンを取得するために使用できる主なトークングラントは、client_credentials
(デフォルト) と password
グラントです。
クライアントクレデンシャル・グラント
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
パスワード・グラント
OidcClient
が password
グラントを使用するように設定する方法は以下の通りです。
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.
Using OidcClient
to support the authorization code
grant might be required if for some reason you cannot use the Quarkus OIDC extension to support Authorization Code Flow. If there is a very good reason for you to implement Authorization Code Flow then you can configure OidcClient
as follows:
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
メソッドで追加プロパティーの Map を受け取り、現在の code
と redirect_uri
パラメーターを渡して認可コードとトークンを交換することが可能です。
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
}
}
トークンの注入
内部で 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 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
は 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
を作成することもできます。
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
}
}
名前の付いた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 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
を提供します。
It works similarly to the way OidcClientRequestFilter
does (see Use OidcClient in MicroProfile RestClient client filter) - it uses OidcClient
to acquire the access token, refresh it if needed, and set it as an HTTP Authorization
Bearer
scheme value. The difference is that it works with Reactive RestClient and implements a non-blocking client filter which does not block the current IO thread when acquiring or refreshing the tokens.
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
extension provides io.quarkus.oidc.client.filter.OidcClientRequestFilter
Jakarta REST ClientRequestFilter which uses OidcClient
to acquire the access token, refresh it if needed, and set it as an HTTP Authorization
Bearer
scheme value.
デフォルトでは、このフィルタは初期化時に 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();
}
Alternatively, OidcClientRequestFilter
can be registered automatically with all MP Rest or Jakarta REST clients if quarkus.oidc-client-filter.register-filter=true
property is set.
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
プロデューサーがトークンを取得・更新し、カスタムフィルターが何時、どのようにトークンを使用するかを決定します。
You can also inject named Tokens
, see Inject named OidcClient and Tokens
アクセストークンの更新
OidcClientRequestReactiveFilter
、 OidcClientRequestFilter
、 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 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
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
または、クレデンシャルプロバイダー から取得したシークレットを使用します。
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
If you work with Keycloak then you can use the same approach as described in the OpenID Connect Bearer Token Integration testing Keycloak section.
ログでエラーを確認する方法
トークン取得および更新エラーの詳細を確認するには、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
Token Propagation Reactive
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 mechanism, 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
AccessTokenRequestReactiveFilter
は OidcClient
を使用して現在のトークンを交換することに注意してください。また、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
を使用します。名前付きの OidcClient
は quarkus.oidc-token-propagation-reactive.client-name
設定プロパティーで選択することができます。
トークンの伝播
The quarkus-oidc-token-propagation
extension provides two Jakarta REST jakarta.ws.rs.client.ClientRequestFilter
class implementations that simplify the propagation of authentication information. io.quarkus.oidc.token.propagation.AccessTokenRequestFilter
propagates the Bearer token present in the current active request or the token acquired from the Authorization code flow mechanism, as the HTTP Authorization
header’s Bearer
scheme value. The io.quarkus.oidc.token.propagation.JsonWebTokenRequestFilter
provides the same functionality, but in addition provides support for JWT tokens.
コードフローアクセストークンは (ID トークンとは異なり)、現在の Quarkus エンドポイントに伝播され、現在認証されているユーザーに代わってリモートサービスにアクセスすることを意図しているからです。
しかし、エンドツーエンドで直接 Bearer トークンを伝播することは、可能な限り避けるべきです。例えば、Client → Service A → Service B
では、Client
から Service A
に送られたトークンを Service B
が受け取ります。このような場合、Service B
はトークンが Service A
から来たのか、それとも Client
から直接来たのかを区別することができません。Service B
は、トークンが Service A
から来たことを確認するために、新しい発行者とオーディエンスのクレームをアサートする必要があります。
さらに、複雑なアプリケーションでは、トークンを伝搬する前に交換または更新する必要があるかもしれません。例えば、Service A
が Service 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();
}
Alternatively, AccessTokenRequestFilter
can be registered automatically with all MP Rest or Jakarta REST clients if quarkus.oidc-token-propagation.register-filter
property is set to true
and quarkus.oidc-token-propagation.json-web-token
property is set to false
(which is a default value).
伝播前のトークンを交換する
もし、現在のアクセストークンを伝播する前に交換する必要があり、かつ 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
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
AccessTokenRequestFilter
は OidcClient
を使用して現在のトークンを交換することに注意してください。また、quarkus.oidc-client.grant-options.exchange
を使用して OpenID Connect プロバイダーが期待する追加の交換プロパティーを設定できます。
AccessTokenRequestFilter
はデフォルトで OidcClient
を使用します。名前付きの OidcClient
は quarkus.oidc-token-propagation.client-name
設定プロパティーで選択することができます。
RestClient JsonWebTokenRequestFilter
JsonWebTokenRequestFilter
の使用は、Bearer JWT トークンを扱う場合に推奨します。これらのトークンは issuer
や audience
などの claim を変更でき、更新したトークンは再度セキュリティー保護 (例えば、再署名) を受けることができます。これは注入された org.eclipse.microprofile.jwt.JsonWebToken
を想定しているので、不透明なトークンでは動作しません。また、OpenID Connect プロバイダーが Token Exchange プロトコルをサポートしている場合は、代わりに AccessTokenRequestFilter
を使用することを推奨します - JWT と不透明な bearer トークンの両方を AccessTokenRequestFilter
で安全に交換することができます。
JsonWebTokenRequestFilter
により、Service A
の実装は注入された org.eclipse.microprofile.jwt.JsonWebToken
を新しい issuer
と audience
claim 値で更新し、更新したトークンを新しい署名で再度保護することが簡単にできます。唯一の難しいステップは、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();
}
Alternatively, JsonWebTokenRequestFilter
can be registered automatically with all MicroProfile REST or Jakarta REST clients if both quarkus.oidc-token-propagation.register-filter
and quarkus.oidc-token-propagation.json-web-token
properties are set to true
.
伝播前のトークンの更新
注入されたトークンの iss
(issuer) や aud
(audience) の主張を更新して、新しい署名で保護する必要がある場合は、次のように 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 Provider を使用する場合は、AccessTokenRequestFilter
を使用してください。
テスト
You can generate the tokens as described in OpenID Connect Bearer Token Integration testing section. Prepare the REST test endpoints, you can have the test frontend endpoint which uses the injected MP REST client with a registered token propagation filter to invoke on the downstream endpoint, for example, see the integration-tests/oidc-token-propagation
in the main
Quarkus repository.
Token Propagation Reactive
以下の 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
エクステンションは現在、伝播の前にトークンを交換したり放棄することをサポートしていません。しかし、これらの機能は将来的に追加される可能性があります。