Chapter 1. OpenID Connect (OIDC) and OAuth2 client and filters
You can use Quarkus extensions for OpenID Connect and OAuth 2.0 access token management, focusing on acquiring, refreshing, and propagating tokens.
This includes the following:
-
Using
quarkus-oidc-client,quarkus-oidc-client-reactive-filterandquarkus-oidc-client-filterextensions to acquire and refresh access tokens from OpenID Connect and OAuth 2.0 compliant Authorization Servers such as Keycloak. -
Using
quarkus-oidc-token-propagation-reactiveandquarkus-oidc-token-propagationextensions to propagate the currentBearerorAuthorization Code Flowaccess tokens.
The access tokens managed by these extensions can be used as HTTP Authorization Bearer tokens to access the remote services.
Also see OpenID Connect client and token propagation quickstart.
1.1. OidcClient Copy linkLink copied to clipboard!
Add the following dependency:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-client</artifactId>
</dependency>
The quarkus-oidc-client extension provides a reactive io.quarkus.oidc.client.OidcClient, which can be used to acquire and refresh tokens using SmallRye Mutiny Uni and Vert.x WebClient.
OidcClient is initialized at build time with the IDP token endpoint URL, which can be auto-discovered or manually configured. OidcClient uses this endpoint to acquire access tokens by using token grants such as client_credentials or password and refresh the tokens by using a refresh_token grant.
1.1.1. Token endpoint configuration Copy linkLink copied to clipboard!
By default, the token endpoint address is discovered by adding a /.well-known/openid-configuration path to the configured quarkus.oidc-client.auth-server-url.
For example, given this Keycloak URL:
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus
quarkus.oidc-client.auth-server-url=http://localhost:8180/auth/realms/quarkus
OidcClient will discover that the token endpoint URL is http://localhost:8180/auth/realms/quarkus/protocol/openid-connect/tokens.
Alternatively, if the discovery endpoint is unavailable or you want to save on the discovery endpoint round-trip, you can disable the discovery and configure the token endpoint address with a relative path value. For example:
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
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
A more compact way to configure the token endpoint URL without the discovery is to set quarkus.oidc-client.token-path to an absolute URL:
quarkus.oidc-client.token-path=http://localhost:8180/auth/realms/quarkus/protocol/openid-connect/tokens
quarkus.oidc-client.token-path=http://localhost:8180/auth/realms/quarkus/protocol/openid-connect/tokens
Setting quarkus.oidc-client.auth-server-url and quarkus.oidc-client.discovery-enabled is not required in this case.
1.1.2. Supported token grants Copy linkLink copied to clipboard!
The main token grants that OidcClient can use to acquire the tokens are the client_credentials (default) and password grants.
1.1.2.1. Client credentials grant Copy linkLink copied to clipboard!
Here is how OidcClient can be configured to use the client_credentials grant:
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.auth-server-url=http://localhost:8180/auth/realms/quarkus/
quarkus.oidc-client.client-id=quarkus-app
quarkus.oidc-client.credentials.secret=secret
The client_credentials grant allows setting extra parameters for the token request by using quarkus.oidc-client.grant-options.client.<param-name>=<value>. Here is how to set the intended token recipient by using the audience parameter:
1.1.2.2. Password grant Copy linkLink copied to clipboard!
Here is how OidcClient can be configured to use the password grant:
It can be further customized by using a quarkus.oidc-client.grant-options.password configuration prefix, similar to how the client credentials grant can be customized.
1.1.2.3. Other grants Copy linkLink copied to clipboard!
OidcClient can also help acquire the tokens by using grants that require some extra input parameters that cannot be captured in the configuration. These grants are refresh_token (with the external refresh token), authorization_code, and two grants which can be used to exchange the current access token, namely, urn:ietf:params:oauth:grant-type:token-exchange and urn:ietf:params:oauth:grant-type:jwt-bearer.
If you need to acquire an access token and have posted an existing refresh token to the current Quarkus endpoint, you must use the refresh_token grant. This grant employs an out-of-band refresh token to obtain a new token set. In this case, 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=refresh
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
Then you can use the OidcClient.refreshTokens method with a provided refresh token to get the access token.
Using the urn:ietf:params:oauth:grant-type:token-exchange or urn:ietf:params:oauth:grant-type:jwt-bearer grants might be required if you are building a complex microservices application and want to avoid the same Bearer token be propagated to and used by more than one service. 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
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
Then, you can use the OidcClient.accessTokens method to accept a Map of extra properties and pass the current code and redirect_uri parameters to exchange the authorization code for the tokens.
OidcClient also supports the urn:openid:params:grant-type:ciba grant:
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
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
Then, you can use the OidcClient.accessTokens method to accept a Map of extra properties and pass the auth_req_id parameter to exchange the token authorization code.
1.1.2.4. Grant scopes Copy linkLink copied to clipboard!
You might need to request that a specific set of scopes be associated with an issued access token. Use a dedicated quarkus.oidc-client.scopes list property, for example: quarkus.oidc-client.scopes=email,phone
1.1.3. Use OidcClient directly Copy linkLink copied to clipboard!
One can use OidcClient directly as follows:
1.1.4. Inject tokens Copy linkLink copied to clipboard!
You can inject Tokens that use OidcClient internally. Tokens can be used to acquire the access tokens and refresh them if necessary:
1.1.5. Use OidcClients Copy linkLink copied to clipboard!
io.quarkus.oidc.client.OidcClients is a container of OidcClients - it includes a default OidcClient and named clients which can be configured like this:
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
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
In this case, the default client is disabled with a client-enabled=false property. The jwt-secret client can be accessed like this:
If you also use OIDC multitenancy, and each OIDC tenant has its own associated OidcClient, you can use a Vert.x RoutingContext tenantId attribute. For example:
If you need, you can also create a new OidcClient programmatically like this:
1.1.6. Inject named OidcClient and tokens Copy linkLink copied to clipboard!
In case of multiple configured OidcClient objects, you can specify the OidcClient injection target by the extra qualifier @NamedOidcClient instead of working with OidcClients:
The same qualifier can be used to specify the OidcClient used for a Tokens injection:
1.1.7. Use OidcClient in RestClient Reactive ClientFilter Copy linkLink copied to clipboard!
Add the following Maven Dependency:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-client-reactive-filter</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-client-reactive-filter</artifactId>
</dependency>
Note it will also bring io.quarkus:quarkus-oidc-client.
quarkus-oidc-client-reactive-filter extension provides 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 that does not block the current IO thread when acquiring or refreshing the tokens.
OidcClientRequestReactiveFilter delays an initial token acquisition until it is executed to avoid blocking an IO thread.
You can selectively register OidcClientRequestReactiveFilter by using either io.quarkus.oidc.client.reactive.filter.OidcClientFilter or org.eclipse.microprofile.rest.client.annotation.RegisterProvider annotations:
or
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 the 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:
1.1.8. Use OidcClient in RestClient ClientFilter Copy linkLink copied to clipboard!
Add the following Maven Dependency:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-client-filter</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-client-filter</artifactId>
</dependency>
Note it will also bring 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.
By default, this filter will get OidcClient to acquire the first pair of access and refresh tokens at its initialization time. If the access tokens are short-lived and refresh tokens are unavailable, then the token acquisition should be delayed with quarkus.oidc-client.early-tokens-acquisition=false.
You can selectively register OidcClientRequestFilter by using either io.quarkus.oidc.client.filter.OidcClientFilter or org.eclipse.microprofile.rest.client.annotation.RegisterProvider annotations:
or
Alternatively, OidcClientRequestFilter can be registered automatically with all MP Rest or Jakarta REST clients if the 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 the 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:
1.1.9. Use a custom RestClient ClientFilter Copy linkLink copied to clipboard!
If you prefer, you can use your own custom filter and inject Tokens:
The Tokens producer will acquire and refresh the tokens, and the custom filter will decide how and when to use the token.
You can also inject named Tokens, see Inject named OidcClient and Tokens
1.1.10. Refreshing access tokens Copy linkLink copied to clipboard!
OidcClientRequestReactiveFilter, OidcClientRequestFilter and Tokens producers will refresh the current expired access token if the refresh token is available. Additionally, the quarkus.oidc-client.refresh-token-time-skew property can be used for a preemptive access token refreshment to avoid sending nearly expired access tokens that might cause HTTP 401 errors. For example, if this property is set to 3S and the access token will expire in less than 3 seconds, then this token will be auto-refreshed.
If the access token needs to be refreshed, but no refresh token is available, then an attempt is made to acquire a new token by using a configured grant, such as client_credentials.
Some OpenID Connect Providers will not return a refresh token in a client_credentials grant response. For example, starting from Keycloak 12, a refresh token will not be returned by default for client_credentials. The providers might also restrict the number of times a refresh token can be used.
1.1.11. Revoking access tokens Copy linkLink copied to clipboard!
If your OpenId Connect provider, such as Keycloak, supports a token revocation endpoint, then OidcClient#revokeAccessToken can be used to revoke the current access token. The revocation endpoint URL will be discovered alongside the token request URI or can be configured with quarkus.oidc-client.revoke-path.
You might want to have the access token revoked if using this token with a REST client fails with an HTTP 401 status code or if the access token has already been used for a long time and you would like to refresh it.
This can be achieved by requesting a token refresh by using a refresh token. However, if the refresh token is unavailable, you can refresh it by revoking it first and then requesting a new access token.
1.1.12. OidcClient authentication Copy linkLink copied to clipboard!
OidcClient has to authenticate to the OpenID Connect Provider for the client_credentials and other grant requests to succeed. All the OIDC Client Authentication options are supported, for example:
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.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
quarkus.oidc-client.credentials.client-secret.value=mysecret
Or with the secret retrieved from a CredentialsProvider:
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
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, signature algorithm is 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
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
Or with the secret retrieved from a CredentialsProvider, signature algorithm is HS256:
private_key_jwt with the PEM key file, signature algorithm is 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
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 with the keystore file, signature algorithm is RS256:
Using client_secret_jwt or private_key_jwt authentication methods ensures that no client secret goes over the wire.
1.1.12.1. Additional JWT authentication options Copy linkLink copied to clipboard!
If either client_secret_jwt or private_key_jwt authentication methods are used, then the JWT signature algorithm, key identifier, audience, subject, and issuer can be customized, for example:
1.1.12.2. Apple POST JWT Copy linkLink copied to clipboard!
Apple OpenID Connect Provider uses a client_secret_post method where a secret is a JWT produced with a private_key_jwt authentication method but with Apple account-specific issuer and subject properties.
quarkus-oidc-client supports a non-standard client_secret_post_jwt authentication method, which can be configured as follows:
1.1.12.3. Mutual TLS Copy linkLink copied to clipboard!
Some OpenID Connect Providers require that a client is authenticated as part of the mutual TLS (mTLS) authentication process.
quarkus-oidc-client can be configured as follows to support mTLS:
1.1.13. Testing Copy linkLink copied to clipboard!
Start by adding the following dependencies to your test project:
1.1.13.1. Wiremock Copy linkLink copied to clipboard!
Add the following dependencies to your test project:
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock</artifactId>
<scope>test</scope>
</dependency>
Write a Wiremock-based QuarkusTestResourceLifecycleManager, for example:
Prepare the REST test endpoints. You can have the test front-end endpoint, which uses the injected MP REST client with a registered OidcClient filter, call the downstream endpoint. This endpoint echoes the token back. For example, see the integration-tests/oidc-client-wiremock in the main Quarkus repository.
Set application.properties, for example:
And finally, write the test code. Given the Wiremock-based resource above, the first test invocation should return the access_token_1 access token, which will expire in 4 seconds. Use awaitility to wait for about 5 seconds, and now the next test invocation should return the access_token_2 access token, which confirms the expired access_token_1 access token has been refreshed.
1.1.13.2. Keycloak Copy linkLink copied to clipboard!
If you work with Keycloak, you can use the same approach described in the OpenID Connect Bearer Token Integration testing Keycloak section.
1.1.14. How to check the errors in the logs Copy linkLink copied to clipboard!
Enable io.quarkus.oidc.client.runtime.OidcClientImpl TRACE level logging to see more details about the token acquisition and refresh errors:
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".level=TRACE quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".min-level=TRACE
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".level=TRACE
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientImpl".min-level=TRACE
Enable io.quarkus.oidc.client.runtime.OidcClientRecorder TRACE level logging to see more details about the OidcClient initialization errors:
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientRecorder".level=TRACE quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientRecorder".min-level=TRACE
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientRecorder".level=TRACE
quarkus.log.category."io.quarkus.oidc.client.runtime.OidcClientRecorder".min-level=TRACE
1.2. OIDC request filters Copy linkLink copied to clipboard!
You can filter OIDC requests made by Quarkus to the OIDC provider by registering one or more OidcRequestFilter implementations, which can update or add new request headers. For example, a filter can analyze the request body and add its digest as a new header value:
1.3. Token Propagation Reactive Copy linkLink copied to clipboard!
The quarkus-oidc-token-propagation-reactive extension provides a RestEasy Reactive Client, io.quarkus.oidc.token.propagation.reactive.AccessTokenRequestReactiveFilter, that simplifies the propagation of authentication information. This client propagates the bearer token present in the currently active request or the token acquired from the authorization code flow mechanism as the HTTP Authorization header’s Bearer scheme value.
You can selectively register AccessTokenRequestReactiveFilter by using either io.quarkus.oidc.token.propagation.AccessToken or org.eclipse.microprofile.rest.client.annotation.RegisterProvider annotation, for example:
or
Additionally, AccessTokenRequestReactiveFilter can support a complex application that needs to exchange the tokens before propagating them.
If you work with Keycloak or another OIDC provider that supports a Token Exchange token grant, then you can configure AccessTokenRequestReactiveFilter to exchange the token like this:
- 1
- Please note that the
exchange-tokenconfiguration property is ignored when the OidcClient name is set with theio.quarkus.oidc.token.propagation.AccessToken#exchangeTokenClientannotation attribute.
Note AccessTokenRequestReactiveFilter will use OidcClient to exchange the current token, and you can use quarkus.oidc-client.grant-options.exchange to set the additional exchange properties expected by your OpenID Connect Provider.
If you work with providers such as Azure that require using JWT bearer token grant to exchange the current token, then you can configure AccessTokenRequestReactiveFilter to exchange the token like this:
AccessTokenRequestReactiveFilter uses a default OidcClient by default. A named OidcClient can be selected with a quarkus.oidc-token-propagation-reactive.client-name configuration property or with the io.quarkus.oidc.token.propagation.AccessToken#exchangeTokenClient annotation attribute.
1.4. Token Propagation Copy linkLink copied to clipboard!
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.
When you need to propagate the current Authorization Code Flow access token, then the immediate token propagation will work well - as the code flow access tokens (as opposed to ID tokens) are meant to be propagated for the current Quarkus endpoint to access the remote services on behalf of the currently authenticated user.
However, the direct end-to-end Bearer token propagation should be avoided. For example, Client where Service B receives a token sent by Client to Service A. In such cases, Service B cannot distinguish if the token came from Service A or from Client directly. For Service B to verify the token came from Service A, it should be able to assert a new issuer and audience claims.
Additionally, a complex application might need to exchange or update the tokens before propagating them. For example, the access context might be different when Service A is accessing Service B. In this case, Service A might be granted a narrow or completely different set of scopes to access Service B.
The following sections show how AccessTokenRequestFilter and JsonWebTokenRequestFilter can help.
1.4.1. RestClient AccessTokenRequestFilter Copy linkLink copied to clipboard!
AccessTokenRequestFilter treats all tokens as Strings, and as such, it can work with both JWT and opaque tokens.
You can selectively register AccessTokenRequestFilter by using either io.quarkus.oidc.token.propagation.AccessToken or org.eclipse.microprofile.rest.client.annotation.RegisterProvider, for example:
or
Alternatively, AccessTokenRequestFilter can be registered automatically with all MP Rest or Jakarta REST clients if the 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).
1.4.1.1. Exchange token before propagation Copy linkLink copied to clipboard!
If the current access token needs to be exchanged before propagation and you work with Keycloak or other OpenID Connect Provider which supports a Token Exchange token grant, then you can configure AccessTokenRequestFilter like this:
If you work with providers such as Azure that require using JWT bearer token grant to exchange the current token, then you can configure AccessTokenRequestFilter to exchange the token like this:
Note AccessTokenRequestFilter will use OidcClient to exchange the current token, and you can use quarkus.oidc-client.grant-options.exchange to set the additional exchange properties expected by your OpenID Connect Provider.
AccessTokenRequestFilter uses a default OidcClient by default. A named OidcClient can be selected with a quarkus.oidc-token-propagation.client-name configuration property.
1.4.2. RestClient JsonWebTokenRequestFilter Copy linkLink copied to clipboard!
Using JsonWebTokenRequestFilter is recommended if you work with Bearer JWT tokens where these tokens can have their claims, such as issuer and audience modified and the updated tokens secured (for example, re-signed) again. It expects an injected org.eclipse.microprofile.jwt.JsonWebToken and, therefore, will not work with the opaque tokens. Also, if your OpenID Connect Provider supports a Token Exchange protocol, then it is recommended to use AccessTokenRequestFilter instead - as both JWT and opaque bearer tokens can be securely exchanged with AccessTokenRequestFilter.
JsonWebTokenRequestFilter makes it easy for Service A implementations to update the injected org.eclipse.microprofile.jwt.JsonWebToken with the new issuer and audience claim values and secure the updated token again with a new signature. The only difficult step is ensuring that Service A has a signing key; it should be provisioned from a secure file system or remote secure storage such as Vault.
You can selectively register JsonWebTokenRequestFilter by using either io.quarkus.oidc.token.propagation.JsonWebToken or org.eclipse.microprofile.rest.client.annotation.RegisterProvider, for example:
or
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.
1.4.2.1. Update token before propagation Copy linkLink copied to clipboard!
If the injected token needs to have its iss (issuer) or aud (audience) claims updated and secured again with a new signature, then you can configure JsonWebTokenRequestFilter like this:
As mentioned, use AccessTokenRequestFilter if you work with Keycloak or an OpenID Connect Provider that supports a Token Exchange protocol.
1.4.3. Testing Copy linkLink copied to clipboard!
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 front-end endpoint, which uses the injected MP REST client with a registered token propagation filter, call the downstream endpoint. For example, see the integration-tests/oidc-token-propagation in the main Quarkus repository.
1.5. Token Propagation Reactive Copy linkLink copied to clipboard!
Add the following Maven Dependency:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-token-propagation-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc-token-propagation-reactive</artifactId>
</dependency>
The quarkus-oidc-token-propagation-reactive extension provides io.quarkus.oidc.token.propagation.reactive.AccessTokenRequestReactiveFilter which can be used to propagate the current Bearer or Authorization Code Flow access tokens.
The quarkus-oidc-token-propagation-reactive extension (as opposed to the non-reactive quarkus-oidc-token-propagation extension) does not currently support the exchanging or resigning of the tokens before the propagation. However, these features might be added in the future.