Dev Services and Dev UI for OpenID Connect (OIDC)
You can use Dev Services for Keycloak and the Dev UI for the OpenID Connect (OIDC) Keycloak provider and adapt these services for other OpenID Connect providers. You can also use the Dev UI with OpenID Connect providers that have already been started before you run Quarkus in development mode.
Introdução
Quarkus provides the Dev Services for Keycloak feature, which is enabled by default when the quarkus-oidc
extension is started in dev mode, the integration tests are running in test mode, and when no quarkus.oidc.auth-server-url
property is configured.
The Dev Services for Keycloak feature starts a Keycloak container for both the dev and test modes.
It initializes them by registering the existing Keycloak realm or creating a new realm with the client and users required for you to start developing your Quarkus application secured by Keycloak immediately.
The container restarts when the application.properties
or the realm file changes have been detected.
Additionally, Dev UI available at /q/dev complements this feature with a Dev UI page, which helps to acquire the tokens from Keycloak and test your Quarkus application.
If quarkus.oidc.auth-server-url
is already set, then a generic OpenID Connect Dev Console, which can be used with all OpenID Connect providers, is activated.
For more information, see Dev UI for all OpenID Connect providers.
Dev Services for Keycloak
Start your application without configuring quarkus.oidc
properties in the application.properties
file:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
The console displays output similar to this:
KeyCloak Dev Services Starting:
2021-11-02 17:14:24,864 INFO [org.tes.con.wai.str.HttpWaitStrategy] (build-10) /unruffled_agnesi: Waiting for 60 seconds for URL: http://localhost:32781 (where port 32781 maps to container port 8080)
2021-11-02 17:14:44,170 INFO [io.qua.oid.dep.dev.key.KeycloakDevServicesProcessor] (build-10) Dev Services for Keycloak started.
When logging in to the Keycloak admin console, the username is |
Be aware that Dev Services for Keycloak defaults to not initiating a new container if it detects an existing container labeled quarkus-dev-service-keycloak
.
It connects to this container provided the value of the quarkus.keycloak.devservices.service-name
property matches the label’s value (default quarkus
).
In such cases, expect a slightly altered output when you run the following:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
2021-08-27 18:42:43,530 INFO [io.qua.dev.com.ContainerLocator] (build-15) Dev Services container found: 48fee151a31ddfe32c39965be8f61108587b25ed2f66cdc18bb926d9e2e570c5 (quay.io/keycloak/keycloak:21.0.2). Connecting to: 0.0.0.0:32797.
2021-08-27 18:42:43,600 INFO [io.qua.oid.dep.dev.key.KeycloakDevServicesProcessor] (build-15) Dev Services for Keycloak started.
...
If the Keycloak container is not ready within the default 60-second timeout, you can resolve this by extending the timeout period.
For instance, set it to 2 minutes with |
You can turn off sharing of the containers by specifying quarkus.keycloak.devservices.shared=false
.
Now, open the main Dev UI page and observe the OpenID Connect card linking to a Keycloak page. For example:
Click the Keycloak provider link. This action opens a Keycloak page whose appearance varies depending on how the Dev Services for Keycloak feature is configured.
Developing service applications
By default, the Keycloak page can be used to support the development of a Quarkus OIDC service application.
Authorization code grant
If you set quarkus.oidc.devui.grant.type=code
in the application.properties
file (this is a default value), then an authorization_code
grant is used to acquire both access and ID tokens.
Using this grant is recommended to emulate a typical flow where a single page application (SPA) acquires the tokens and uses them to access Quarkus services.
First, you see an option to Log into Single Page Application. For example:
Choose the Keycloak realm and client ID to use during the authentication process.
This SPA represents a public OpenID Connect client; therefore, the client IDs you enter must identify public Keycloak clients that have no secrets. This is because SPA is not a web application and cannot securely handle the secrets it needs to complete the authorization code flow if the client secret is also expected to complete the authorization code flow. The clients requiring secrets can only be supported with this SPA if a default realm has been created or if |
Next, after selecting Log into Single Page Application, you are redirected to Keycloak to authenticate, for example, as alice:alice
.
Then, you are returned to the page representing the SPA:
You can view the acquired access and ID tokens, for example:
This view shows the encoded JSON Web Token (JWT) token on the left side and highlights the headers in red, payload or claims in green, and signature in blue. It also shows the decoded JWT token on the right side, where you can see the header, claim names, and their values.
Next, test the service by entering a relative service path and sending a token. SPA usually sends access tokens to the application endpoint, so choose the With Access Token option, for example:
To clear the test results area, use the eraser icon in the lower right corner.
Sometimes, ID tokens are forwarded to application frontends as bearer tokens. This helps endpoints identify the user logged into SPA or perform out-of-band token verification. Choose the With ID Token option in such cases.
Manually entering the service paths is not ideal. For information about enabling Swagger or GraphQL UI for testing the service with the access token already acquired by the OIDC Dev UI, see the Test with Swagger UI or GraphQL UI section.
Finally, you can click Log Out image::dev-ui-keycloak-logout.png[alt=Dev UI Keycloak - Log Out,role="center"] so you can authenticate to Keycloak as a different user.
Keycloak might return an error when you try to Log into Single Page Application.
For example, quarkus.oidc.client-id
might not match the client ID in the realm imported to Keycloak, or the client in this realm might not be configured correctly to support the authorization code flow.
In such cases, Keycloak returns an error_description
query parameter, and the Dev UI also shows this error description.
For example:
If the error occurs, log in to Keycloak by using the Keycloak Admin option, update the realm configuration as necessary, and check the application.properties
.
Test with Swagger UI or GraphQL UI
You can avoid manually entering the service paths and test your service with Swagger UI or GraphQL UI if quarkus-smallrye-openapi
or quarkus-smallrye-graphql
are used in your project.
For example, start Quarkus in dev mode with both quarkus-smallrye-openapi
and quarkus-smallrye-graphql
dependencies.
You can see the following options after logging in to Keycloak:
For example, clicking Swagger UI opens the Swagger UI in a new browser tab where you can test the service by using the token acquired by Dev UI for Keycloak.
The Swagger UI does not try to re-authenticate again.
In the Swagger UI, do not choose a Swagger UI Authorize
option; the OIDC Dev UI has authorized and provided the access token for Swagger UI to use for testing.
Integration with GraphQL UI works similarly; the access token acquired by Dev UI for Keycloak is used.
You might need to register a redirect URI for the authorization code flow initiated by Dev UI for Keycloak to work.
This is because Keycloak might enforce that the authenticated users are redirected only to the configured redirect URI.
It is recommended to do this in production to avoid the users being redirected to the wrong endpoints, which might happen if the correct If Keycloak enforces it, you see an authentication error informing you that the In this case, select the Keycloak Admin option in the top right corner, login as If the container is shared between multiple applications running on different ports, you must register You can set the If no custom realm is imported, Dev Services for Keycloak sets the |
Implicit grant
If you set quarkus.oidc.devui.grant.type=implicit
in the application.properties
file, then an implicit
grant is used to acquire both access and ID tokens.
Use this grant to emulate a single page application only if the authorization code grant does not work; for example, when a client is configured in Keycloak to support an implicit grant.
Password grant
If you set quarkus.oidc.devui.grant.type=password
in the application.properties
file, then you see a screen similar to this one:
Select a realm, enter a client ID and secret, user name and password, a relative service endpoint path, and click Test service.
It returns a status code, such as 200
, 403
, 401
, or 404
.
If the username is also set in the quarkus.keycloak.devservices.users
map property containing usernames and passwords, then you do not have to set a password when testing the service.
Be aware that you do not have to initialize quarkus.keycloak.devservices.users
to test the service by using the password
grant.
In the Dev UI console, you can also see output similar to the following:
2021-07-19 17:58:11,407 INFO [io.qua.oid.dep.dev.key.KeycloakDevConsolePostHandler] (security-openid-connect-quickstart-dev.jar) (DEV Console action) Using password grant to get a token from 'http://localhost:32818/realms/quarkus/protocol/openid-connect/token' for user 'alice' in realm 'quarkus' with client id 'quarkus-app'
2021-07-19 17:58:11,533 INFO [io.qua.oid.dep.dev.key.KeycloakDevConsolePostHandler] (security-openid-connect-quickstart-dev.jar) (DEV Console action) Test token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ6Z2tDazJQZ1JaYnVlVG5kcTFKSW1sVnNoZ2hhbWhtbnBNcXU0QUt5MnJBIn0.ey...
2021-07-19 17:58:11,536 INFO [io.qua.oid.dep.dev.key.KeycloakDevConsolePostHandler] (security-openid-connect-quickstart-dev.jar) (DEV Console action) Sending token to 'http://localhost:8080/api/admin'
2021-07-19 17:58:11,674 INFO [io.qua.oid.dep.dev.key.KeycloakDevConsolePostHandler] (security-openid-connect-quickstart-dev.jar) (DEV Console action) Result: 200
A token is acquired from Keycloak by using a password
grant and is sent to the service endpoint.
Client credentials grant
If you set quarkus.oidc.devui.grant.type=client
, then a client_credentials
grant is used to acquire a token, with the page showing no User field in this case:
Select a realm, enter the client ID and secret, a relative service endpoint path, and click Test service.
It returns a status code, such as 200
, 403
, 401
, or 404
.
Developing OpenID Connect web-app applications
To develop a Quarkus OIDC web application, set quarkus.oidc.application-type=web-app
in the application.properties
file before starting the application.
Starting the application displays a screen similar to this one:
Set a relative service endpoint path and click Log in to your web application. You are redirected to Keycloak to enter a username and password in a new browser tab before you get a response from the Quarkus application.
In this case, the Dev UI is not very helpful because the Quarkus OIDC web-app
application controls the authorization code flow and acquires the tokens.
To make Dev UI more helpful in supporting the development of OIDC web-app
applications, consider setting profile-specific values for quarkus.oidc.application-type
:
%prod.quarkus.oidc.application-type=web-app
%test.quarkus.oidc.application-type=web-app
%dev.quarkus.oidc.application-type=service
This profile ensures that all Dev UI options described in Developing service applications are available when your web-app
application is run in dev mode.
The limitation of this approach is that both access and ID tokens returned with the code flow and acquired with Dev UI are sent to the endpoint as HTTP Bearer
tokens - which does not work well if your endpoint requires the injection of IdToken
.
However, it works as expected if your web-app
application only uses the access token, for example, as a source of roles or to get UserInfo
, even if it is assumed to be a service
application in dev mode.
For dev mode, an even better option is to set the application-type
property to hybrid
:
%prod.quarkus.oidc.application-type=web-app
%test.quarkus.oidc.application-type=web-app
%dev.quarkus.oidc.application-type=hybrid
This type ensures that if you access the application from the browser in dev mode without the OIDC Dev UI, Quarkus OIDC also performs the authorization code flow as in the production mode. The OIDC Dev UI is also more beneficial because hybrid applications can also accept the bearer access tokens.
Running the tests
You can run the tests against a Keycloak container started in a test mode in a Continuous Testing mode.
It is also recommended to run the integration tests against Keycloak by using Dev Services for Keycloak. For more information, see Testing OpenID Connect Service Applications with Dev Services and Testing OpenID Connect WebApp Applications with Dev Services.
Keycloak initialization
The quay.io/keycloak/keycloak:25.0.6
image which contains a Keycloak distribution powered by Quarkus is used to start a container by default.
quarkus.keycloak.devservices.image-name
can be used to change the Keycloak image name.
For example, set it to quay.io/keycloak/keycloak:19.0.3-legacy
to use a Keycloak distribution powered by WildFly.
Be aware that a Quarkus-based Keycloak distribution is only available starting from Keycloak 20.0.0
.
Dev Services for Keycloak initializes a launched Keycloak server next.
By default, the quarkus
and quarkus-app
client with a secret
password, alice
and bob
users (with the passwords matching the names), and user
and admin
roles are created, with alice
given both admin
and user
roles and bob
- the user
role.
Usernames, secrets, and their roles can be customized with quarkus.keycloak.devservices.users
(the map which contains usernames and secrets) and quarkus.keycloak.devservices.roles
(the map which contains usernames and comma-separated role values).
For example:
%dev.quarkus.keycloak.devservices.users.duke=dukePassword
%dev.quarkus.keycloak.devservices.roles.duke=reader
%dev.quarkus.keycloak.devservices.users.john=johnPassword
%dev.quarkus.keycloak.devservices.roles.john=reader,writer
This configuration creates two users:
* duke
with a dukePassword
password and a reader
role
* john
with a johnPassword
password and reader
and writer
roles
To customize the client ID and secret, you can use the quarkus.oidc.client-id
and quarkus.oidc.credentials.secret
properties.
However, it is likely that your Keycloak configuration is more complex and requires setting more properties.
This is why quarkus.keycloak.devservices.realm-path
is always checked before initializing Keycloak with the default or configured realm, client, user, and roles properties.
If the realm file exists on the file system or classpath, then only this realm is used to initialize Keycloak, for example:
quarkus.keycloak.devservices.realm-path=quarkus-realm.json
You can use quarkus.keycloak.devservices.realm-path
to initialize Keycloak with multiple realm files by providing a comma-separated list of files:
quarkus.keycloak.devservices.realm-path=quarkus-realm1.json,quarkus-realm2.json
Also, the Keycloak page offers an option to Sign In To Keycloak To Configure Realms
by using a Keycloak Admin option in the right top corner:
Sign in to Keycloak as admin:admin
to further customize the realm properties, create or import a new realm, or export the realm.
You can also copy classpath and file system resources to the container.
For example, if your application configures Keycloak authorization with JavaScript policies that are deployed to Keycloak in a jar file, then you can configure Dev Services for Keycloak
to copy this jar to the Keycloak container as follows:
quarkus.keycloak.devservices.resource-aliases.policies=/policies.jar (1)
quarkus.keycloak.devservices.resource-mappings.policies=/opt/keycloak/providers/policies.jar (2)
1 | policies alias is created for the classpath /policies.jar resource. |
Policy jars can also be located in the file system.
<2> The policies jar is mapped to the /opt/keycloak/providers/policies.jar
container location.
Disable Dev Services for Keycloak
Dev Services for Keycloak is not activated if either quarkus.oidc.auth-server-url
is already initialized or the default OIDC tenant is disabled with quarkus.oidc.tenant.enabled=false
, regardless of whether you work with Keycloak or not.
If you prefer not to have a Dev Services for Keycloak container started or do not work with Keycloak, then you can also disable this feature with quarkus.keycloak.devservices.enabled=false
- it is only necessary if you expect to start quarkus:dev
without quarkus.oidc.auth-server-url
.
The main Dev UI page includes an empty OpenID Connect card when Dev Services for Keycloak is disabled and the quarkus.oidc.auth-server-url
property has not been initialized:
If quarkus.oidc.auth-server-url
is already set, then a generic OpenID Connect Dev Console, which can be used with all OpenID Connect providers, can be activated.
For more information, see the Dev UI for all OpenID Connect providers section.
Dev UI for all OpenID Connect providers
The Dev UI for all OpenID Connect providers is activated if the following conditions are met:
-
The
quarkus.oidc.auth-server-url
points to an already started OpenID Connect provider, which can be Keycloak or other provider. -
The
quarkus.oidc.application-type
is set toservice
, the default value, orhybrid
. -
The
quarkus.oidc.client-id
is set.
Setting quarkus.oidc.credentials.secret
is most likely required for Keycloak and other providers for the authorization code flow initiated from Dev UI to complete unless the client identified with quarkus.oidc.client-id
is configured as a public client in your OpenID Connect provider’s administration console.
For example, you can use Dev UI to test Google authentication with this configuration:
quarkus.oidc.provider=google
quarkus.oidc.application-type=hybrid
quarkus.oidc.client-id=${google-client-id}
quarkus.oidc.credentials.secret=${google-client-secret}
Run:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
This command outputs a message similar to the following example:
...
2021-09-07 15:53:42,697 INFO [io.qua.oid.dep.dev.OidcDevConsoleProcessor] (build-41) OIDC Dev Console: discovering the provider metadata at https://accounts.google.com/.well-known/openid-configuration
...
If the provider metadata discovery has been successful, then after you open the main Dev UI page, you can see the following OpenID Connect card referencing a Google
provider:
Follow the link to log in to your provider, get the tokens, and test the application. The experience is the same as described in the Authorization code grant for Keycloak section, where the Dev Services for Keycloak container has been started, especially if you work with Keycloak.
You likely need to configure your OpenID Connect provider to support redirecting back to the Dev Console
.
You add http://localhost:8080/q/dev-ui/io.quarkus.quarkus-oidc/<providerName>-provider
as one of the supported redirect and logout URLs, where <providerName>
must be replaced by the name of the provider shown in the Dev UI, for example, auth0
.
The Dev UI experience described in the Authorization code grant for Keycloak section might differ slightly if you work with other providers. For example, an access token might not be in JWT format, so it would not be possible to show its internal content. However, all providers should return ID tokens in the JWT format.
The current access token is used by default to test the service with Swagger UI or GrapghQL UI.
If the provider (other than Keycloak) returns a binary access token, then it is used with Swagger UI or GrapghQL UI only if this provider has a token introspection endpoint; otherwise, an |
Some providers, such as Auth0
do not support a standard RP-initiated logout, so the provider-specific logout properties must be configured for a logout option to be visible.
For more information, see User-initiated logout section in the "OpenID Connect authorization code flow mechanism for protecting web applications" guide.
Similarly, if you want to use a password
or client_credentials
grant for Dev UI to acquire the tokens, then you might need to configure some extra provider-specific properties, for example:
quarkus.oidc.devui.grant.type=password
quarkus.oidc.devui.grant-options.password.audience=http://localhost:8080
Non-application root path considerations
This document refers to the http://localhost:8080/q/dev-ui
Dev UI URL in several places where q
is a default non-application root path.
If you customize quarkus.http.root-path
or quarkus.http.non-application-root-path
properties, then replace q
accordingly.
For more information, see the Path resolution in Quarkus blog post.