이 콘텐츠는 선택한 언어로 제공되지 않습니다.
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 링크 복사링크가 클립보드에 복사되었습니다!
To complete this guide, you need:
- Roughly 15 minutes
- An IDE
-
JDK 17+ installed with
JAVA_HOMEconfigured appropriately - Apache Maven 3.9.6
- 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 링크 복사링크가 클립보드에 복사되었습니다!
In this example, an application is built with two Jakarta REST resources, FrontendResource and ProtectedResource. Here, FrontendResource uses one of two methods to propagate access tokens to ProtectedResource:
- It can get a token by using an OIDC token propagation Reactive filter before propagating it.
- It can use an OIDC token propagation Reactive filter to propagate the incoming access token.
FrontendResource has four endpoints:
-
/frontend/user-name-with-oidc-client-token -
/frontend/admin-name-with-oidc-client-token -
/frontend/user-name-with-propagated-token -
/frontend/admin-name-with-propagated-token
FrontendResource uses a REST Client with an OIDC token propagation Reactive filter to get and propagate an access token to ProtectedResource when either /frontend/user-name-with-oidc-client-token or /frontend/admin-name-with-oidc-client-token is called. Also, FrontendResource uses a REST Client with OpenID Connect Token Propagation Reactive Filter to propagate the current incoming access token to ProtectedResource when either /frontend/user-name-with-propagated-token or /frontend/admin-name-with-propagated-token is called.
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 링크 복사링크가 클립보드에 복사되었습니다!
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.8, or download an archive.
The solution is in the security-openid-connect-client-quickstart directory.
2.4. Creating the Maven project 링크 복사링크가 클립보드에 복사되었습니다!
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,oidc-client-reactive-filter,oidc-token-propagation-reactive,resteasy-reactive' \ --no-code cd security-openid-connect-client-quickstartquarkus create app org.acme:security-openid-connect-client-quickstart \ --extension='oidc,oidc-client-reactive-filter,oidc-token-propagation-reactive,resteasy-reactive' \ --no-code cd security-openid-connect-client-quickstartCopy to Clipboard Copied! Toggle word wrap Toggle overflow To create a Gradle project, add the
--gradleor--gradle-kotlin-dsloption.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=gradleor-DbuildTool=gradle-kotlin-dsloption.
For Windows users:
-
If using cmd, (don’t use backward slash
\and put everything on the same line) -
If using Powershell, wrap
-Dparameters in double quotes e.g."-DprojectArtifactId=security-openid-connect-client-quickstart"
This command generates a Maven project, importing the oidc, oidc-client-reactive-filter, oidc-token-propagation-reactive-filter, and resteasy-reactive 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,oidc-client-reactive-filter,oidc-token-propagation-reactive,resteasy-reactive
quarkus extension add oidc,oidc-client-reactive-filter,oidc-token-propagation-reactive,resteasy-reactiveCopy to Clipboard Copied! Toggle word wrap Toggle overflow Using Maven:
./mvnw quarkus:add-extension -Dextensions='oidc,oidc-client-reactive-filter,oidc-token-propagation-reactive,resteasy-reactive'
./mvnw quarkus:add-extension -Dextensions='oidc,oidc-client-reactive-filter,oidc-token-propagation-reactive,resteasy-reactive'Copy to Clipboard Copied! Toggle word wrap Toggle overflow Using Gradle:
./gradlew addExtension --extensions='oidc,oidc-client-reactive-filter,oidc-token-propagation-reactive,resteasy-reactive'
./gradlew addExtension --extensions='oidc,oidc-client-reactive-filter,oidc-token-propagation-reactive,resteasy-reactive'Copy to Clipboard Copied! Toggle word wrap Toggle overflow
This command 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,oidc-client-reactive-filter,oidc-token-propagation-reactive,resteasy-reactive")implementation("io.quarkus:quarkus-oidc,oidc-client-reactive-filter,oidc-token-propagation-reactive,resteasy-reactive")Copy to Clipboard Copied! Toggle word wrap Toggle overflow
2.5. Writing the application 링크 복사링크가 클립보드에 복사되었습니다!
Start by implementing ProtectedResource:
ProtectedResource returns a name from both userName() and adminName() methods. The name is extracted from the current JsonWebToken.
Next, add two REST clients, OidcClientRequestReactiveFilter and AccessTokenRequestReactiveFilter, which FrontendResource uses to call ProtectedResource.
Add the OidcClientRequestReactiveFilter REST Client:
The RestClientWithOidcClientFilter interface depends on OidcClientRequestReactiveFilter to get and propagate the tokens.
Add the AccessTokenRequestReactiveFilter REST Client:
The RestClientWithTokenPropagationFilter interface depends on AccessTokenRequestReactiveFilter to propagate the incoming already-existing tokens.
Note that both RestClientWithOidcClientFilter and RestClientWithTokenPropagationFilter interfaces are the same. This is because combining OidcClientRequestReactiveFilter and AccessTokenRequestReactiveFilter on the same REST Client causes side effects because both filters can interfere with each other. For example, OidcClientRequestReactiveFilter can override the token propagated by AccessTokenRequestReactiveFilter, or AccessTokenRequestReactiveFilter can fail if it is called when no token is available to propagate and OidcClientRequestReactiveFilter is expected to get a new token instead.
Now, finish creating the application by adding FrontendResource:
FrontendResource uses REST Client with an OIDC token propagation Reactive filter to get and propagate an access token to ProtectedResource when either /frontend/user-name-with-oidc-client-token or /frontend/admin-name-with-oidc-client-token is called. Also, FrontendResource uses REST Client with OpenID Connect Token Propagation Reactive Filter to propagate the current incoming access token to ProtectedResource when either /frontend/user-name-with-propagated-token or /frontend/admin-name-with-propagated-token is called.
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, 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 링크 복사링크가 클립보드에 복사되었습니다!
Having prepared the code, you configure the application:
This 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 링크 복사링크가 클립보드에 복사되었습니다!
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 24.0.0 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 링크 복사링크가 클립보드에 복사되었습니다!
To run the application in a dev mode, use:
Using the Quarkus CLI:
quarkus dev
quarkus devCopy to Clipboard Copied! Toggle word wrap Toggle overflow Using Maven:
./mvnw quarkus:dev
./mvnw quarkus:devCopy to Clipboard Copied! Toggle word wrap Toggle overflow Using Gradle:
./gradlew --console=plain quarkusDev
./gradlew --console=plain quarkusDevCopy 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 Provider: Keycloak 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 auserrole.-
Access
/frontend/user-name-with-propagated-token, which returns200. -
Access
/frontend/admin-name-with-propagated-token, which returns403.
-
Access
Log out and back in as
adminwith the password,admin. This user has bothadminanduserroles.-
Access
/frontend/user-name-with-propagated-token, which returns200. -
Access
/frontend/admin-name-with-propagated-token, which returns200.
-
Access
In this case, you are testing that FrontendResource can propagate the access tokens from the OpenID Connect Dev UI.
2.9. Running the application in JVM mode 링크 복사링크가 클립보드에 복사되었습니다!
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 buildCopy to Clipboard Copied! Toggle word wrap Toggle overflow Using Maven:
./mvnw install
./mvnw installCopy to Clipboard Copied! Toggle word wrap Toggle overflow Using Gradle:
./gradlew build
./gradlew buildCopy 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 링크 복사링크가 클립보드에 복사되었습니다!
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 --nativeCopy to Clipboard Copied! Toggle word wrap Toggle overflow Using Maven:
./mvnw install -Dnative
./mvnw install -DnativeCopy to Clipboard Copied! Toggle word wrap Toggle overflow Using Gradle:
./gradlew build -Dquarkus.package.type=native
./gradlew build -Dquarkus.package.type=nativeCopy 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 링크 복사링크가 클립보드에 복사되었습니다!
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:
Now, use this token to call /frontend/user-name-with-propagated-token and /frontend/admin-name-with-propagated-token:
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
This command returns the 200 status code and the name alice.
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
In contrast, this command returns 403. Recall that alice only has a user role.
Next, obtain an access token for admin:
Use this token to call /frontend/user-name-with-propagated-token:
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
This command returns a 200 status code and the name admin.
Now, use this token to call /frontend/admin-name-with-propagated-token:
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
This command also returns the 200 status code and the name admin because admin has both user and admin roles.
Now, 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, so:
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.