Dieser Inhalt ist in der von Ihnen ausgewählten Sprache nicht verfügbar.
Chapter 2. OpenID Connect client and token propagation quickstart
Learn how to use OpenID Connect (OIDC) and OAuth2 clients with filters to get, refresh, and propagate access tokens in your applications.
For more information about OIDC Client
and Token Propagation
support in Quarkus, see the OpenID Connect (OIDC) and OAuth2 client and filters reference guide.
To protect your applications by using Bearer Token Authorization, see the OpenID Connect (OIDC) Bearer token authentication guide.
2.1. Prerequisites Link kopierenLink in die Zwischenablage kopiert!
To complete this guide, you need:
- Roughly 15 minutes
- An IDE
-
JDK 17+ installed with
JAVA_HOME
configured appropriately - Apache Maven 3.8.6 or later
- A working container runtime (Docker or Podman)
- Optionally the Quarkus CLI if you want to use it
- Optionally Mandrel or GraalVM installed and configured appropriately if you want to build a native executable (or Docker if you use a native container build)
- jq tool
2.2. Architecture Link kopierenLink in die Zwischenablage kopiert!
In this example, an application is built with two Jakarta REST resources, FrontendResource
and ProtectedResource
. Here, FrontendResource
uses one of three methods to propagate access tokens to ProtectedResource
:
- It can get a token by using an OIDC client filter before propagating it.
-
It can get a token by using a programmatically created OIDC client and propagate it by passing it to a REST client method as an HTTP
Authorization
header value. - It can use an OIDC token propagation filter to propagate the incoming access token.
FrontendResource
has eight endpoints:
-
/frontend/user-name-with-oidc-client-token
-
/frontend/admin-name-with-oidc-client-token
-
/frontend/user-name-with-oidc-client-token-header-param
-
/frontend/admin-name-with-oidc-client-token-header-param
-
/frontend/user-name-with-oidc-client-token-header-param-blocking
-
/frontend/admin-name-with-oidc-client-token-header-param-blocking
-
/frontend/user-name-with-propagated-token
-
/frontend/admin-name-with-propagated-token
When either /frontend/user-name-with-oidc-client-token
or /frontend/admin-name-with-oidc-client-token
endpoint is called, FrontendResource
uses a REST client with an OIDC client filter to get and propagate an access token to ProtectedResource
. When either /frontend/user-name-with-oidc-client-token-header-param
or /frontend/admin-name-with-oidc-client-token-header-param
endpoint is called, FrontendResource
uses a programmatically created OIDC client to get and propagate an access token to ProtectedResource
by passing it to a REST client method as an HTTP Authorization
header value. When either /frontend/user-name-with-propagated-token
or /frontend/admin-name-with-propagated-token
endpoint is called, FrontendResource
uses a REST client with OIDC Token Propagation Filter
to propagate the current incoming access token to ProtectedResource
.
ProtectedResource
has two endpoints:
-
/protected/user-name
-
/protected/admin-name
Both endpoints return the username extracted from the incoming access token, which was propagated to ProtectedResource
from FrontendResource
. The only difference between these endpoints is that calling /protected/user-name
is only allowed if the current access token has a user
role, and calling /protected/admin-name
is only allowed if the current access token has an admin
role.
2.3. Solution Link kopierenLink in die Zwischenablage kopiert!
We recommend that you follow the instructions in the next sections and create the application step by step. However, you can go right to the completed example.
Clone the Git repository: git clone https://github.com/quarkusio/quarkus-quickstarts.git -b 3.15
, or download an archive.
The solution is in the security-openid-connect-client-quickstart
directory.
2.4. Creating the Maven project Link kopierenLink in die Zwischenablage kopiert!
First, you need a new project. Create a new project with the following command:
Using the Quarkus CLI:
quarkus create app org.acme:security-openid-connect-client-quickstart \ --extension='oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest' \ --no-code cd security-openid-connect-client-quickstart
quarkus create app org.acme:security-openid-connect-client-quickstart \ --extension='oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest' \ --no-code cd security-openid-connect-client-quickstart
Copy to Clipboard Copied! Toggle word wrap Toggle overflow To create a Gradle project, add the
--gradle
or--gradle-kotlin-dsl
option.For more information about how to install and use the Quarkus CLI, see the Quarkus CLI guide.
Using Maven:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow To create a Gradle project, add the
-DbuildTool=gradle
or-DbuildTool=gradle-kotlin-dsl
option.
For Windows users:
-
If using cmd, (don’t use backward slash
\
and put everything on the same line) -
If using Powershell, wrap
-D
parameters in double quotes e.g."-DprojectArtifactId=security-openid-connect-client-quickstart"
It generates a Maven project, importing the oidc
, rest-client-oidc-filter
, rest-client-oidc-token-propagation
, and rest
extensions.
If you already have your Quarkus project configured, you can add these extensions to your project by running the following command in your project base directory:
Using the Quarkus CLI:
quarkus extension add oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest
quarkus extension add oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Using Maven:
./mvnw quarkus:add-extension -Dextensions='oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest'
./mvnw quarkus:add-extension -Dextensions='oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest'
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Using Gradle:
./gradlew addExtension --extensions='oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest'
./gradlew addExtension --extensions='oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest'
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
It adds the following extensions to your build file:
Using Maven:
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Using Gradle:
implementation("io.quarkus:quarkus-oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest")
implementation("io.quarkus:quarkus-oidc,rest-client-oidc-filter,rest-client-oidc-token-propagation,rest")
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
2.5. Writing the application Link kopierenLink in die Zwischenablage kopiert!
Start by implementing ProtectedResource
:
ProtectedResource
returns a name from both userName()
and adminName()
methods. The name is extracted from the current JsonWebToken
.
Next, add the following REST clients:
-
RestClientWithOidcClientFilter
, which uses an OIDC client filter provided by thequarkus-rest-client-oidc-filter
extension to get and propagate an access token. -
RestClientWithTokenHeaderParam
, which accepts a token already acquired by the programmatically created OidcClient as an HTTPAuthorization
header value. -
RestClientWithTokenPropagationFilter
, which uses an OIDC token propagation filter provided by thequarkus-rest-client-oidc-token-propagation
extension to get and propagate an access token.
Add the RestClientWithOidcClientFilter
REST client:
- 1
- Register an OIDC client filter with the REST client to get and propagate the tokens.
Add the RestClientWithTokenHeaderParam
REST client:
Add the RestClientWithTokenPropagationFilter
REST client:
- 1
- Register an OIDC token propagation filter with the REST client to propagate the incoming already-existing tokens.
Do not use the RestClientWithOidcClientFilter
and RestClientWithTokenPropagationFilter
interfaces in the same REST client because they can conflict, leading to issues. For example, the OIDC client filter can override the token from the OIDC token propagation filter, or the propagation filter might not work correctly if it attempts to propagate a token when none is available, expecting the OIDC client filter to obtain a new token instead.
Also, add OidcClientCreator
to create an OIDC client programmatically at startup. OidcClientCreator
supports RestClientWithTokenHeaderParam
REST client calls:
- 1
OidcClients
can be used to retrieve the already initialized, named OIDC clients and create new OIDC clients on demand.
Now, finish creating the application by adding FrontendResource
:
- 1 5 6
FrontendResource
uses the injectedRestClientWithOidcClientFilter
REST client with the OIDC client filter to get and propagate an access token toProtectedResource
when either/frontend/user-name-with-oidc-client-token
or/frontend/admin-name-with-oidc-client-token
is called.- 2 7 8
FrontendResource
uses the injectedRestClientWithTokenPropagationFilter
REST client with the OIDC token propagation filter to propagate the current incoming access token toProtectedResource
when either/frontend/user-name-with-propagated-token
or/frontend/admin-name-with-propagated-token
is called.- 4 9 10
FrontendResource
uses the programmatically created OIDC client to get and propagate an access token toProtectedResource
by passing it directly to the injectedRestClientWithTokenHeaderParam
REST client’s method as an HTTPAuthorization
header value, when either/frontend/user-name-with-oidc-client-token-header-param
or/frontend/admin-name-with-oidc-client-token-header-param
is called.- 11 12
- Sometimes, one may have to acquire tokens in a blocking manner before propagating them with the REST client. This example shows how to acquire the tokens in such cases.
- 3
io.quarkus.oidc.client.runtime.TokensHelper
is a useful tool when OIDC client is used directly, without the OIDC client filter. To useTokensHelper
, pass OIDC Client to it to get the tokens andTokensHelper
acquires the tokens and refreshes them if necessary in a thread-safe way.
Finally, add a Jakarta REST ExceptionMapper
:
This exception mapper is only added to verify during the tests that ProtectedResource
returns 403
when the token has no expected role. Without this mapper, Quarkus REST (formerly RESTEasy Reactive) would correctly convert the exceptions that escape from REST client calls to 500
to avoid leaking the information from the downstream resources such as ProtectedResource
. However, in the tests, it would not be possible to assert that 500
is caused by an authorization exception instead of some internal error.
2.6. Configuring the application Link kopierenLink in die Zwischenablage kopiert!
Having prepared the code, you configure the application:
The preceding configuration references Keycloak, which is used by ProtectedResource
to verify the incoming access tokens and by OidcClient
to get the tokens for a user alice
by using a password
grant. Both REST clients point to ProtectedResource
's HTTP address.
Adding a %prod.
profile prefix to quarkus.oidc.auth-server-url
ensures that Dev Services for Keycloak
launches a container for you when the application is run in dev or test modes. For more information, see the Running the application in dev mode section.
2.7. Starting and configuring the Keycloak server Link kopierenLink in die Zwischenablage kopiert!
Do not start the Keycloak server when you run the application in dev or test modes; Dev Services for Keycloak
launches a container. For more information, see the Running the application in dev mode section. Ensure you put the realm configuration file on the classpath, in the target/classes
directory. This placement ensures that the file is automatically imported in dev mode. However, if you have already built a complete solution, you do not need to add the realm file to the classpath because the build process has already done so.
To start a Keycloak Server, you can use Docker and just run the following command:
docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev
docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev
Set {keycloak.version}
to 25.0.6
or later.
You can access your Keycloak Server at localhost:8180.
Log in as the admin
user to access the Keycloak Administration Console. The password is admin
.
Import the realm configuration file to create a new realm. For more details, see the Keycloak documentation about how to create a new realm.
This quarkus
realm file adds a frontend
client, and alice
and admin
users. alice
has a user
role. admin
has both user
and admin
roles.
2.8. Running the application in dev mode Link kopierenLink in die Zwischenablage kopiert!
To run the application in a dev mode, use:
Using the Quarkus CLI:
quarkus dev
quarkus dev
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Using Maven:
./mvnw quarkus:dev
./mvnw quarkus:dev
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Using Gradle:
./gradlew --console=plain quarkusDev
./gradlew --console=plain quarkusDev
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Dev Services for Keycloak launches a Keycloak container and imports quarkus-realm.json
.
Open a Dev UI available at /q/dev-ui and click a Keycloak provider
link in the OpenID Connect Dev UI card.
When asked, log in to a Single Page Application
provided by the OpenID Connect Dev UI:
Log in as
alice
, with the password,alice
. This user has bothadmin
anduser
roles.-
Access
/frontend/user-name-with-propagated-token
, which returns200
. -
Access
/frontend/admin-name-with-propagated-token
, which returns200
.
-
Access
Log out and back in as
bob
with the password,bob
. This user has auser
role.-
Access
/frontend/user-name-with-propagated-token
, which returns200
. -
Access
/frontend/admin-name-with-propagated-token
, which returns403
.
-
Access
You have tested that FrontendResource
can propagate the access tokens from the OpenID Connect Dev UI.
2.9. Running the application in JVM mode Link kopierenLink in die Zwischenablage kopiert!
After exploring the application in dev mode, you can run it as a standard Java application.
First, compile it:
Using the Quarkus CLI:
quarkus build
quarkus build
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Using Maven:
./mvnw install
./mvnw install
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Using Gradle:
./gradlew build
./gradlew build
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
Then, run it:
java -jar target/quarkus-app/quarkus-run.jar
java -jar target/quarkus-app/quarkus-run.jar
2.10. Running the application in native mode Link kopierenLink in die Zwischenablage kopiert!
You can compile this demo into native code; no modifications are required.
This implies that you no longer need to install a JVM on your production environment, as the runtime technology is included in the produced binary and optimized to run with minimal resources.
Compilation takes longer, so this step is turned off by default. To build again, enable the native
profile:
Using the Quarkus CLI:
quarkus build --native
quarkus build --native
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Using Maven:
./mvnw install -Dnative
./mvnw install -Dnative
Copy to Clipboard Copied! Toggle word wrap Toggle overflow Using Gradle:
./gradlew build -Dquarkus.native.enabled=true
./gradlew build -Dquarkus.native.enabled=true
Copy to Clipboard Copied! Toggle word wrap Toggle overflow
After a little while, when the build finishes, you can run the native binary directly:
./target/security-openid-connect-quickstart-1.0.0-SNAPSHOT-runner
./target/security-openid-connect-quickstart-1.0.0-SNAPSHOT-runner
2.11. Testing the application Link kopierenLink in die Zwischenablage kopiert!
For more information about testing your application in dev mode, see the preceding Running the application in dev mode section.
You can test the application launched in JVM or Native modes with curl
.
Obtain an access token for alice
:
Use this token to call /frontend/user-name-with-propagated-token
. This command returns the 200
status code and the name alice
:
curl -i -X GET \ http://localhost:8080/frontend/user-name-with-propagated-token \ -H "Authorization: Bearer "$access_token
curl -i -X GET \
http://localhost:8080/frontend/user-name-with-propagated-token \
-H "Authorization: Bearer "$access_token
Use the same token to call /frontend/admin-name-with-propagated-token
. In contrast to the preceding command, this command returns 403
because alice
has only a user
role:
curl -i -X GET \ http://localhost:8080/frontend/admin-name-with-propagated-token \ -H "Authorization: Bearer "$access_token
curl -i -X GET \
http://localhost:8080/frontend/admin-name-with-propagated-token \
-H "Authorization: Bearer "$access_token
Next, obtain an access token for admin
:
Use this token to call /frontend/user-name-with-propagated-token
. This command returns a 200
status code and the name admin
:
curl -i -X GET \ http://localhost:8080/frontend/user-name-with-propagated-token \ -H "Authorization: Bearer "$access_token
curl -i -X GET \
http://localhost:8080/frontend/user-name-with-propagated-token \
-H "Authorization: Bearer "$access_token
Use the same token to call /frontend/admin-name-with-propagated-token
. This command also returns the 200
status code and the name admin
because admin
has both user
and admin
roles:
curl -i -X GET \ http://localhost:8080/frontend/admin-name-with-propagated-token \ -H "Authorization: Bearer "$access_token
curl -i -X GET \
http://localhost:8080/frontend/admin-name-with-propagated-token \
-H "Authorization: Bearer "$access_token
Next, check the FrontendResource
methods, which do not propagate the existing tokens but use OidcClient
to get and propagate the tokens. As already shown, OidcClient
is configured to get the tokens for the alice
user.
curl -i -X GET \ http://localhost:8080/frontend/user-name-with-oidc-client-token
curl -i -X GET \
http://localhost:8080/frontend/user-name-with-oidc-client-token
This command returns the 200
status code and the name alice
.
curl -i -X GET \ http://localhost:8080/frontend/admin-name-with-oidc-client-token
curl -i -X GET \
http://localhost:8080/frontend/admin-name-with-oidc-client-token
In contrast with the preceding command, this command returns a 403
status code.
Next, test that the programmatically created OIDC client correctly acquires and propagates the token with RestClientWithTokenHeaderParam
both in reactive and imperative (blocking) modes.
Call the /user-name-with-oidc-client-token-header-param
. This command returns the 200
status code and the name alice
:
curl -i -X GET \ http://localhost:8080/frontend/user-name-with-oidc-client-token-header-param
curl -i -X GET \
http://localhost:8080/frontend/user-name-with-oidc-client-token-header-param
Call the /admin-name-with-oidc-client-token-header-param
. In contrast with the preceding command, this command returns a 403
status code:
curl -i -X GET \ http://localhost:8080/frontend/admin-name-with-oidc-client-token-header-param
curl -i -X GET \
http://localhost:8080/frontend/admin-name-with-oidc-client-token-header-param
Next, test the endpoints which use OIDC client in in the blocking mode.
Call the /user-name-with-oidc-client-token-header-param-blocking
. This command returns the 200
status code and the name alice
:
curl -i -X GET \ http://localhost:8080/frontend/user-name-with-oidc-client-token-header-param-blocking
curl -i -X GET \
http://localhost:8080/frontend/user-name-with-oidc-client-token-header-param-blocking
Call the /admin-name-with-oidc-client-token-header-param-blocking
. In contrast with the preceding command, this command returns a 403
status code:
curl -i -X GET \ http://localhost:8080/frontend/admin-name-with-oidc-client-token-header-param-blocking
curl -i -X GET \
http://localhost:8080/frontend/admin-name-with-oidc-client-token-header-param-blocking