All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.quarkus.oidc.OidcTenantConfig Maven / Gradle / Ivy

Go to download

Secure your applications with OpenID Connect Adapter and IDP such as Keycloak

There is a newer version: 3.17.5
Show newest version
package io.quarkus.oidc;

import java.time.Duration;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.OptionalInt;

import io.quarkus.oidc.common.runtime.OidcCommonConfig;
import io.quarkus.oidc.common.runtime.OidcConstants;
import io.quarkus.oidc.runtime.OidcConfig;
import io.quarkus.runtime.annotations.ConfigDocMapKey;
import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConvertWith;
import io.quarkus.runtime.configuration.TrimmedStringConverter;
import io.quarkus.security.identity.SecurityIdentityAugmentor;

@ConfigGroup
public class OidcTenantConfig extends OidcCommonConfig {

    /**
     * A unique tenant identifier. It must be set by {@code TenantConfigResolver} providers which
     * resolve the tenant configuration dynamically and is optional in all other cases.
     */
    @ConfigItem
    public Optional tenantId = Optional.empty();

    /**
     * If this tenant configuration is enabled.
     *
     * Note that the default tenant will be disabled if it is not configured but either
     * {@link TenantConfigResolver} which will resolve tenant configurations is registered
     * or named tenants are configured.
     * You do not have to disable the default tenant in this case.
     */
    @ConfigItem(defaultValue = "true")
    public boolean tenantEnabled = true;

    /**
     * The application type, which can be one of the following values from enum {@link ApplicationType}.
     */
    @ConfigItem(defaultValueDocumentation = "service")
    public Optional applicationType = Optional.empty();

    /**
     * Relative path or absolute URL of the OIDC authorization endpoint which authenticates the users.
     * This property must be set for the 'web-app' applications if OIDC discovery is disabled.
     * This property will be ignored if the discovery is enabled.
     */
    @ConfigItem
    public Optional authorizationPath = Optional.empty();

    /**
     * Relative path or absolute URL of the OIDC userinfo endpoint.
     * This property must only be set for the 'web-app' applications if OIDC discovery is disabled
     * and 'authentication.user-info-required' property is enabled.
     * This property will be ignored if the discovery is enabled.
     */
    @ConfigItem
    public Optional userInfoPath = Optional.empty();

    /**
     * Relative path or absolute URL of the OIDC RFC7662 introspection endpoint which can introspect both opaque and JWT tokens.
     * This property must be set if OIDC discovery is disabled and 1) the opaque bearer access tokens have to be verified
     * or 2) JWT tokens have to be verified while the cached JWK verification set with no matching JWK is being refreshed.
     * This property will be ignored if the discovery is enabled.
     */
    @ConfigItem
    public Optional introspectionPath = Optional.empty();

    /**
     * Relative path or absolute URL of the OIDC JWKS endpoint which returns a JSON Web Key Verification Set.
     * This property should be set if OIDC discovery is disabled and the local JWT verification is required.
     * This property will be ignored if the discovery is enabled.
     */
    @ConfigItem
    public Optional jwksPath = Optional.empty();

    /**
     * Relative path or absolute URL of the OIDC end_session_endpoint.
     * This property must be set if OIDC discovery is disabled and RP Initiated Logout support for the 'web-app' applications is
     * required.
     * This property will be ignored if the discovery is enabled.
     */
    @ConfigItem
    public Optional endSessionPath = Optional.empty();

    /**
     * Public key for the local JWT token verification.
     * OIDC server connection will not be created when this property is set.
     */
    @ConfigItem
    public Optional publicKey = Optional.empty();

    /**
     * Introspection Basic Authentication which must be configured only if the introspection is required
     * and OpenId Connect Provider does not support the OIDC client authentication configured with
     * {@link OidcCommonConfig#credentials} for its introspection endpoint.
     */
    @ConfigItem
    public IntrospectionCredentials introspectionCredentials = new IntrospectionCredentials();

    /**
     * Introspection Basic Authentication configuration
     */
    @ConfigGroup
    public static class IntrospectionCredentials {
        /**
         * Name
         */
        @ConfigItem
        public Optional name = Optional.empty();

        /**
         * Secret
         */
        @ConfigItem
        public Optional secret = Optional.empty();

        /**
         * Include OpenId Connect Client ID configured with 'quarkus.oidc.client-id'
         */
        @ConfigItem(defaultValue = "true")
        public boolean includeClientId = true;

        public Optional getName() {
            return name;
        }

        public void setName(String name) {
            this.name = Optional.of(name);
        }

        public Optional getSecret() {
            return secret;
        }

        public void setSecret(String secret) {
            this.secret = Optional.of(secret);
        }

        public boolean isIncludeClientId() {
            return includeClientId;
        }

        public void setIncludeClientId(boolean includeClientId) {
            this.includeClientId = includeClientId;
        }

    }

    /**
     * Configuration to find and parse a custom claim containing the roles information.
     */
    @ConfigItem
    public Roles roles = new Roles();

    /**
     * Configuration how to validate the token claims.
     */
    @ConfigItem
    public Token token = new Token();

    /**
     * RP Initiated, BackChannel and FrontChannel Logout configuration
     */
    @ConfigItem
    public Logout logout = new Logout();

    /**
     * Different options to configure authorization requests
     */
    public Authentication authentication = new Authentication();

    /**
     * Authorization code grant configuration
     */
    public CodeGrant codeGrant = new CodeGrant();

    /**
     * Default token state manager configuration
     */
    @ConfigItem
    public TokenStateManager tokenStateManager = new TokenStateManager();

    /**
     * Allow caching the token introspection data.
     * Note enabling this property does not enable the cache itself but only permits to cache the token introspection
     * for a given tenant. If the default token cache can be used then please see {@link OidcConfig.TokenCache} how to enable
     * it.
     */
    @ConfigItem(defaultValue = "true")
    public boolean allowTokenIntrospectionCache = true;

    /**
     * Allow caching the user info data.
     * Note enabling this property does not enable the cache itself but only permits to cache the user info data
     * for a given tenant. If the default token cache can be used then please see {@link OidcConfig.TokenCache} how to enable
     * it.
     */
    @ConfigItem(defaultValue = "true")
    public boolean allowUserInfoCache = true;

    /**
     * Allow inlining UserInfo in IdToken instead of caching it in the token cache.
     * This property is only checked when an internal IdToken is generated when Oauth2 providers do not return IdToken.
     * Inlining UserInfo in the generated IdToken allows to store it in the session cookie and avoids introducing a cached
     * state.
     */
    @ConfigItem(defaultValue = "false")
    public boolean cacheUserInfoInIdtoken = false;

    @ConfigGroup
    public static class Logout {

        /**
         * The relative path of the logout endpoint at the application. If provided, the application is able to initiate the
         * logout through this endpoint in conformance with the OpenID Connect RP-Initiated Logout specification.
         */
        @ConfigItem
        public Optional path = Optional.empty();

        /**
         * Relative path of the application endpoint where the user should be redirected to after logging out from the OpenID
         * Connect Provider.
         * This endpoint URI must be properly registered at the OpenID Connect Provider as a valid redirect URI.
         */
        @ConfigItem
        public Optional postLogoutPath = Optional.empty();

        /**
         * Name of the post logout URI parameter which will be added as a query parameter to the logout redirect URI.
         */
        @ConfigItem(defaultValue = OidcConstants.POST_LOGOUT_REDIRECT_URI)
        public String postLogoutUriParam;

        /**
         * Additional properties which will be added as the query parameters to the logout redirect URI.
         */
        @ConfigItem
        public Map extraParams;

        /**
         * Back-Channel Logout configuration
         */
        @ConfigItem
        public Backchannel backchannel = new Backchannel();

        /**
         * Front-Channel Logout configuration
         */
        @ConfigItem
        public Frontchannel frontchannel = new Frontchannel();

        public void setPath(Optional path) {
            this.path = path;
        }

        public Optional getPath() {
            return path;
        }

        public void setPostLogoutPath(Optional postLogoutPath) {
            this.postLogoutPath = postLogoutPath;
        }

        public Optional getPostLogoutPath() {
            return postLogoutPath;
        }

        public Map getExtraParams() {
            return extraParams;
        }

        public void setExtraParams(Map extraParams) {
            this.extraParams = extraParams;
        }

        public String getPostLogoutUriParam() {
            return postLogoutUriParam;
        }

        public void setPostLogoutUriParam(String postLogoutUriParam) {
            this.postLogoutUriParam = postLogoutUriParam;
        }

        public Backchannel getBackchannel() {
            return backchannel;
        }

        public void setBackchannel(Backchannel backchannel) {
            this.backchannel = backchannel;
        }

        public Frontchannel getFrontchannel() {
            return frontchannel;
        }

        public void setFrontchannel(Frontchannel frontchannel) {
            this.frontchannel = frontchannel;
        }
    }

    @ConfigGroup
    public static class Backchannel {
        /**
         * The relative path of the Back-Channel Logout endpoint at the application.
         */
        @ConfigItem
        public Optional path = Optional.empty();

        /**
         * Maximum number of logout tokens that can be cached before they are matched against ID tokens stored in session
         * cookies.
         */
        @ConfigItem(defaultValue = "10")
        public int tokenCacheSize = 10;

        /**
         * Number of minutes a logout token can be cached for.
         */
        @ConfigItem(defaultValue = "10M")
        public Duration tokenCacheTimeToLive = Duration.ofMinutes(10);

        /**
         * Token cache timer interval.
         * If this property is set then a timer will check and remove the stale entries periodically.
         */
        @ConfigItem
        public Optional cleanUpTimerInterval = Optional.empty();

        /**
         * Logout token claim whose value will be used as a key for caching the tokens.
         * Only `sub` (subject) and `sid` (session id) claims can be used as keys.
         * Set it to `sid` only if ID tokens issued by the OIDC provider have no `sub` but have `sid` claim.
         */
        @ConfigItem(defaultValue = "sub")
        public String logoutTokenKey = "sub";

        public void setPath(Optional path) {
            this.path = path;
        }

        public Optional getPath() {
            return path;
        }

        public String getLogoutTokenKey() {
            return logoutTokenKey;
        }

        public void setLogoutTokenKey(String logoutTokenKey) {
            this.logoutTokenKey = logoutTokenKey;
        }

        public int getTokenCacheSize() {
            return tokenCacheSize;
        }

        public void setTokenCacheSize(int tokenCacheSize) {
            this.tokenCacheSize = tokenCacheSize;
        }

        public Duration getTokenCacheTimeToLive() {
            return tokenCacheTimeToLive;
        }

        public void setTokenCacheTimeToLive(Duration tokenCacheTimeToLive) {
            this.tokenCacheTimeToLive = tokenCacheTimeToLive;
        }

        public Optional getCleanUpTimerInterval() {
            return cleanUpTimerInterval;
        }

        public void setCleanUpTimerInterval(Duration cleanUpTimerInterval) {
            this.cleanUpTimerInterval = Optional.of(cleanUpTimerInterval);
        }
    }

    @ConfigGroup
    public static class Frontchannel {
        /**
         * The relative path of the Front-Channel Logout endpoint at the application.
         */
        @ConfigItem
        public Optional path = Optional.empty();

        public void setPath(Optional path) {
            this.path = path;
        }

        public Optional getPath() {
            return path;
        }
    }

    /**
     * Default Authorization Code token state manager configuration
     */
    @ConfigGroup
    public static class TokenStateManager {

        public enum Strategy {
            /**
             * Keep ID, access and refresh tokens.
             */
            KEEP_ALL_TOKENS,

            /**
             * Keep ID token only
             */
            ID_TOKEN,

            /**
             * Keep ID and refresh tokens only
             */
            ID_REFRESH_TOKENS
        }

        /**
         * Default TokenStateManager strategy.
         */
        @ConfigItem(defaultValue = "keep_all_tokens")
        public Strategy strategy = Strategy.KEEP_ALL_TOKENS;

        /**
         * Default TokenStateManager keeps all tokens (ID, access and refresh)
         * returned in the authorization code grant response in a single session cookie by default.
         *
         * Enable this property to minimize a session cookie size
         */
        @ConfigItem(defaultValue = "false")
        public boolean splitTokens;

        /**
         * Mandates that the Default TokenStateManager will encrypt the session cookie that stores the tokens.
         */
        @ConfigItem(defaultValue = "true")
        public boolean encryptionRequired = true;

        /**
         * Secret which will be used by the Default TokenStateManager to encrypt the session cookie
         * storing the tokens when {@link #encryptionRequired} property is enabled.
         * 

* If this secret is not set, the client secret configured with * either `quarkus.oidc.credentials.secret` or `quarkus.oidc.credentials.client-secret.value` will be checked. * Finally, `quarkus.oidc.credentials.jwt.secret` which can be used for `client_jwt_secret` authentication will be * checked. * The secret will be auto-generated if it remains uninitialized after checking all of these properties. *

* The length of the secret which will be used to encrypt the tokens should be at least 32 characters long. * Warning will be logged if the secret length is less than 16 characters. */ @ConfigItem public Optional encryptionSecret = Optional.empty(); public boolean isEncryptionRequired() { return encryptionRequired; } public void setEncryptionRequired(boolean encryptionRequired) { this.encryptionRequired = encryptionRequired; } public Optional getEncryptionSecret() { return encryptionSecret; } public void setEncryptionSecret(String encryptionSecret) { this.encryptionSecret = Optional.of(encryptionSecret); } public boolean isSplitTokens() { return splitTokens; } public void setSplitTokens(boolean splitTokens) { this.splitTokens = splitTokens; } public Strategy getStrategy() { return strategy; } public void setStrategy(Strategy strategy) { this.strategy = strategy; } } public Optional getAuthorizationPath() { return authorizationPath; } public void setAuthorizationPath(String authorizationPath) { this.authorizationPath = Optional.of(authorizationPath); } public Optional getUserInfoPath() { return userInfoPath; } public void setUserInfoPath(String userInfoPath) { this.userInfoPath = Optional.of(userInfoPath); } public Optional getIntrospectionPath() { return introspectionPath; } public void setIntrospectionPath(String introspectionPath) { this.introspectionPath = Optional.of(introspectionPath); } public Optional getJwksPath() { return jwksPath; } public void setJwksPath(String jwksPath) { this.jwksPath = Optional.of(jwksPath); } public Optional getEndSessionPath() { return endSessionPath; } public void setEndSessionPath(String endSessionPath) { this.endSessionPath = Optional.of(endSessionPath); } public Optional getPublicKey() { return publicKey; } public void setPublicKey(String publicKey) { this.publicKey = Optional.of(publicKey); } public Roles getRoles() { return roles; } public void setRoles(Roles roles) { this.roles = roles; } public Token getToken() { return token; } public void setToken(Token token) { this.token = token; } public Authentication getAuthentication() { return authentication; } public void setAuthentication(Authentication authentication) { this.authentication = authentication; } public Optional getTenantId() { return tenantId; } public void setTenantId(String tenantId) { this.tenantId = Optional.of(tenantId); } public boolean isTenantEnabled() { return tenantEnabled; } public void setTenantEnabled(boolean enabled) { this.tenantEnabled = enabled; } public void setLogout(Logout logout) { this.logout = logout; } public Logout getLogout() { return logout; } @ConfigGroup public static class Roles { public static Roles fromClaimPath(List path) { return fromClaimPathAndSeparator(path, null); } public static Roles fromClaimPathAndSeparator(List path, String sep) { Roles roles = new Roles(); roles.roleClaimPath = Optional.ofNullable(path); roles.roleClaimSeparator = Optional.ofNullable(sep); return roles; } /** * List of paths to claims containing an array of groups. Each path starts from the top level JWT JSON object * and can contain multiple segments where each segment represents a JSON object name only, * example: "realm/groups". Use double quotes with the namespace qualified claim names. * This property can be used if a token has no 'groups' claim but has the groups set in one or more different * claims. */ @ConfigItem public Optional> roleClaimPath = Optional.empty(); /** * Separator for splitting a string which may contain multiple group values. * It will only be used if the "role-claim-path" property points to one or more custom claims whose values are strings. * A single space will be used by default because the standard 'scope' claim may contain a space separated sequence. */ @ConfigItem public Optional roleClaimSeparator = Optional.empty(); /** * Source of the principal roles. */ @ConfigItem public Optional source = Optional.empty(); public Optional> getRoleClaimPath() { return roleClaimPath; } public void setRoleClaimPath(List roleClaimPath) { this.roleClaimPath = Optional.of(roleClaimPath); } public Optional getRoleClaimSeparator() { return roleClaimSeparator; } public void setRoleClaimSeparator(String roleClaimSeparator) { this.roleClaimSeparator = Optional.of(roleClaimSeparator); } public Optional getSource() { return source; } public void setSource(Source source) { this.source = Optional.of(source); } // Source of the principal roles public static enum Source { /** * ID Token - the default value for the 'web-app' applications. */ idtoken, /** * Access Token - the default value for the 'service' applications; * can also be used as the source of roles for the 'web-app' applications. */ accesstoken, /** * User Info */ userinfo } } /** * Defines the authorization request properties when authenticating * users using the Authorization Code Grant Type. */ @ConfigGroup public static class Authentication { /** * SameSite attribute values for the session cookie. */ public enum CookieSameSite { STRICT, LAX, NONE } /** * Authorization code flow response mode */ public enum ResponseMode { /** * Authorization response parameters are encoded in the query string added to the redirect_uri */ QUERY, /** * Authorization response parameters are encoded as HTML form values that are auto-submitted in the browser * and transmitted via the HTTP POST method using the application/x-www-form-urlencoded content type */ FORM_POST } /** * Authorization code flow response mode */ @ConfigItem(defaultValueDocumentation = "query") public Optional responseMode = Optional.empty(); /** * Relative path for calculating a "redirect_uri" query parameter. * It has to start from a forward slash and will be appended to the request URI's host and port. * For example, if the current request URI is 'https://localhost:8080/service' then a 'redirect_uri' parameter * will be set to 'https://localhost:8080/' if this property is set to '/' and be the same as the request URI * if this property has not been configured. * Note the original request URI will be restored after the user has authenticated if 'restorePathAfterRedirect' is set * to 'true'. */ @ConfigItem public Optional redirectPath = Optional.empty(); /** * If this property is set to 'true' then the original request URI which was used before * the authentication will be restored after the user has been redirected back to the application. * * Note if `redirectPath` property is not set, the original request URI will be restored even if this property is * disabled. */ @ConfigItem(defaultValue = "false") public boolean restorePathAfterRedirect; /** * Remove the query parameters such as 'code' and 'state' set by the OIDC server on the redirect URI * after the user has authenticated by redirecting a user to the same URI but without the query parameters. */ @ConfigItem(defaultValue = "true") public boolean removeRedirectParameters = true; /** * Relative path to the public endpoint which will process the error response from the OIDC authorization endpoint. * If the user authentication has failed then the OIDC provider will return an 'error' and an optional * 'error_description' * parameters, instead of the expected authorization 'code'. * * If this property is set then the user will be redirected to the endpoint which can return a user-friendly * error description page. It has to start from a forward slash and will be appended to the request URI's host and port. * For example, if it is set as '/error' and the current request URI is * 'https://localhost:8080/callback?error=invalid_scope' * then a redirect will be made to 'https://localhost:8080/error?error=invalid_scope'. * * If this property is not set then HTTP 401 status will be returned in case of the user authentication failure. */ @ConfigItem public Optional errorPath = Optional.empty(); /** * Both ID and access tokens are fetched from the OIDC provider as part of the authorization code flow. * ID token is always verified on every user request as the primary token which is used * to represent the principal and extract the roles. * Access token is not verified by default since it is meant to be propagated to the downstream services. * The verification of the access token should be enabled if it is injected as a JWT token. * * Access tokens obtained as part of the code flow will always be verified if `quarkus.oidc.roles.source` * property is set to `accesstoken` which means the authorization decision will be based on the roles extracted from the * access token. * * Bearer access tokens are always verified. */ @ConfigItem(defaultValue = "false") public boolean verifyAccessToken; /** * Force 'https' as the 'redirect_uri' parameter scheme when running behind an SSL terminating reverse proxy. * This property, if enabled, will also affect the logout `post_logout_redirect_uri` and the local redirect requests. */ @ConfigItem(defaultValueDocumentation = "false") public Optional forceRedirectHttpsScheme = Optional.empty(); /** * List of scopes */ @ConfigItem public Optional> scopes = Optional.empty(); /** * Require that ID token includes a `nonce` claim which must match `nonce` authentication request query parameter. * Enabling this property can help mitigate replay attacks. * Do not enable this property if your OpenId Connect provider does not support setting `nonce` in ID token * or if you work with OAuth2 provider such as `GitHub` which does not issue ID tokens. */ @ConfigItem(defaultValue = "false") public boolean nonceRequired = false; /** * Add the 'openid' scope automatically to the list of scopes. This is required for OpenId Connect providers * but will not work for OAuth2 providers such as Twitter OAuth2 which does not accept that scope and throws an error. */ @ConfigItem(defaultValueDocumentation = "true") public Optional addOpenidScope = Optional.empty(); /** * Additional properties which will be added as the query parameters to the authentication redirect URI. */ @ConfigItem public Map extraParams = new HashMap<>(); /** * Request URL query parameters which, if present, will be added to the authentication redirect URI. */ @ConfigItem @ConvertWith(TrimmedStringConverter.class) public Optional> forwardParams = Optional.empty(); /** * If enabled the state, session and post logout cookies will have their 'secure' parameter set to 'true' * when HTTP is used. It may be necessary when running behind an SSL terminating reverse proxy. * The cookies will always be secure if HTTPS is used even if this property is set to false. */ @ConfigItem(defaultValue = "false") public boolean cookieForceSecure; /** * Cookie name suffix. * For example, a session cookie name for the default OIDC tenant is 'q_session' but can be changed to 'q_session_test' * if this property is set to 'test'. */ @ConfigItem public Optional cookieSuffix = Optional.empty(); /** * Cookie path parameter value which, if set, will be used to set a path parameter for the session, state and post * logout cookies. * The `cookie-path-header` property, if set, will be checked first. */ @ConfigItem(defaultValue = "/") public String cookiePath = "/"; /** * Cookie path header parameter value which, if set, identifies the incoming HTTP header * whose value will be used to set a path parameter for the session, state and post logout cookies. * If the header is missing then the `cookie-path` property will be checked. */ @ConfigItem public Optional cookiePathHeader = Optional.empty(); /** * Cookie domain parameter value which, if set, will be used for the session, state and post logout cookies. */ @ConfigItem public Optional cookieDomain = Optional.empty(); /** * SameSite attribute for the session cookie. */ @ConfigItem(defaultValue = "lax") public CookieSameSite cookieSameSite = CookieSameSite.LAX; /** * If a state cookie is present then a `state` query parameter must also be present and both the state * cookie name suffix and state cookie value have to match the value of the `state` query parameter when * the redirect path matches the current path. * However, if multiple authentications are attempted from the same browser, for example, from the different * browser tabs, then the currently available state cookie may represent the authentication flow * initiated from another tab and not related to the current request. * Disable this property if you would like to avoid supporting multiple authorization code flows running in the same * browser. * */ @ConfigItem(defaultValue = "true") public boolean allowMultipleCodeFlows = true; /** * Fail with the HTTP 401 error if the state cookie is present but no state query parameter is present. *

* When either multiple authentications are disabled or the redirect URL * matches the original request URL, the stale state cookie might remain in the browser cache from * the earlier failed redirect to an OpenId Connect provider and be visible during the current request. * For example, if Single-page application (SPA) uses XHR to handle redirects to the provider * which does not support CORS for its authorization endpoint, the browser will block it * and the state cookie created by Quarkus will remain in the browser cache. * Quarkus will report an authentication failure when it will detect such an old state cookie but find no matching state * query parameter. *

* Reporting HTTP 401 error is usually the right thing to do in such cases, it will minimize a risk of the * browser redirect loop but also can identify problems in the way SPA or Quarkus application manage redirects. * For example, enabling {@link #javaScriptAutoRedirect} or having the provider redirect to URL configured * with {@link #redirectPath} may be needed to avoid such errors. *

* However, setting this property to `false` may help if the above options are not suitable. * It will cause a new authentication redirect to OpenId Connect provider. Please be aware doing so may increase the * risk of browser redirect loops. */ @ConfigItem(defaultValue = "false") public boolean failOnMissingStateParam = false; /** * If this property is set to 'true' then an OIDC UserInfo endpoint will be called. * This property will be enabled if `quarkus.oidc.roles.source` is `userinfo` * or `quarkus.oidc.token.verify-access-token-with-user-info` is `true` * or `quarkus.oidc.authentication.id-token-required` is set to `false`, * you do not have to enable this property manually in these cases. */ @ConfigItem(defaultValueDocumentation = "false") public Optional userInfoRequired = Optional.empty(); /** * Session age extension in minutes. * The user session age property is set to the value of the ID token life-span by default and * the user will be redirected to the OIDC provider to re-authenticate once the session has expired. * If this property is set to a non-zero value then the expired ID token can be refreshed before * the session has expired. * This property will be ignored if the `token.refresh-expired` property has not been enabled. */ @ConfigItem(defaultValue = "5M") public Duration sessionAgeExtension = Duration.ofMinutes(5); /** * If this property is set to 'true' then a normal 302 redirect response will be returned * if the request was initiated via JavaScript API such as XMLHttpRequest or Fetch and the current user needs to be * (re)authenticated which may not be desirable for Single-page applications (SPA) since * it automatically following the redirect may not work given that OIDC authorization endpoints typically do not support * CORS. *

* If this property is set to 'false' then a status code of '499' will be returned to allow * SPA to handle the redirect manually if a request header identifying current request as a JavaScript request is found. * 'X-Requested-With' request header with its value set to either `JavaScript` or `XMLHttpRequest` is expected by * default if * this property is enabled. You can register a custom {@linkplain JavaScriptRequestChecker} to do a custom JavaScript * request check instead. */ @ConfigItem(defaultValue = "true") public boolean javaScriptAutoRedirect = true; /** * Requires that ID token is available when the authorization code flow completes. * Disable this property only when you need to use the authorization code flow with OAuth2 providers which do not return * ID token - an internal IdToken will be generated in such cases. */ @ConfigItem(defaultValueDocumentation = "true") public Optional idTokenRequired = Optional.empty(); /** * Internal ID token lifespan. * This property is only checked when an internal IdToken is generated when Oauth2 providers do not return IdToken. */ @ConfigItem(defaultValueDocumentation = "5M") public Optional internalIdTokenLifespan = Optional.empty(); /** * Requires that a Proof Key for Code Exchange (PKCE) is used. */ @ConfigItem(defaultValueDocumentation = "false") public Optional pkceRequired = Optional.empty(); /** * Secret which will be used to encrypt a Proof Key for Code Exchange (PKCE) code verifier in the code flow state. * This secret should be at least 32 characters long. * * @deprecated Use {@link #stateSecret} property instead. */ @ConfigItem @Deprecated(forRemoval = true) public Optional pkceSecret = Optional.empty(); /** * Secret which will be used to encrypt Proof Key for Code Exchange (PKCE) code verifier and/or nonce in the code flow * state. * This secret should be at least 32 characters long. *

* If this secret is not set, the client secret configured with * either `quarkus.oidc.credentials.secret` or `quarkus.oidc.credentials.client-secret.value` will be checked. * Finally, `quarkus.oidc.credentials.jwt.secret` which can be used for `client_jwt_secret` authentication will be * checked. Client secret will not be used as a state encryption secret if it is less than 32 characters * long. *

* The secret will be auto-generated if it remains uninitialized after checking all of these properties. *

* Error will be reported if the secret length is less than 16 characters. */ @ConfigItem public Optional stateSecret = Optional.empty(); public Optional getInternalIdTokenLifespan() { return internalIdTokenLifespan; } public void setInternalIdTokenLifespan(Duration internalIdTokenLifespan) { this.internalIdTokenLifespan = Optional.of(internalIdTokenLifespan); } public Optional isPkceRequired() { return pkceRequired; } public void setPkceRequired(boolean pkceRequired) { this.pkceRequired = Optional.of(pkceRequired); } @Deprecated(forRemoval = true) public Optional getPkceSecret() { return pkceSecret; } @Deprecated(forRemoval = true) public void setPkceSecret(String pkceSecret) { this.pkceSecret = Optional.of(pkceSecret); } public Optional getErrorPath() { return errorPath; } public void setErrorPath(String errorPath) { this.errorPath = Optional.of(errorPath); } public boolean isJavaScriptAutoRedirect() { return javaScriptAutoRedirect; } public void setJavaScriptAutoredirect(boolean autoRedirect) { this.javaScriptAutoRedirect = autoRedirect; } public Optional getRedirectPath() { return redirectPath; } public void setRedirectPath(String redirectPath) { this.redirectPath = Optional.of(redirectPath); } public Optional> getScopes() { return scopes; } public void setScopes(List scopes) { this.scopes = Optional.of(scopes); } public Map getExtraParams() { return extraParams; } public void setExtraParams(Map extraParams) { this.extraParams = extraParams; } public void setAddOpenidScope(boolean addOpenidScope) { this.addOpenidScope = Optional.of(addOpenidScope); } public Optional isAddOpenidScope() { return addOpenidScope; } public Optional isForceRedirectHttpsScheme() { return forceRedirectHttpsScheme; } public void setForceRedirectHttpsScheme(boolean forceRedirectHttpsScheme) { this.forceRedirectHttpsScheme = Optional.of(forceRedirectHttpsScheme); } public boolean isRestorePathAfterRedirect() { return restorePathAfterRedirect; } public void setRestorePathAfterRedirect(boolean restorePathAfterRedirect) { this.restorePathAfterRedirect = restorePathAfterRedirect; } public boolean isCookieForceSecure() { return cookieForceSecure; } public void setCookieForceSecure(boolean cookieForceSecure) { this.cookieForceSecure = cookieForceSecure; } public String getCookiePath() { return cookiePath; } public void setCookiePath(String cookiePath) { this.cookiePath = cookiePath; } public Optional getCookieDomain() { return cookieDomain; } public void setCookieDomain(String cookieDomain) { this.cookieDomain = Optional.of(cookieDomain); } public Optional isUserInfoRequired() { return userInfoRequired; } public void setUserInfoRequired(boolean userInfoRequired) { this.userInfoRequired = Optional.of(userInfoRequired); } public boolean isRemoveRedirectParameters() { return removeRedirectParameters; } public void setRemoveRedirectParameters(boolean removeRedirectParameters) { this.removeRedirectParameters = removeRedirectParameters; } public boolean isVerifyAccessToken() { return verifyAccessToken; } public void setVerifyAccessToken(boolean verifyAccessToken) { this.verifyAccessToken = verifyAccessToken; } public Duration getSessionAgeExtension() { return sessionAgeExtension; } public void setSessionAgeExtension(Duration sessionAgeExtension) { this.sessionAgeExtension = sessionAgeExtension; } public Optional getCookiePathHeader() { return cookiePathHeader; } public void setCookiePathHeader(String cookiePathHeader) { this.cookiePathHeader = Optional.of(cookiePathHeader); } public Optional isIdTokenRequired() { return idTokenRequired; } public void setIdTokenRequired(boolean idTokenRequired) { this.idTokenRequired = Optional.of(idTokenRequired); } public Optional getCookieSuffix() { return cookieSuffix; } public void setCookieSuffix(String cookieSuffix) { this.cookieSuffix = Optional.of(cookieSuffix); } public Optional getResponseMode() { return responseMode; } public void setResponseMode(ResponseMode responseMode) { this.responseMode = Optional.of(responseMode); } public Optional> getForwardParams() { return forwardParams; } public void setForwardParams(List forwardParams) { this.forwardParams = Optional.of(forwardParams); } public CookieSameSite getCookieSameSite() { return cookieSameSite; } public void setCookieSameSite(CookieSameSite cookieSameSite) { this.cookieSameSite = cookieSameSite; } public boolean isAllowMultipleCodeFlows() { return allowMultipleCodeFlows; } public void setAllowMultipleCodeFlows(boolean allowMultipleCodeFlows) { this.allowMultipleCodeFlows = allowMultipleCodeFlows; } public boolean isNonceRequired() { return nonceRequired; } public void setNonceRequired(boolean nonceRequired) { this.nonceRequired = nonceRequired; } public Optional getStateSecret() { return stateSecret; } public void setStateSecret(Optional stateSecret) { this.stateSecret = stateSecret; } } /** * Authorization Code grant configuration */ @ConfigGroup public static class CodeGrant { /** * Additional parameters, in addition to the required `code` and `redirect-uri` parameters, * which have to be included to complete the authorization code grant request. */ @ConfigItem public Map extraParams = new HashMap<>(); /** * Custom HTTP headers which have to be sent to complete the authorization code grant request. */ @ConfigItem public Map headers = new HashMap<>(); public Map getExtraParams() { return extraParams; } public void setExtraParams(Map extraParams) { this.extraParams = extraParams; } public Map getHeaders() { return headers; } public void setHeaders(Map headers) { this.headers = headers; } } /** * Supported asymmetric signature algorithms */ public static enum SignatureAlgorithm { RS256, RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, EDDSA; private static String EDDSA_ALG = "EDDSA"; private static String REQUIRED_EDDSA_ALG = "EdDSA"; public String getAlgorithm() { String name = name(); return EDDSA_ALG.equals(name) ? REQUIRED_EDDSA_ALG : name; } } @ConfigGroup public static class Token { public static Token fromIssuer(String issuer) { Token tokenClaims = new Token(); tokenClaims.issuer = Optional.of(issuer); tokenClaims.audience = Optional.ofNullable(null); return tokenClaims; } public static Token fromAudience(String... audience) { Token tokenClaims = new Token(); tokenClaims.issuer = Optional.ofNullable(null); tokenClaims.audience = Optional.of(Arrays.asList(audience)); return tokenClaims; } /** * Expected issuer 'iss' claim value. * Note this property overrides the `issuer` property which may be set in OpenId Connect provider's well-known * configuration. * If the `iss` claim value varies depending on the host/IP address or tenant id of the provider then you may skip the * issuer verification by setting this property to 'any' but it should be done only when other options (such as * configuring * the provider to use the fixed `iss` claim value) are not possible. */ @ConfigItem public Optional issuer = Optional.empty(); /** * Expected audience 'aud' claim value which may be a string or an array of strings. * * Note the audience claim will be verified for ID tokens by default. * ID token audience must be equal to the value of `quarkus.oidc.client-id` property. * Use this property to override the expected value if your OpenID Connect provider * sets a different audience claim value in ID tokens. Set it to `any` if your provider * does not set ID token audience` claim. * * Audience verification for access tokens will only be done if this property is configured. */ @ConfigItem public Optional> audience = Optional.empty(); /** * Require that the token includes a `sub` (subject) claim which is a unique * and never reassigned identifier for the current user. * Note that if you enable this property and if UserInfo is also required then * both the token and UserInfo `sub` claims must be present and match each other. */ @ConfigItem(defaultValue = "false") public boolean subjectRequired = false; /** * A map of required claims and their expected values. * For example, `quarkus.oidc.token.required-claims.org_id = org_xyz` would require tokens to have the `org_id` claim to * be present and set to `org_xyz`. * Strings are the only supported types. Use {@linkplain SecurityIdentityAugmentor} to verify claims of other types or * complex claims. */ @ConfigItem @ConfigDocMapKey("claim-name") public Map requiredClaims = new HashMap<>(); /** * Expected token type */ @ConfigItem public Optional tokenType = Optional.empty(); /** * Life span grace period in seconds. * When checking token expiry, current time is allowed to be later than token expiration time by at most the configured * number of seconds. * When checking token issuance, current time is allowed to be sooner than token issue time by at most the configured * number of seconds. */ @ConfigItem public OptionalInt lifespanGrace = OptionalInt.empty(); /** * Token age. * * It allows for the number of seconds to be specified that must not elapse since the `iat` (issued at) time. * A small leeway to account for clock skew which can be configured with 'quarkus.oidc.token.lifespan-grace' to verify * the token expiry time * can also be used to verify the token age property. * * Note that setting this property does not relax the requirement that Bearer and Code Flow JWT tokens * must have a valid ('exp') expiry claim value. The only exception where setting this property relaxes the requirement * is when a logout token is sent with a back-channel logout request since the current * OpenId Connect Back-Channel specification does not explicitly require the logout tokens to contain an 'exp' claim. * However, even if the current logout token is allowed to have no 'exp' claim, the `exp` claim will be still verified * if the logout token contains it. */ @ConfigItem public Optional age = Optional.empty(); /** * Name of the claim which contains a principal name. By default, the 'upn', 'preferred_username' and `sub` claims are * checked. */ @ConfigItem public Optional principalClaim = Optional.empty(); /** * Refresh expired authorization code flow ID or access tokens. * If this property is enabled then a refresh token request will be performed if the authorization code * ID or access token has expired and, if successful, the local session will be updated with the new set of tokens. * Otherwise, the local session will be invalidated and the user redirected to the OpenID Provider to re-authenticate. * In this case the user may not be challenged again if the OIDC provider session is still active. * * For this option be effective the `authentication.session-age-extension` property should also be set to a non-zero * value since the refresh token is currently kept in the user session. * * This option is valid only when the application is of type {@link ApplicationType#WEB_APP}}. * * This property will be enabled if `quarkus.oidc.token.refresh-token-time-skew` is configured, * you do not have to enable this property manually in this case. */ @ConfigItem public boolean refreshExpired; /** * Refresh token time skew in seconds. * If this property is enabled then the configured number of seconds is added to the current time * when checking if the authorization code ID or access token should be refreshed. * If the sum is greater than the authorization code ID or access token's expiration time then a refresh is going to * happen. */ @ConfigItem public Optional refreshTokenTimeSkew = Optional.empty(); /** * Forced JWK set refresh interval in minutes. */ @ConfigItem(defaultValue = "10M") public Duration forcedJwkRefreshInterval = Duration.ofMinutes(10); /** * Custom HTTP header that contains a bearer token. * This option is valid only when the application is of type {@link ApplicationType#SERVICE}}. */ @ConfigItem public Optional header = Optional.empty(); /** * Required signature algorithm. * OIDC providers support many signature algorithms but if necessary you can restrict * Quarkus application to accept tokens signed only using an algorithm configured with this property. */ @ConfigItem public Optional signatureAlgorithm = Optional.empty(); /** * Decryption key location. * JWT tokens can be inner-signed and encrypted by OpenId Connect providers. * However, it is not always possible to remotely introspect such tokens because * the providers may not control the private decryption keys. * In such cases set this property to point to the file containing the decryption private key in * PEM or JSON Web Key (JWK) format. * Note that if a 'private_key_jwt' client authentication method is used then the private key * which is used to sign client authentication JWT tokens will be used to try to decrypt an encrypted ID token * if this property is not set. */ @ConfigItem public Optional decryptionKeyLocation = Optional.empty(); /** * Allow the remote introspection of JWT tokens when no matching JWK key is available. * * Note this property is set to 'true' by default for backward-compatibility reasons and will be set to `false` * instead in one of the next releases. * * Also note this property will be ignored if JWK endpoint URI is not available and introspecting the tokens is * the only verification option. */ @ConfigItem(defaultValue = "true") public boolean allowJwtIntrospection = true; /** * Require that JWT tokens are only introspected remotely. * */ @ConfigItem(defaultValue = "false") public boolean requireJwtIntrospectionOnly = false; /** * Allow the remote introspection of the opaque tokens. * * Set this property to 'false' if only JWT tokens are expected. */ @ConfigItem(defaultValue = "true") public boolean allowOpaqueTokenIntrospection = true; /** * Token customizer name. * * Allows to select a tenant specific token customizer as a named bean. * Prefer using {@link TenantFeature} qualifier when registering custom {@link TokenCustomizer}. * Use this property only to refer to `TokenCustomizer` implementations provided by this extension. */ @ConfigItem public Optional customizerName = Optional.empty(); /** * Indirectly verify that the opaque (binary) access token is valid by using it to request UserInfo. * Opaque access token is considered valid if the provider accepted this token and returned a valid UserInfo. * You should only enable this option if the opaque access tokens have to be accepted but OpenId Connect * provider does not have a token introspection endpoint. * This property will have no effect when JWT tokens have to be verified. */ @ConfigItem(defaultValueDocumentation = "false") public Optional verifyAccessTokenWithUserInfo = Optional.empty(); public Optional isVerifyAccessTokenWithUserInfo() { return verifyAccessTokenWithUserInfo; } public void setVerifyAccessTokenWithUserInfo(boolean verify) { this.verifyAccessTokenWithUserInfo = Optional.of(verify); } public Optional getIssuer() { return issuer; } public void setIssuer(String issuer) { this.issuer = Optional.of(issuer); } public Optional getHeader() { return header; } public void setHeader(String header) { this.header = Optional.of(header); } public Optional> getAudience() { return audience; } public void setAudience(List audience) { this.audience = Optional.of(audience); } public OptionalInt getLifespanGrace() { return lifespanGrace; } public void setLifespanGrace(int lifespanGrace) { this.lifespanGrace = OptionalInt.of(lifespanGrace); } public Optional getPrincipalClaim() { return principalClaim; } public void setPrincipalClaim(String principalClaim) { this.principalClaim = Optional.of(principalClaim); } public boolean isRefreshExpired() { return refreshExpired; } public void setRefreshExpired(boolean refreshExpired) { this.refreshExpired = refreshExpired; } public Duration getForcedJwkRefreshInterval() { return forcedJwkRefreshInterval; } public void setForcedJwkRefreshInterval(Duration forcedJwkRefreshInterval) { this.forcedJwkRefreshInterval = forcedJwkRefreshInterval; } public Optional getTokenType() { return tokenType; } public void setTokenType(String tokenType) { this.tokenType = Optional.of(tokenType); } public Optional getRefreshTokenTimeSkew() { return refreshTokenTimeSkew; } public void setRefreshTokenTimeSkew(Duration refreshTokenTimeSkew) { this.refreshTokenTimeSkew = Optional.of(refreshTokenTimeSkew); } public boolean isAllowJwtIntrospection() { return allowJwtIntrospection; } public void setAllowJwtIntrospection(boolean allowJwtIntrospection) { this.allowJwtIntrospection = allowJwtIntrospection; } public boolean isAllowOpaqueTokenIntrospection() { return allowOpaqueTokenIntrospection; } public void setAllowOpaqueTokenIntrospection(boolean allowOpaqueTokenIntrospection) { this.allowOpaqueTokenIntrospection = allowOpaqueTokenIntrospection; } public Optional getAge() { return age; } public void setAge(Duration age) { this.age = Optional.of(age); } public Optional getDecryptionKeyLocation() { return decryptionKeyLocation; } public void setDecryptionKeyLocation(String decryptionKeyLocation) { this.decryptionKeyLocation = Optional.of(decryptionKeyLocation); } public Map getRequiredClaims() { return requiredClaims; } public void setRequiredClaims(Map requiredClaims) { this.requiredClaims = requiredClaims; } public boolean isRequireJwtIntrospectionOnly() { return requireJwtIntrospectionOnly; } public void setRequireJwtIntrospectionOnly(boolean requireJwtIntrospectionOnly) { this.requireJwtIntrospectionOnly = requireJwtIntrospectionOnly; } public Optional getSignatureAlgorithm() { return signatureAlgorithm; } public void setSignatureAlgorithm(SignatureAlgorithm signatureAlgorithm) { this.signatureAlgorithm = Optional.of(signatureAlgorithm); } public Optional getCustomizerName() { return customizerName; } public void setCustomizerName(String customizerName) { this.customizerName = Optional.of(customizerName); } public boolean isSubjectRequired() { return subjectRequired; } public void setSubjectRequired(boolean subjectRequired) { this.subjectRequired = subjectRequired; } } public static enum ApplicationType { /** * A {@code WEB_APP} is a client that serves pages, usually a frontend application. For this type of client the * Authorization Code Flow is defined as the preferred method for authenticating users. */ WEB_APP, /** * A {@code SERVICE} is a client that has a set of protected HTTP resources, usually a backend application following the * RESTful Architectural Design. For this type of client, the Bearer Authorization method is defined as the preferred * method for authenticating and authorizing users. */ SERVICE, /** * A combined {@code SERVICE} and {@code WEB_APP} client. * For this type of client, the Bearer Authorization method will be used if the Authorization header is set * and Authorization Code Flow - if not. */ HYBRID } /** * Well known OpenId Connect provider identifier */ @ConfigItem public Optional provider = Optional.empty(); public static enum Provider { APPLE, FACEBOOK, GITHUB, GOOGLE, MASTODON, MICROSOFT, SPOTIFY, TWITCH, TWITTER, // New name for Twitter X } public Optional getProvider() { return provider; } public void setProvider(Provider provider) { this.provider = Optional.of(provider); } public Optional getApplicationType() { return applicationType; } public void setApplicationType(ApplicationType type) { this.applicationType = Optional.of(type); } public boolean isAllowTokenIntrospectionCache() { return allowTokenIntrospectionCache; } public void setAllowTokenIntrospectionCache(boolean allowTokenIntrospectionCache) { this.allowTokenIntrospectionCache = allowTokenIntrospectionCache; } public boolean isAllowUserInfoCache() { return allowUserInfoCache; } public void setAllowUserInfoCache(boolean allowUserInfoCache) { this.allowUserInfoCache = allowUserInfoCache; } public boolean isCacheUserInfoInIdtoken() { return cacheUserInfoInIdtoken; } public void setCacheUserInfoInIdtoken(boolean cacheUserInfoInIdtoken) { this.cacheUserInfoInIdtoken = cacheUserInfoInIdtoken; } public IntrospectionCredentials getIntrospectionCredentials() { return introspectionCredentials; } public void setIntrospectionCredentials(IntrospectionCredentials introspectionCredentials) { this.introspectionCredentials = introspectionCredentials; } public CodeGrant getCodeGrant() { return codeGrant; } public void setCodeGrant(CodeGrant codeGrant) { this.codeGrant = codeGrant; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy