이 콘텐츠는 선택한 언어로 제공되지 않습니다.

Security architecture


Red Hat build of Quarkus 3.8

Red Hat Customer Content Services

Abstract

Quarkus Security architecture delivers versatile authentication mechanisms and customizable security for HTTP applications through the HttpAuthenticationMechanism interface. Explore the range of authentication options tailored to your needs and understand the role of identity providers in verifying user identities and managing access with SecurityIdentity instances. The framework also supports proactive authentication, allowing for customized settings and efficient exception handling in various application contexts.

Providing feedback on Red Hat build of Quarkus documentation

To report an error or to improve our documentation, log in to your Red Hat Jira account and submit an issue. If you do not have a Red Hat Jira account, then you will be prompted to create an account.

Procedure

  1. Click the following link to create a ticket.
  2. Enter a brief description of the issue in the Summary.
  3. Provide a detailed description of the issue or enhancement in the Description. Include a URL to where the issue occurs in the documentation.
  4. Clicking Submit creates and routes the issue to the appropriate documentation team.

Making open source more inclusive

Red Hat is committed to replacing problematic language in our code, documentation, and web properties. We are beginning with these four terms: master, slave, blacklist, and whitelist. Because of the enormity of this endeavor, these changes will be implemented gradually over several upcoming releases. For more details, see our CTO Chris Wright’s message.

Chapter 1. Quarkus Security architecture

The Quarkus Security architecture provides several built-in authentication mechanisms and is highly customizable. The primary mechanism for securing HTTP applications in Quarkus is the HttpAuthenticationMechanism interface.

1.1. Overview of the Quarkus Security architecture

When a client sends an HTTP request, Quarkus Security orchestrates security authentication and authorization by interacting with several built-in core components, including HttpAuthenticationMechanism, IdentityProvider, and SecurityIdentityAugmentor.

The sequential security validation process results in one of three outcomes:

  • The HTTP request gets authenticated and authorized, and access to the Quarkus application gets granted.
  • The HTTP request authentication fails, and the requester receives a challenge specific to the authentication mechanism, for example, a 401 error, a URL redirect to reauthenticate, or some other custom authentication challenge response. For practical examples of challenge responses, see the Quarkus Security Tips and Tricks guide.
  • The HTTP request authorization fails, and the requester gets denied access to the Quarkus application.

The following diagram steps through the detailed process flow of the Quarkus Security architecture:

Figure 1.1. The Quarkus Security architecture and process flow

Quarkus Security architecture process flow

1.2. Core components of the Quarkus Security architecture

1.2.1. HttpAuthenticationMechanism

Quarkus Security uses HttpAuthenticationMechanism to extract the authentication credentials from the HTTP request and delegates them to IdentityProvider to convert the credentials to SecurityIdentity. For example, the credentials can come from the Authorization header, client HTTPS certificates, or cookies.

When Quarkus Security rejects an authentication request, HttpAuthenticationMechanism returns an authentication challenge to the client. The type of challenge depends on the authentication mechanism. For example, with the OIDC OpenID Connect (OIDC) Authorization Code Flow mechanism, a redirect URL gets generated, and the client is returned to the OpenID Connect provider to authenticate.

1.2.2. IdentityProvider

IdentityProvider verifies the authentication credentials and maps them to SecurityIdentity, which has the username, roles, original authentication credentials, and other attributes.

You can inject a SecurityIdentity instance for every authenticated resource to get the authenticated identity information.

In other contexts, it is possible to have other parallel representations of the same information or parts of it, for example, SecurityContext for Jakarta REST or JsonWebToken for JSON Web Tokens (JWT).

For more information, see the Quarkus Identity providers guide.

1.2.3. SecurityIdentityAugmentor

Because Quarkus Security is customizable, you can, for example, add authorization roles to SecurityIdentity and register and prioritize one or more SecurityAugmentor implementations.

Registered instances of SecurityIdentityAugmentor are invoked during the final stage of the security authentication process. For more information, see the Security Identity Customization section of the "Security Tips and Tricks" guide.

1.3. Supported authentication mechanisms

The Quarkus Security framework supports multiple authentication mechanisms, which can also be combined. Some supported authentication mechanisms are built into Quarkus, while others require you to add an extension.

To learn about security authentication in Quarkus and the supported mechanisms and protocols, see the Quarkus Authentication mechanisms in Quarkus guide.

1.4. Proactive authentication

Proactive authentication is enabled in Quarkus by default. The request is always authenticated if an incoming request has a credential, even if the target page does not require authentication. For more information, see the Quarkus Proactive authentication guide.

1.5. Quarkus Security customization

Quarkus Security is customizable. You can customize the following core security components of Quarkus:

  • HttpAuthenticationMechanism
  • IdentityProvider
  • SecurityidentityAugmentor

For more information about customizing Quarkus Security, including reactive security and how to register a security provider, see the Quarkus Security tips and tricks guide.

1.6. References

Chapter 2. Authentication mechanisms in Quarkus

The Quarkus Security framework supports multiple authentication mechanisms, which you can use to secure your applications. You can also combine authentication mechanisms.

Tip

Before you choose an authentication mechanism for securing your Quarkus applications, review the information provided.

2.1. Overview of supported authentication mechanisms

Some supported authentication mechanisms are built into Quarkus, while others require you to add an extension. All of these mechanisms are detailed in the following sections:

The following table maps specific authentication requirements to a supported mechanism that you can use in Quarkus:

Table 2.1. Authentication requirements and mechanisms
Authentication requirementAuthentication mechanism

Username and password

Basic, Form-based authentication

Bearer access token

OIDC Bearer token authentication, JWT

Single sign-on (SSO)

OIDC Code Flow, Form-based authentication

Client certificate

Mutual TLS authentication

For more information, see the following Token authentication mechanism comparison table.

2.2. Built-in authentication mechanisms

Quarkus Security provides the following built-in authentication support:

2.2.1. Basic authentication

You can secure your Quarkus application endpoints with the built-in HTTP Basic authentication mechanism. For more information, see the following documentation:

2.2.2. Form-based authentication

Quarkus provides form-based authentication that works similarly to traditional Servlet form-based authentication. Unlike traditional form authentication, the authenticated user is not stored in an HTTP session because Quarkus does not support clustered HTTP sessions. Instead, the authentication information is stored in an encrypted cookie, which can be read by all cluster members who share the same encryption key.

To apply encryption, add the quarkus.http.auth.session.encryption-key property, and ensure the value you set is at least 16 characters long. The encryption key is hashed by using SHA-256. The resulting digest is used as a key for AES-256 encryption of the cookie value. The cookie contains an expiry time as part of the encrypted value, so all nodes in the cluster must have their clocks synchronized. At one-minute intervals, a new cookie gets generated with an updated expiry time if the session is in use.

With single-page applications (SPA), you typically want to avoid redirects by removing default page paths, as shown in the following example:

# do not redirect, respond with HTTP 200 OK
quarkus.http.auth.form.landing-page=

# do not redirect, respond with HTTP 401 Unauthorized
quarkus.http.auth.form.login-page=
quarkus.http.auth.form.error-page=

# HttpOnly must be false if you want to log out on the client; it can be true if logging out from the server
quarkus.http.auth.form.http-only-cookie=false

Now that you have disabled redirects for the SPA, you must log in and log out programmatically from your client. Below are examples of JavaScript methods for logging into the j_security_check endpoint and logging out of the application by destroying the cookie.

const login = () => {
    // Create an object to represent the form data
    const formData = new URLSearchParams();
    formData.append("j_username", username);
    formData.append("j_password", password);

    // Make an HTTP POST request using fetch against j_security_check endpoint
    fetch("j_security_check", {
        method: "POST",
        body: formData,
        headers: {
            "Content-Type": "application/x-www-form-urlencoded",
        },
    })
    .then((response) => {
        if (response.status === 200) {
            // Authentication was successful
            console.log("Authentication successful");
        } else {
            // Authentication failed
            console.error("Invalid credentials");
        }
    })
    .catch((error) => {
        console.error(error);
    });
};

To log out of the SPA from the client, the cookie must be set to quarkus.http.auth.form.http-only-cookie=false so you can destroy the cookie and possibly redirect back to your main page.

const logout= () => {
    // delete the credential cookie, essentially killing the session
    const removeCookie = `quarkus-credential=; Max-Age=0;path=/`;
    document.cookie = removeCookie;

    // perform post-logout actions here, such as redirecting back to your login page
};

To log out of the SPA from the server, the cookie can be set to quarkus.http.auth.form.http-only-cookie=true and use this example code to destroy the cookie.

@ConfigProperty(name = "quarkus.http.auth.form.cookie-name")
String cookieName;

@Inject
CurrentIdentityAssociation identity;

@POST
public Response logout() {
    if (identity.getIdentity().isAnonymous()) {
        throw new UnauthorizedException("Not authenticated");
    }
    final NewCookie removeCookie = new NewCookie.Builder(cookieName)
            .maxAge(0)
            .expiry(Date.from(Instant.EPOCH))
            .path("/")
            .build();
    return Response.noContent().cookie(removeCookie).build();
}

The following properties can be used to configure form-based authentication:

lock Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

lock quarkus.http.auth.form.enabled

If form authentication is enabled.

Environment variable: QUARKUS_HTTP_AUTH_FORM_ENABLED

boolean

false

lock quarkus.http.auth.form.post-location

The post location.

Environment variable: QUARKUS_HTTP_AUTH_FORM_POST_LOCATION

string

/j_security_check

lock Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

quarkus.http.auth.certificate-role-properties

Properties file containing the client certificate common name (CN) to role mappings. Use it only if the mTLS authentication mechanism is enabled with either quarkus.http.ssl.client-auth=required or quarkus.http.ssl.client-auth=request.

Properties file is expected to have the CN=role1,role,…​,roleN format and should be encoded using UTF-8.

Environment variable: QUARKUS_HTTP_AUTH_CERTIFICATE_ROLE_PROPERTIES

path

 

quarkus.http.auth.realm

The authentication realm

Environment variable: QUARKUS_HTTP_AUTH_REALM

string

 

quarkus.http.auth.form.login-page

The login page. Redirect to login page can be disabled by setting quarkus.http.auth.form.login-page=.

Environment variable: QUARKUS_HTTP_AUTH_FORM_LOGIN_PAGE

string

/login.html

quarkus.http.auth.form.username-parameter

The username field name.

Environment variable: QUARKUS_HTTP_AUTH_FORM_USERNAME_PARAMETER

string

j_username

quarkus.http.auth.form.password-parameter

The password field name.

Environment variable: QUARKUS_HTTP_AUTH_FORM_PASSWORD_PARAMETER

string

j_password

quarkus.http.auth.form.error-page

The error page. Redirect to error page can be disabled by setting quarkus.http.auth.form.error-page=.

Environment variable: QUARKUS_HTTP_AUTH_FORM_ERROR_PAGE

string

/error.html

quarkus.http.auth.form.landing-page

The landing page to redirect to if there is no saved page to redirect back to. Redirect to landing page can be disabled by setting quarkus.http.auth.form.landing-page=.

Environment variable: QUARKUS_HTTP_AUTH_FORM_LANDING_PAGE

string

/index.html

quarkus.http.auth.form.location-cookie

Option to control the name of the cookie used to redirect the user back to the location they want to access.

Environment variable: QUARKUS_HTTP_AUTH_FORM_LOCATION_COOKIE

string

quarkus-redirect-location

quarkus.http.auth.form.timeout

The inactivity (idle) timeout When inactivity timeout is reached, cookie is not renewed and a new login is enforced.

Environment variable: QUARKUS_HTTP_AUTH_FORM_TIMEOUT

Duration question circle

PT30M

quarkus.http.auth.form.new-cookie-interval

How old a cookie can get before it will be replaced with a new cookie with an updated timeout, also referred to as "renewal-timeout". Note that smaller values will result in slightly more server load (as new encrypted cookies will be generated more often); however, larger values affect the inactivity timeout because the timeout is set when a cookie is generated. For example if this is set to 10 minutes, and the inactivity timeout is 30m, if a user’s last request is when the cookie is 9m old then the actual timeout will happen 21m after the last request because the timeout is only refreshed when a new cookie is generated. That is, no timeout is tracked on the server side; the timestamp is encoded and encrypted in the cookie itself, and it is decrypted and parsed with each request.

Environment variable: QUARKUS_HTTP_AUTH_FORM_NEW_COOKIE_INTERVAL

Duration question circle

PT1M

quarkus.http.auth.form.cookie-name

The cookie that is used to store the persistent session

Environment variable: QUARKUS_HTTP_AUTH_FORM_COOKIE_NAME

string

quarkus-credential

quarkus.http.auth.form.cookie-path

The cookie path for the session and location cookies.

Environment variable: QUARKUS_HTTP_AUTH_FORM_COOKIE_PATH

string

/

quarkus.http.auth.form.http-only-cookie

Set the HttpOnly attribute to prevent access to the cookie via JavaScript.

Environment variable: QUARKUS_HTTP_AUTH_FORM_HTTP_ONLY_COOKIE

boolean

false

quarkus.http.auth.form.cookie-same-site

SameSite attribute for the session and location cookies.

Environment variable: QUARKUS_HTTP_AUTH_FORM_COOKIE_SAME_SITE

strict, lax, none

strict

quarkus.http.auth.permission."permissions".enabled

Determines whether the entire permission set is enabled, or not. By default, if the permission set is defined, it is enabled.

Environment variable: QUARKUS_HTTP_AUTH_PERMISSION__PERMISSIONS__ENABLED

boolean

 

quarkus.http.auth.permission."permissions".policy

The HTTP policy that this permission set is linked to. There are three built-in policies: permit, deny and authenticated. Role based policies can be defined, and extensions can add their own policies.

Environment variable: QUARKUS_HTTP_AUTH_PERMISSION__PERMISSIONS__POLICY

string

required exclamation circle

quarkus.http.auth.permission."permissions".methods

The methods that this permission set applies to. If this is not set then they apply to all methods. Note that if a request matches any path from any permission set, but does not match the constraint due to the method not being listed then the request will be denied. Method specific permissions take precedence over matches that do not have any methods set. This means that for example if Quarkus is configured to allow GET and POST requests to /admin to and no other permissions are configured PUT requests to /admin will be denied.

Environment variable: QUARKUS_HTTP_AUTH_PERMISSION__PERMISSIONS__METHODS

list of string

 

quarkus.http.auth.permission."permissions".paths

The paths that this permission check applies to. If the path ends in /* then this is treated as a path prefix, otherwise it is treated as an exact match. Matches are done on a length basis, so the most specific path match takes precedence. If multiple permission sets match the same path then explicit methods matches take precedence over matches without methods set, otherwise the most restrictive permissions are applied.

Environment variable: QUARKUS_HTTP_AUTH_PERMISSION__PERMISSIONS__PATHS

list of string

 

quarkus.http.auth.permission."permissions".auth-mechanism

Path specific authentication mechanism which must be used to authenticate a user. It needs to match HttpCredentialTransport authentication scheme such as 'basic', 'bearer', 'form', etc.

Environment variable: QUARKUS_HTTP_AUTH_PERMISSION__PERMISSIONS__AUTH_MECHANISM

string

 

quarkus.http.auth.permission."permissions".shared

Indicates that this policy always applies to the matched paths in addition to the policy with a winning path. Avoid creating more than one shared policy to minimize the performance impact.

Environment variable: QUARKUS_HTTP_AUTH_PERMISSION__PERMISSIONS__SHARED

boolean

false

quarkus.http.auth.policy."role-policy".roles-allowed

The roles that are allowed to access resources protected by this policy. By default, access is allowed to any authenticated user.

Environment variable: QUARKUS_HTTP_AUTH_POLICY__ROLE_POLICY__ROLES_ALLOWED

list of string

**

quarkus.http.auth.policy."role-policy".roles

Add roles granted to the SecurityIdentity based on the roles that the SecurityIdentity already have. For example, the Quarkus OIDC extension can map roles from the verified JWT access token, and you may want to remap them to a deployment specific roles.

Environment variable: QUARKUS_HTTP_AUTH_POLICY__ROLE_POLICY__ROLES

Map<String,List<String>>

 

quarkus.http.auth.policy."role-policy".permissions

Permissions granted to the SecurityIdentity if this policy is applied successfully (the policy allows request to proceed) and the authenticated request has required role. For example, you can map permission perm1 with actions action1 and action2 to role admin by setting quarkus.http.auth.policy.role-policy1.permissions.admin=perm1:action1,perm1:action2 configuration property. Granted permissions are used for authorization with the @PermissionsAllowed annotation.

Environment variable: QUARKUS_HTTP_AUTH_POLICY__ROLE_POLICY__PERMISSIONS

Map<String,List<String>>

 

quarkus.http.auth.policy."role-policy".permission-class

Permissions granted by this policy will be created with a java.security.Permission implementation specified by this configuration property. The permission class must declare exactly one constructor that accepts permission name (String) or permission name and actions (String, String[]). Permission class must be registered for reflection if you run your application in a native mode.

Environment variable: QUARKUS_HTTP_AUTH_POLICY__ROLE_POLICY__PERMISSION_CLASS

string

io.quarkus.security.StringPermission

About the Duration format

To write duration values, use the standard java.time.Duration format. See the Duration#parse() Java API documentation for more information.

You can also use a simplified format, starting with a number:

  • If the value is only a number, it represents time in seconds.
  • If the value is a number followed by ms, it represents time in milliseconds.

In other cases, the simplified format is translated to the java.time.Duration format for parsing:

  • If the value is a number followed by h, m, or s, it is prefixed with PT.
  • If the value is a number followed by d, it is prefixed with P.

2.2.3. Mutual TLS authentication

Quarkus provides mutual TLS (mTLS) authentication so that you can authenticate users based on their X.509 certificates.

To use this authentication method, you must first enable SSL/TLS for your application. For more information, see the Supporting secure connections with SSL/TLS section of the Quarkus "HTTP reference" guide.

After your application accepts secure connections, the next step is to configure the quarkus.http.ssl.certificate.trust-store-file property with the name of that file that holds all the certificates your application trusts. The specified file also includes information about how your application asks for certificates when a client, such as a browser or other service, tries to access one of its protected resources.

quarkus.http.ssl.certificate.key-store-file=server-keystore.jks            1
quarkus.http.ssl.certificate.key-store-password=the_key_store_secret
quarkus.http.ssl.certificate.trust-store-file=server-truststore.jks        2
quarkus.http.ssl.certificate.trust-store-password=the_trust_store_secret
quarkus.http.ssl.client-auth=required                                      3
quarkus.http.auth.permission.default.paths=/*                              4
quarkus.http.auth.permission.default.policy=authenticated
quarkus.http.insecure-requests=disabled                                    5
1
The keystore where the server’s private key is located.
2
The truststore from which the trusted certificates are loaded.
3
With the value set to required, the server demands client certificates. Set the value to REQUEST to allow the server to accept requests without a certificate. This setting is beneficial when supporting authentication methods besides mTLS.
4
Defines a policy where only authenticated users should have access to resources from your application.
5
You can explicitly disable the plain HTTP protocol, thus requiring all requests to use HTTPS. When you set quarkus.http.ssl.client-auth to required, the system automatically sets quarkus.http.insecure-requests to disabled.

When the incoming request matches a valid certificate in the truststore, your application can obtain the subject by injecting a SecurityIdentity as follows:

Obtaining the subject

@Inject
SecurityIdentity identity;

@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
    return String.format("Hello, %s", identity.getPrincipal().getName());
}

You can also get the certificate by using the code outlined in the following example:

Obtaining the certificate

import java.security.cert.X509Certificate;
import io.quarkus.security.credential.CertificateCredential;

CertificateCredential credential = identity.getCredential(CertificateCredential.class);
X509Certificate certificate = credential.getCertificate();

2.2.3.1. Mapping certificate attributes to roles

The information from the client certificate can be used to add roles to Quarkus SecurityIdentity.

You can add new roles to SecurityIdentity after checking a client certificate’s common name (CN) attribute. The easiest way to add new roles is to use a certificate attribute to role mapping feature.

For example, you can update the properties shown in the section which introduces Mutual TLS authentication as follows:

quarkus.http.ssl.certificate.key-store-file=server-keystore.jks
quarkus.http.ssl.certificate.key-store-password=the_key_store_secret
quarkus.http.ssl.certificate.trust-store-file=server-truststore.jks
quarkus.http.ssl.certificate.trust-store-password=the_trust_store_secret
quarkus.http.ssl.client-auth=required
quarkus.http.insecure-requests=disabled

quarkus.http.auth.certificate-role-properties=cert-role-mappings.properties 1

quarkus.http.auth.permission.certauthenticated.paths=/*   2
quarkus.http.auth.permission.certauthenticated.policy=role-policy-cert 3
quarkus.http.auth.policy.role-policy-cert.roles-allowed=user,admin     4
1
The cert-role-mappings.properties classpath resource contains a map of certificate’s CN values to roles in the form CN=role or CN=role1,role2, etc. Let’s assume it contains three entries: alice=user,admin, bob=user and jdoe=tester.
2 3 4
Use HTTP security policy to require that SecurityIdentity must have either user or admin roles for the requests to be authorized.

Given the preceeding configuration, the request is authorized if the client certificate’s CN attribute is equal to alice or bob and forbidden if it is equal to jdoe.

2.2.3.2. Using certificate attributes to augment SecurityIdentity

You can always register SecurityIdentityAugmentor if the automatic Mapping certificate attributes to roles option does not suit. Custom SecurityIdentityAugmentor can check the values of different client certificate attributes and augment the SecurityIdentity accordingly.

For more information about customizing SecurityIdentity, see the Security identity customization section in the Quarkus "Security tips and tricks" guide.

2.3. Other supported authentication mechanisms

Quarkus Security also supports the following authentication mechanisms through extensions:

2.3.1. OpenID Connect authentication

OpenID Connect (OIDC) is an identity layer that works on top of the OAuth 2.0 protocol. OIDC enables client applications to verify the identity of a user based on the authentication performed by the OIDC provider and retrieve basic information about that user.

The Quarkus quarkus-oidc extension provides a reactive, interoperable, multitenant-enabled OIDC adapter that supports Bearer token and Authorization Code Flow authentication mechanisms. The Bearer token authentication mechanism extracts the token from the HTTP Authorization header.

The Authorization Code Flow mechanism redirects the user to an OIDC provider to authenticate the user’s identity. After the user is redirected back to Quarkus, the mechanism completes the authentication process by exchanging the provided code that was granted for the ID, access, and refresh tokens.

You can verify ID and access JSON Web Token (JWT) tokens by using the refreshable JSON Web Key (JWK) set or introspect them remotely. However, opaque, also known as binary tokens, can only be introspected remotely.

Note

Using the Quarkus OIDC extension, both the Bearer token and Authorization Code Flow authentication mechanisms use SmallRye JWT authentication to represent JWT tokens as MicroProfile JWT org.eclipse.microprofile.jwt.JsonWebToken.

2.3.1.1. Additional Quarkus resources for OIDC authentication

For more information about OIDC authentication and authorization methods that you can use to secure your Quarkus applications, see the following resources:

OIDC topicQuarkus information resource

Bearer token authentication mechanism

OIDC Bearer token authentication

Authorization Code Flow authentication mechanism

OpenID Connect (OIDC) Authorization Code Flow mechanism

OIDC and SAML Identity broker

OpenID Connect (OIDC) Authorization Code Flow and SAML Identity broker

Multiple tenants that can support the Bearer token authentication or Authorization Code Flow mechanisms

Using OpenID Connect (OIDC) multi-tenancy

Securing Quarkus with commonly used OpenID Connect providers

Configuring well-known OpenID Connect providers

Using Keycloak to centralize authorization

Using OpenID Connect (OIDC) and Keycloak to centralize authorization

Note

To enable the Quarkus OIDC extension at runtime, set quarkus.oidc.tenant-enabled=false at build time. Then, re-enable it at runtime by using a system property.

For more information about managing the individual tenant configurations in multitenant OIDC deployments, see the Disabling tenant configurations section in the "Using OpenID Connect (OIDC) multi-tenancy" guide.

2.3.1.2. OpenID Connect client and filters

The quarkus-oidc-client extension provides OidcClient for acquiring and refreshing access tokens from OpenID Connect and OAuth2 providers that support the following token grants:

  • client-credentials
  • password
  • refresh_token

The quarkus-oidc-client-filter extension requires the quarkus-oidc-client extension. It provides JAX-RS RESTful Web Services OidcClientRequestFilter, which sets the access token acquired by OidcClient as the Bearer scheme value of the HTTP Authorization header. This filter can be registered with MicroProfile REST client implementations injected into the current Quarkus endpoint, but it is not related to the authentication requirements of this service endpoint. For example, it can be a public endpoint or be protected with mTLS.

Important

In this scenario, you do not need to protect your Quarkus endpoint by using the Quarkus OpenID Connect adapter.

The quarkus-oidc-token-propagation extension requires the quarkus-oidc extension. It provides Jakarta REST TokenCredentialRequestFilter, which sets the OpenID Connect Bearer token or Authorization Code Flow access token as the Bearer scheme value of the HTTP Authorization header. This filter can be registered with MicroProfile REST client implementations injected into the current Quarkus endpoint, which must be protected by using the Quarkus OIDC adapter. This filter can propagate the access token to the downstream services.

For more information, see the OpenID Connect client and token propagation quickstart and OpenID Connect (OIDC) and OAuth2 client and filters reference guides.

2.3.2. SmallRye JWT authentication

The quarkus-smallrye-jwt extension provides a MicroProfile JSON Web Token (JWT) 2.1 implementation and multiple options to verify signed and encrypted JWT tokens. It represents them as org.eclipse.microprofile.jwt.JsonWebToken.

quarkus-smallrye-jwt is an alternative to the quarkus-oidc Bearer token authentication mechanism and verifies only JWT tokens by using either Privacy Enhanced Mail (PEM) keys or the refreshable JWK key set. quarkus-smallrye-jwt also provides the JWT generation API, which you can use to easily create signed, inner-signed, and encrypted JWT tokens.

For more information, see the Using JWT RBAC guide.

2.4. Choosing between OpenID Connect, SmallRye JWT, and OAuth2 authentication mechanisms

Use the following information to select the appropriate token authentication mechanism to secure your Quarkus applications.

List of authentication mechanism use cases

  • quarkus-oidc requires an OpenID Connect provider such as Keycloak, which can verify the bearer tokens or authenticate the end users with the Authorization Code flow. In both cases, quarkus-oidc requires a connection to the specified OpenID Connect provider.
  • If the user authentication requires Authorization Code flow, or you need to support multiple tenants, use quarkus-oidc. quarkus-oidc can also request user information by using both Authorization Code Flow and Bearer access tokens.
  • If your bearer tokens must be verified, use quarkus-oidc or quarkus-smallrye-jwt.
  • If your bearer tokens are in a JSON web token (JWT) format, you can use any extensions in the preceding list. Both quarkus-oidc and quarkus-smallrye-jwt support refreshing the JsonWebKey (JWK) set when the OpenID Connect provider rotates the keys. Therefore, if remote token introspection must be avoided or is unsupported by the providers, use quarkus-oidc or quarkus-smallrye-jwt to verify JWT tokens.
  • To introspect the JWT tokens remotely, you can use quarkus-oidc for verifying the opaque or binary tokens by using remote introspection. quarkus-smallrye-jwt does not support the remote introspection of both opaque or JWT tokens but instead relies on the locally available keys that are usually retrieved from the OpenID Connect provider.
  • quarkus-oidc and quarkus-smallrye-jwt support the JWT and opaque token injection into the endpoint code. Injected JWT tokens provide more information about the user. All extensions can have the tokens injected as Principal.
  • quarkus-smallrye-jwt supports more key formats than quarkus-oidc. quarkus-oidc uses only the JWK-formatted keys that are part of a JWK set, whereas quarkus-smallrye-jwt supports PEM keys.
  • quarkus-smallrye-jwt handles locally signed, inner-signed-and-encrypted, and encrypted tokens. In contrast, although quarkus-oidc can also verify such tokens, it treats them as opaque tokens and verifies them through remote introspection.
Note

Architectural considerations drive your decision to use opaque or JSON web token (JWT) token format. Opaque tokens tend to be much shorter than JWT tokens but need most of the token-associated state to be maintained in the provider database. Opaque tokens are effectively database pointers.

JWT tokens are significantly longer than opaque tokens. Nonetheless, the providers effectively delegate most of the token-associated state to the client by storing it as the token claims and either signing or encrypting them.

Table 2.2. Token authentication mechanism comparison
Feature requiredAuthentication mechanism
 

quarkus-oidc

quarkus-smallrye-jwt

Bearer JWT verification

Local verification or introspection

Local verification

Bearer opaque token verification

Introspection

No

Refreshing JsonWebKey set to verify JWT tokens

Yes

Yes

Represent token as Principal

Yes

Yes

Inject JWT as MP JWT

Yes

Yes

Authorization code flow

Yes

No

Multi-tenancy

Yes

No

User information support

Yes

No

PEM key format support

No

Yes

SecretKey support

No

In JSON Web Key (JWK) format

Inner-signed and encrypted or encrypted tokens

Introspection

Local verification

Custom token verification

No

With injected JWT parser

JWT as a cookie support

No

Yes

2.5. Combining authentication mechanisms

If different sources provide the user credentials, you can combine authentication mechanisms. For example, you can combine the built-in Basic and the Quarkus quarkus-oidc Bearer token authentication mechanisms.

Important

You cannot combine the Quarkus quarkus-oidc Bearer token and smallrye-jwt authentication mechanisms because both mechanisms attempt to verify the token extracted from the HTTP Bearer token authentication scheme.

2.5.1. Path-specific authentication mechanisms

The following configuration example demonstrates how you can enforce a single selectable authentication mechanism for a given request path:

quarkus.http.auth.permission.basic-or-bearer.paths=/service
quarkus.http.auth.permission.basic-or-bearer.policy=authenticated

quarkus.http.auth.permission.basic.paths=/basic-only
quarkus.http.auth.permission.basic.policy=authenticated
quarkus.http.auth.permission.basic.auth-mechanism=basic

quarkus.http.auth.permission.bearer.paths=/bearer-only
quarkus.http.auth.permission.bearer.policy=authenticated
quarkus.http.auth.permission.bearer.auth-mechanism=bearer

Ensure that the value of the auth-mechanism property matches the authentication scheme supported by HttpAuthenticationMechanism, for example, basic, bearer, or form.

2.6. Proactive authentication

Proactive authentication is enabled in Quarkus by default. This means that if an incoming request has a credential, the request will always be authenticated, even if the target page does not require authentication. For more information, see the Quarkus Proactive authentication guide.

2.7. References

Chapter 3. Identity providers

In the Quarkus Security framework, identity providers play a crucial role in authentication and authorization by verifying user identities. IdentityProvider creates a SecurityIdentity instance, which gets used during user authentication to verify and authorize access requests to your Quarkus application.

IdentityProvider converts the authentication credentials provided by HttpAuthenticationMechanism to a SecurityIdentity instance.

Some extensions, for example, OIDC, OAuth2, and SmallRye JWT, have inline IdentityProvider implementations specific to the supported authentication flow. For example, quarkus-oidc uses its own IdentityProvider to convert a token to a SecurityIdentity instance.

If you use Basic or form-based authentication, you must add an IdentityProvider instance to convert a username and password to a SecurityIdentity instance.

To get started with security in Quarkus, consider combining the Quarkus built-in Basic HTTP authentication with the Jakarta Persistence identity provider to enable role-based access control (RBAC).

For more information about Basic authentication, its mechanisms, and related identity providers, see the following resources:

Chapter 4. Proactive authentication

Learn how to manage proactive authentication in Quarkus, including customizing settings and handling exceptions. Gain practical insights and strategies for various application scenarios.

Proactive authentication is enabled in Quarkus by default. It ensures that all incoming requests with credentials are authenticated, even if the target page does not require authentication. As a result, requests with invalid credentials are rejected, even if the target page is public.

You can turn off this default behavior if you want to authenticate only when the target page requires it. To turn off proactive authentication so that authentication occurs only when the target page requires it, modify the application.properties configuration file as follows:

quarkus.http.auth.proactive=false

If you turn off proactive authentication, the authentication process runs only when an identity is requested. An identity can be requested because of security rules that require the user to authenticate or because programmatic access to the current identity is required.

If proactive authentication is used, accessing SecurityIdentity is a blocking operation. This is because authentication might have yet to happen, and accessing SecurityIdentity might require calls to external systems, such as databases, that might block the operation. For blocking applications, this is not an issue. However, if you have disabled authentication in a reactive application, this fails because you cannot do blocking operations on the I/O thread. To work around this, you need to @Inject an instance of io.quarkus.security.identity.CurrentIdentityAssociation and call the Uni<SecurityIdentity> getDeferredIdentity(); method. Then, you can subscribe to the resulting Uni to be notified when authentication is complete and the identity is available.

Note

You can still access SecurityIdentity synchronously with public SecurityIdentity getIdentity() in RESTEasy Reactive from endpoints that are annotated with @RolesAllowed, @Authenticated, or with respective configuration authorization checks because authentication has already happened. The same is also valid for Reactive routes if a route response is synchronous.

When proactive authentication is disabled, standard security annotations used on CDI beans do not function on an I/O thread if a secured method that is not void synchronously returns a value. This limitation arises from the necessity for these methods to access SecurityIdentity.

The following example defines HelloResource and HelloService. Any GET request to /hello runs on the I/O thread and throws a BlockingOperationNotAllowedException exception.

There is more than one way to fix the example:

  • Switch to a worker thread by annotating the hello endpoint with @Blocking.
  • Change the sayHello method return type by using a reactive or asynchronous data type.
  • Move the @RolesAllowed annotation to the endpoint. This could be one of the safest ways because accessing SecurityIdentity from endpoint methods is never the blocking operation.
import jakarta.annotation.security.PermitAll;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

import io.smallrye.mutiny.Uni;

@Path("/hello")
@PermitAll
public class HelloResource {

    @Inject
    HelloService helloService;

    @GET
    public Uni<String> hello() {
        return Uni.createFrom().item(helloService.sayHello());
    }

}
import jakarta.annotation.security.RolesAllowed;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class HelloService {

    @RolesAllowed("admin")
    public String sayHello() {
        return "Hello";
    }

}

4.1. Customize authentication exception responses

You can use Jakarta REST ExceptionMapper to capture Quarkus Security authentication exceptions such as io.quarkus.security.AuthenticationFailedException. For example:

package io.quarkus.it.keycloak;

import jakarta.annotation.Priority;
import jakarta.ws.rs.Priorities;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;

import io.quarkus.security.AuthenticationFailedException;

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFailedExceptionMapper implements ExceptionMapper<AuthenticationFailedException> {

    @Context
    UriInfo uriInfo;

    @Override
    public Response toResponse(AuthenticationFailedException exception) {
        return Response.status(401).header("WWW-Authenticate", "Basic realm=\"Quarkus\"").build();
    }
}
Caution

Some HTTP authentication mechanisms must handle authentication exceptions themselves to create a correct authentication challenge. For example, io.quarkus.oidc.runtime.CodeAuthenticationMechanism, which manages OpenID Connect (OIDC) authorization code flow authentication, must build a correct redirect URL and set a state cookie. Therefore, avoid using custom exception mappers to customize authentication exceptions thrown by such mechanisms. Instead, a safer approach is to ensure that proactive authentication is enabled and to use Vert.x HTTP route failure handlers. This is because events come to the handler with the correct response status and headers. Then, you must only customize the response; for example:

package io.quarkus.it.keycloak;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;

import io.quarkus.security.AuthenticationFailedException;
import io.vertx.core.Handler;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class AuthenticationFailedExceptionHandler {

    public void init(@Observes Router router) {
        router.route().failureHandler(new Handler<RoutingContext>() {
            @Override
            public void handle(RoutingContext event) {
                if (event.failure() instanceof AuthenticationFailedException) {
                    event.response().end("CUSTOMIZED_RESPONSE");
                } else {
                    event.next();
                }
            }
        });
    }
}

4.2. References

Legal Notice

Copyright © 2025 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.
Red Hat logoGithubRedditYoutubeTwitter

자세한 정보

평가판, 구매 및 판매

커뮤니티

Red Hat 문서 정보

Red Hat을 사용하는 고객은 신뢰할 수 있는 콘텐츠가 포함된 제품과 서비스를 통해 혁신하고 목표를 달성할 수 있습니다.

보다 포괄적 수용을 위한 오픈 소스 용어 교체

Red Hat은 코드, 문서, 웹 속성에서 문제가 있는 언어를 교체하기 위해 최선을 다하고 있습니다. 자세한 내용은 다음을 참조하세요.Red Hat 블로그.

Red Hat 소개

Red Hat은 기업이 핵심 데이터 센터에서 네트워크 에지에 이르기까지 플랫폼과 환경 전반에서 더 쉽게 작업할 수 있도록 강화된 솔루션을 제공합니다.

© 2024 Red Hat, Inc.