Securing Applications and Services Guide (2024)

This section describes how you can secure applications and services with OpenID Connect using Keycloak.

2.1. Available Endpoints

As a fully-compliant OpenID Connect Provider implementation, Keycloak exposes a set of endpoints that applicationsand services can use to authenticate and authorize their users.

This section describes some of the key endpoints that your application and service should use wheninteracting with Keycloak.

2.1.1. Endpoints

The most important endpoint to understand is the well-known configuration endpoint. It lists endpoints and other configuration options relevant to the OpenID Connect implementation in Keycloak. The endpoint is:

/realms/{realm-name}/.well-known/openid-configuration

To obtain the full URL, add the base URL for Keycloak and replace {realm-name} with the name of your realm. For example:

http://localhost:8080/realms/master/.well-known/openid-configuration

Some RP libraries retrieve all required endpoints from this endpoint, but for others you might need to list the endpoints individually.

Authorization endpoint
/realms/{realm-name}/protocol/openid-connect/auth

The authorization endpoint performs authentication of the end-user. This authentication is done by redirecting the user agent to this endpoint.

For more details see the Authorization Endpoint section in the OpenID Connect specification.

Token endpoint
/realms/{realm-name}/protocol/openid-connect/token

The token endpoint is used to obtain tokens. Tokens can either be obtained by exchanging an authorization code or by supplying credentials directly depending on what flow is used.The token endpoint is also used to obtain new access tokens when they expire.

For more details, see the Token Endpoint section in the OpenID Connect specification.

Userinfo endpoint
/realms/{realm-name}/protocol/openid-connect/userinfo

The userinfo endpoint returns standard claims about the authenticated user; this endpoint is protected by a bearer token.

For more details, see the Userinfo Endpoint section in the OpenID Connect specification.

Logout endpoint
/realms/{realm-name}/protocol/openid-connect/logout

The logout endpoint logs out the authenticated user.

The user agent can be redirected to the endpoint, which causes the active user session to be logged out. The user agent is then redirected back to the application.

The endpoint can also be invoked directly by the application. To invoke this endpoint directly, the refresh token needs to be included as well as the credentials required to authenticate the client.

Certificate endpoint
/realms/{realm-name}/protocol/openid-connect/certs

The certificate endpoint returns the public keys enabled by the realm, encoded as a JSON Web Key (JWK). Depending on the realm settings, one or more keys can be enabled for verifying tokens. For more information, see the Server Administration Guide and the JSON Web Key specification.

Introspection endpoint
/realms/{realm-name}/protocol/openid-connect/token/introspect

The introspection endpoint is used to retrieve the active state of a token. In other words, you can use it to validate an access or refresh token.This endpoint can only be invoked by confidential clients.

For more details on how to invoke on this endpoint, see OAuth 2.0 Token Introspection specification.

Introspection endpoint triggered with application/jwt header

You can invoke an introspection endpoint with the HTTP header Accept: application/jwt instead of Accept: application/json. In case of application/jwt, the responsemay contain the additional claim jwt with the full JWT access token, which can be useful especially if the token to be introspected was a lightweight access token. This requires that you enable Support JWT claim in Introspection Responseon the client advanced settings, which triggers the token introspection.

Dynamic Client Registration endpoint
/realms/{realm-name}/clients-registrations/openid-connect

The dynamic client registration endpoint is used to dynamically register clients.

For more details, see the Client Registration chapter and theOpenID Connect Dynamic Client Registration specification.

Token Revocation endpoint
/realms/{realm-name}/protocol/openid-connect/revoke

The token revocation endpoint is used to revoke tokens. Both refresh tokens and access tokens are supported by this endpoint. When revoking a refresh token, the user consent for the corresponding client is also revoked.

For more details on how to invoke on this endpoint, see OAuth 2.0 Token Revocation specification.

Device Authorization endpoint
/realms/{realm-name}/protocol/openid-connect/auth/device

The device authorization endpoint is used to obtain a device code and a user code. It can be invoked by confidential or public clients.

For more details on how to invoke on this endpoint, see OAuth 2.0 Device Authorization Grant specification.

Backchannel Authentication endpoint
/realms/{realm-name}/protocol/openid-connect/ext/ciba/auth

The backchannel authentication endpoint is used to obtain an auth_req_id that identifies the authentication request made by the client. It can only be invoked by confidential clients.

For more details on how to invoke on this endpoint, see OpenID Connect Client Initiated Backchannel Authentication Flow specification.

Also refer to other places of Keycloak documentation like Client Initiated Backchannel Authentication Grant section of this guide and Client Initiated Backchannel Authentication Grant section of Server Administration Guide.

2.2. Supported Grant Types

This section describes the different grant types available to relaying parties.

2.2.1. Authorization code

The Authorization Code flow redirects the user agent to Keycloak. Once the user has successfully authenticated with Keycloak, anAuthorization Code is created and the user agent is redirected back to the application. The application then uses the authorization code along with itscredentials to obtain an Access Token, Refresh Token and ID Token from Keycloak.

The flow is targeted towards web applications, but is also recommended for native applications, including mobile applications, where it is possible to embeda user agent.

For more details refer to the Authorization Code Flow in the OpenID Connect specification.

2.2.2. Implicit

The Implicit flow works similarly to the Authorization Code flow, but instead of returning an Authorization Code, the Access Token and ID Token isreturned. This approach reduces the need for the extra invocation to exchange the Authorization Code for an Access Token. However, it does not include a RefreshToken. This results in the need to permit Access Tokens with a long expiration; however, that approach is not practical because it is very hard to invalidate these tokens. Alternatively, you canrequire a new redirect to obtain a new Access Token once the initial Access Token has expired. The Implicit flow is useful if the application only wants toauthenticate the user and deals with logout itself.

You can instead use a Hybrid flow where both the Access Token and an Authorization Code are returned.

One thing to note is that both the Implicit flow and Hybrid flow have potential security risks as the Access Token may be leaked through web server logs andbrowser history. You can somewhat mitigate this problem by using short expiration for Access Tokens.

For more details, see the Implicit Flow in the OpenID Connect specification.

Per current OAuth 2.0 Security Best Current Practice, this flow should not be used.This flow is removed from the future OAuth 2.1 specification.

2.2.3. Resource Owner Password Credentials

Resource Owner Password Credentials, referred to as Direct Grant in Keycloak, allows exchanging user credentials for tokens.Per current OAuth 2.0 Security Best Practices,this flow should not be used, preferring alternative methods such as Device Authorization Grant or Authorization code.

The limitations of using this flow include:

  • User credentials are exposed to the application

  • Applications need login pages

  • Application needs to be aware of the authentication scheme

  • Changes to authentication flow requires changes to application

  • No support for identity brokering or social login

  • Flows are not supported (user self-registration, required actions, and so on.)

Security concerns with this flow include:

  • Involving more than Keycloak in handling of credentials

  • Increased vulnerable surface area where credential leaks can happen

  • Creating an ecosystem where users trust another application for entering their credentials and not Keycloak

For a client to be permitted to use the Resource Owner Password Credentials grant, the client has to have the Direct Access Grants Enabled option enabled.

This flow is not included in OpenID Connect, but is a part of the OAuth 2.0 specification.It is removed from the future OAuth 2.1 specification.

For more details, see the Resource Owner Password Credentials Grant chapter in the OAuth 2.0 specification.

Example using CURL

The following example shows how to obtain an access token for a user in the realm master with username user and password password. The example is usingthe confidential client myclient:

curl \ -d "client_id=myclient" \ -d "client_secret=40cc097b-2a57-4c17-b36a-8fdf3fc2d578" \ -d "username=user" \ -d "password=password" \ -d "grant_type=password" \ "http://localhost:8080/realms/master/protocol/openid-connect/token"

2.2.4. Client credentials

Client Credentials are used when clients (applications and services) want to obtain access on behalf of themselves rather than on behalf of a user. For example, these credentials can be useful for background services that apply changes to the system in general rather than for a specific user.

Keycloak provides support for clients to authenticate either with a secret or with public/private keys.

This flow is not included in OpenID Connect, but is a part of the OAuth 2.0 specification.

For more details, see the Client Credentials Grant chapter in the OAuth 2.0 specification.

2.2.5. Device Authorization Grant

Device Authorization Grant is used by clients running on internet-connected devices that have limited input capabilities or lack a suitable browser.

  1. The application requests that Keycloak provide a device code and a user code.

  2. Keycloak creates a device code and a user code.

  3. Keycloak returns a response including the device code and the user code to the application.

  4. The application provides the user with the user code and the verification URI. The user accesses a verification URI to be authenticated by using another browser.

  5. The application repeatedly polls Keycloak until Keycloak completes the user authorization.

  6. If user authentication is complete, the application obtains the device code.

  7. The application uses the device code along with its credentials to obtain an Access Token, Refresh Token and ID Token from Keycloak.

2.2.6. Client Initiated Backchannel Authentication Grant

Client Initiated Backchannel Authentication Grant is used by clients who want to initiate the authentication flow by communicating with the OpenID Provider directly without redirect through the user’s browser like OAuth 2.0’s authorization code grant.

The client requests from Keycloak an auth_req_id that identifies the authentication request made by the client. Keycloak creates the auth_req_id.

After receiving this auth_req_id, this client repeatedly needs to poll Keycloak to obtain an Access Token, Refresh Token, and ID Token from Keycloak in return for the auth_req_id until the user is authenticated.

In case that client uses ping mode, it does not need to repeatedly poll the token endpoint, but it can wait for the notification sent by Keycloak to the specified Client Notification Endpoint.The Client Notification Endpoint can be configured in the Keycloak Admin Console. The details of the contract for Client Notification Endpoint are described in the CIBA specification.

Also refer to other places of Keycloak documentation such as Backchannel Authentication Endpoint of this guide and Client Initiated Backchannel Authentication Grant section of Server Administration Guide.For the details about FAPI CIBA compliance, see the FAPI section of this guide.

2.3. Keycloak specific errors

Keycloak server can send errors to the client application in the OIDC authentication response with parameters error=temporarily_unavailable and error_description=authentication_expired.Keycloak sends this error when a user is authenticated and has an SSO session, but the authentication session expired in the current browser tab and hence the Keycloak server cannot automatically do SSOre-authentication of the user and redirect back to client with a successful response. When a client application receives this type of error, it is ideal to retry authentication immediately and send a newOIDC authentication request to the Keycloak server, which should typically always authenticate the user due to the SSO session and redirect back. For more details, seethe Server Administration Guide.

2.4. Keycloak Java adapters

Keycloak Java Adapters were removed from Keycloak codebase and they are not supported anymore.

For more details about how to integrate Keycloak with Java applications, consider looking at theKeycloak Quickstart GitHub Repository.

2.5. Keycloak JavaScript adapter

Keycloak comes with a client-side JavaScript library called keycloak-js that can be used to secure web applications. The adapter also comes with built-in support for Cordova applications.

2.5.1. Installation

The adapter is distributed in several ways, but we recommend that you install the keycloak-js package from NPM:

npm install keycloak-js

Alternatively, the library can be retrieved directly from the Keycloak server at /js/keycloak.js and is also distributed as a ZIP archive. We are however considering the inclusion of the adapter directly from the Keycloak server as deprecated, and this functionality might be removed in the future.

2.5.2. Keycloak server configuration

One important thing to consider about using client-side applications is that the client has to be a public client as there is no secure way to store client credentials in a client-side application. This consideration makes it very important to make sure the redirect URIs you have configured for the client are correct and as specific as possible.

To use the adapter, create a client for your application in the Keycloak Admin Console. Make the client public by toggling Client authentication to Off on the Capability config page.

You also need to configure Valid Redirect URIs and Web Origins. Be as specific as possible as failing to do so may result in a security vulnerability.

2.5.3. Using the adapter

The following example shows how to initialize the adapter. Make sure that you replace the options passed to the Keycloak constructor with those of the client you have configured.

import Keycloak from 'keycloak-js';const keycloak = new Keycloak({ url: 'http://keycloak-server${kc_base_path}', realm: 'myrealm', clientId: 'myapp'});try { const authenticated = await keycloak.init(); console.log(`User is ${authenticated ? 'authenticated' : 'not authenticated'}`);} catch (error) { console.error('Failed to initialize adapter:', error);}

To authenticate, you call the login function. Two options exist to make the adapter automatically authenticate. You can pass login-required or check-sso to the init() function.

  • login-required authenticates the client if the user is logged in to Keycloak or displays the login page if the user is not logged in.

  • check-sso only authenticates the client if the user is already logged in. If the user is not logged in, the browser is redirected back to the application and remains unauthenticated.

You can configure a silent check-sso option. With this feature enabled, your browser will not perform a full redirect to the Keycloak server and back to your application, but this action will be performed in a hidden iframe. Therefore, your application resources are only loaded and parsed once by the browser, namely when the application is initialized and not again after the redirect back from Keycloak to your application. This approach is particularly useful in case of SPAs (Single Page Applications).

To enable the silent check-sso, you provide a silentCheckSsoRedirectUri attribute in the init method. Make sure this URI is a valid endpoint in the application; it must be configured as a valid redirect for the client in the Keycloak Admin Console:

keycloak.init({ onLoad: 'check-sso', silentCheckSsoRedirectUri: `${location.origin}/silent-check-sso.html`});

The page at the silent check-sso redirect uri is loaded in the iframe after successfully checking your authentication state and retrieving the tokens from the Keycloak server.It has no other task than sending the received tokens to the main application and should only look like this:

<!doctype html><html><body> <script> parent.postMessage(location.href, location.origin); </script></body></html>

Remember that this page must be served by your application at the specified location in silentCheckSsoRedirectUri and is not part of the adapter.

Silent check-sso functionality is limited in some modern browsers. Please see the Modern Browsers with Tracking Protection Section.

To enable login-required set onLoad to login-required and pass to the init method:

keycloak.init({ onLoad: 'login-required'});

After the user is authenticated the application can make requests to RESTful services secured by Keycloak by including the bearer token in theAuthorization header. For example:

async function fetchUsers() { const response = await fetch('/api/users', { headers: { accept: 'application/json', authorization: `Bearer ${keycloak.token}` } }); return response.json();}

One thing to keep in mind is that the access token by default has a short life expiration so you may need to refresh the access token prior to sending the request. You refresh this token by calling the updateToken() method. This method returns a Promise, which makes it easy to invoke the service only if the token was successfully refreshed and displays an error to the user if it was not refreshed. For example:

try { await keycloak.updateToken(30);} catch (error) { console.error('Failed to refresh token:', error);}const users = await fetchUsers();

Both access and refresh token are stored in memory and are not persisted in any kind of storage. Therefore, these tokens should never be persisted to prevent hijacking attacks.

2.5.4. Session Status iframe

By default, the adapter creates a hidden iframe that is used to detect if a Single-Sign Out has occurred. This iframe does not require any network traffic. Instead the status is retrieved by looking at a special status cookie. This feature can be disabled by setting checkLoginIframe: false in the options passed to the init() method.

You should not rely on looking at this cookie directly. Its format can change and it’s also associated with the URL of the Keycloak server, notyour application.

Session Status iframe functionality is limited in some modern browsers. Please see Modern Browsers with Tracking Protection Section.

2.5.5. Implicit and hybrid flow

By default, the adapter uses the Authorization Code flow.

With this flow, the Keycloak server returns an authorization code, not an authentication token, to the application. The JavaScript adapter exchanges the code for an access token and a refresh token after the browser is redirected back to the application.

Keycloak also supports the Implicit flow where an access token is sent immediately after successful authentication with Keycloak. This flow may have better performance than the standard flow because no additional request exists to exchange the code for tokens, but it has implications when the access token expires.

However, sending the access token in the URL fragment can be a security vulnerability. For example the token could be leaked through web server logs and orbrowser history.

To enable implicit flow, you enable the Implicit Flow Enabled flag for the client in the Keycloak Admin Console. You also pass the parameter flow with the value implicit to init method:

keycloak.init({ flow: 'implicit'})

Note that only an access token is provided and no refresh token exists. This situation means that once the access token has expired, the application has to redirect to Keycloak again to obtain a new access token.

Keycloak also supports the Hybrid flow.

This flow requires the client to have both the Standard Flow and Implicit Flow enabled in the Admin Console. The Keycloak server then sends both the code and tokens to your application. The access token can be used immediately while the code can be exchanged for access and refresh tokens. Similar to the implicit flow, the hybrid flow is good for performance because the access token is available immediately.But, the token is still sent in the URL, and the security vulnerability mentioned earlier may still apply.

One advantage in the Hybrid flow is that the refresh token is made available to the application.

For the Hybrid flow, you need to pass the parameter flow with value hybrid to the init method:

keycloak.init({ flow: 'hybrid'});

2.5.6. Hybrid Apps with Cordova

Keycloak supports hybrid mobile apps developed with Apache Cordova. The adapter has two modes for this: cordova and cordova-native:

The default is cordova, which the adapter automatically selects if no adapter type has been explicitly configured and window.cordova is present. When logging in, it opens an InApp Browser that lets the user interact with Keycloak and afterwards returns to the app by redirecting to http://localhost. Because of this behavior, you whitelist this URL as a valid redirect-uri in the client configuration section of the Admin Console.

While this mode is easy to set up, it also has some disadvantages:

  • The InApp-Browser is a browser embedded in the app and is not the phone’s default browser. Therefore it will have different settings and stored credentials will not be available.

  • The InApp-Browser might also be slower, especially when rendering more complex themes.

  • There are security concerns to consider, before using this mode, such as that it is possible for the app to gain access to the credentials of the user, as it has full control of the browser rendering the login page, so do not allow its use in apps you do not trust.

The alternative mode is`cordova-native`, which takes a different approach. It opens the login page using the system’s browser. After the user has authenticated, the browser redirects back into the application using a special URL. From there, the Keycloak adapter can finish the login by reading the code or token from the URL.

You can activate the native mode by passing the adapter type cordova-native to the init() method:

keycloak.init({ adapter: 'cordova-native'});

This adapter requires two additional plugins:

The technical details for linking to an app differ on each platform and special setup is needed.Please refer to the Android and iOS sections of the deeplinks plugin documentation for further instructions.

Different kinds of links exist for opening apps:* custom schemes, such as myapp://login or android-app://com.example.myapp/https/example.com/login* Universal Links (iOS)) / Deep Links (Android).While the former are easier to set up and tend to work more reliably, the latter offer extra security because they are unique and only the owner of a domain can register them. Custom-URLs are deprecated on iOS. For best reliability, we recommend that you use universal links combined with a fallback site that uses a custom-url link.

Furthermore, we recommend the following steps to improve compatibility with the adapter:

  • Universal Links on iOS seem to work more reliably with response-mode set to query

  • To prevent Android from opening a new instance of your app on redirect add the following snippet to config.xml:

<preference name="AndroidLaunchMode" value="singleTask" />

2.5.7. Custom Adapters

In some situations, you may need to run the adapter in environments that are not supported by default, such as Capacitor. To use the JavasScript client in these environments, you can pass a custom adapter. For example, a third-party library could provide such an adapter to make it possible to reliably run the adapter:

import Keycloak from 'keycloak-js';import KeycloakCapacitorAdapter from 'keycloak-capacitor-adapter';const keycloak = new Keycloak();keycloak.init({ adapter: KeycloakCapacitorAdapter,});

This specific package does not exist, but it gives a pretty good example of how such an adapter could be passed into the client.

It’s also possible to make your own adapter, to do so you will have to implement the methods described in the KeycloakAdapter interface. For example the following TypeScript code ensures that all the methods are properly implemented:

import Keycloak, { KeycloakAdapter } from 'keycloak-js';// Implement the 'KeycloakAdapter' interface so that all required methods are guaranteed to be present.const MyCustomAdapter: KeycloakAdapter = { login(options) { // Write your own implementation here. } // The other methods go here...};const keycloak = new Keycloak();keycloak.init({ adapter: MyCustomAdapter,});

Naturally you can also do this without TypeScript by omitting the type information, but ensuring implementing the interface properly will then be left entirely up to you.

2.5.8. Modern Browsers with Tracking Protection

In the latest versions of some browsers, various cookies policies are applied to prevent tracking of the users by third parties, such as SameSite in Chrome or completely blocked third-party cookies. Those policies are likely to become more restrictive and adopted by other browsers over time. Eventually cookies in third-party contexts may become completely unsupported and blocked by the browsers. As a result, the affected adapter features might ultimately be deprecated.

The adapter relies on third-party cookies for Session Status iframe, silent check-sso and partially also for regular (non-silent) check-sso. Those features have limited functionality or are completely disabled based on how restrictive the browser is regarding cookies. The adapter tries to detect this setting and reacts accordingly.

Browsers with "SameSite=Lax by Default" Policy

All features are supported if SSL / TLS connection is configured on the Keycloak side as well as on the application side. For example, Chrome is affected starting with version 84.

Browsers with Blocked Third-Party Cookies

Session Status iframe is not supported and is automatically disabled if such browser behavior is detected by the adapter. This means the adapter cannot use a session cookie for Single Sign-Out detection and must rely purely on tokens. As a result, when a user logs out in another window, the application using the adapter will not be logged out until the application tries to refresh the Access Token. Therefore, consider setting the Access Token Lifespan to a relatively short time, so that the logout is detected as soon as possible. For more details, see Session and Token Timeouts.

Silent check-sso is not supported and falls back to regular (non-silent) check-sso by default. This behavior can be changed by setting silentCheckSsoFallback: false in the options passed to the init method. In this case, check-sso will be completely disabled if restrictive browser behavior is detected.

Regular check-sso is affected as well. Since Session Status iframe is unsupported, an additional redirect to Keycloak has to be made when the adapter is initialized to check the user’s login status. This check is different from the standard behavior when the iframe is used to tell whether the user is logged in, and the redirect is performed only when the user is logged out.

An affected browser is for example Safari starting with version 13.1.

2.5.9. API Reference

Constructor
new Keycloak();new Keycloak('http://localhost/keycloak.json');new Keycloak({ url: 'http://localhost', realm: 'myrealm', clientId: 'myApp' });
Properties
authenticated

Is true if the user is authenticated, false otherwise.

token

The base64 encoded token that can be sent in the Authorization header in requests to services.

tokenParsed

The parsed token as a JavaScript object.

subject

The user id.

idToken

The base64 encoded ID token.

idTokenParsed

The parsed id token as a JavaScript object.

realmAccess

The realm roles associated with the token.

resourceAccess

The resource roles associated with the token.

refreshToken

The base64 encoded refresh token that can be used to retrieve a new token.

refreshTokenParsed

The parsed refresh token as a JavaScript object.

timeSkew

The estimated time difference between the browser time and the Keycloak server in seconds. This value is just an estimation, but is accurateenough when determining if a token is expired or not.

responseMode

Response mode passed in init (default value is fragment).

flow

Flow passed in init.

adapter

Allows you to override the way that redirects and other browser-related functions will be handled by the library.Available options:

  • "default" - the library uses the browser api for redirects (this is the default)

  • "cordova" - the library will try to use the InAppBrowser cordova plugin to load keycloak login/registration pages (this is used automatically when the library is working in a cordova ecosystem)

  • "cordova-native" - the library tries to open the login and registration page using the phone’s system browser using the BrowserTabs cordova plugin. This requires extra setup for redirecting back to the app (see Hybrid Apps with Cordova).

  • "custom" - allows you to implement a custom adapter (only for advanced use cases)

responseType

Response type sent to Keycloak with login requests. This is determined based on the flow value used during initialization, but can be overridden by setting this value.

Methods

init(options)

Called to initialize the adapter.

Options is an Object, where:

  • useNonce - Adds a cryptographic nonce to verify that the authentication response matches the request (default is true).

  • onLoad - Specifies an action to do on load. Supported values are login-required or check-sso.

  • silentCheckSsoRedirectUri - Set the redirect uri for silent authentication check if onLoad is set to 'check-sso'.

  • silentCheckSsoFallback - Enables fall back to regular check-sso when silent check-sso is not supported by the browser (default is true).

  • token - Set an initial value for the token.

  • refreshToken - Set an initial value for the refresh token.

  • idToken - Set an initial value for the id token (only together with token or refreshToken).

  • scope - Set the default scope parameter to the Keycloak login endpoint. Use a space-delimited list of scopes. Those typicallyreference Client scopes defined on a particular client. Note that the scope openid willalways be added to the list of scopes by the adapter. For example, if you enter the scope options address phone, then the requestto Keycloak will contain the scope parameter scope=openid address phone. Note that the default scope specified here is overwritten if the login() options specify scope explicitly.

  • timeSkew - Set an initial value for skew between local time and Keycloak server in seconds (only together with token or refreshToken).

  • checkLoginIframe - Set to enable/disable monitoring login state (default is true).

  • checkLoginIframeInterval - Set the interval to check login state (default is 5 seconds).

  • responseMode - Set the OpenID Connect response mode send to Keycloak server at login request. Valid values are query or fragment. Default value is fragment, which means that after successful authentication will Keycloak redirect to JavaScript application with OpenID Connect parameters added in URL fragment. This is generally safer and recommended over query.

  • flow - Set the OpenID Connect flow. Valid values are standard, implicit or hybrid.

  • enableLogging - Enables logging messages from Keycloak to the console (default is false).

  • pkceMethod - The method for Proof Key Code Exchange (PKCE) to use. Configuring this value enables the PKCE mechanism. Available options:

    • "S256" - The SHA256 based PKCE method (default)

    • false - PKCE is disabled.

  • acrValues - Generates the acr_values parameter which refers to authentication context class reference and allows clients to declare the required assurance level requirements, e.g. authentication mechanisms. See Section 4. acr_values request values and level of assurance in OpenID Connect MODRNA Authentication Profile 1.0.

  • messageReceiveTimeout - Set a timeout in milliseconds for waiting for message responses from the Keycloak server. This is used, for example, when waiting for a message during 3rd party cookies check. The default value is 10000.

  • locale - When onLoad is 'login-required', sets the 'ui_locales' query param in compliance with section 3.1.2.1 of the OIDC 1.0 specification.

Returns a promise that resolves when initialization completes.

login(options)

Redirects to login form.

Options is an optional Object, where:

  • redirectUri - Specifies the uri to redirect to after login.

  • prompt - This parameter allows to slightly customize the login flow on the Keycloak server side.For example, enforce displaying the login screen in case of value login. Or enforce displaying of consent screen for the value consent in case that client has Consent Required.Finally it is possible use the value none to make sure that login screen is not displayed to the user, which is useful just to check SSO for the case when user was alreadyauthenticated before (This is related to the onLoad check with value check-sso described above).

  • maxAge - Used just if user is already authenticated. Specifies maximum time since the authentication of user happened. If user is already authenticated for longer time than maxAge, the SSO is ignored and he will need to re-authenticate again.

  • loginHint - Used to pre-fill the username/email field on the login form.

  • scope - Override the scope configured in init with a different value for this specific login.

  • idpHint - Used to tell Keycloak to skip showing the login page and automatically redirect to the specified identityprovider instead. More info in the Identity Provider documentation.

  • acr - Contains the information about acr claim, which will be sent inside claims parameter to the Keycloak server. Typical usageis for step-up authentication. Example of use { values: ["silver", "gold"], essential: true }. See OpenID Connect specificationand Step-up authentication documentation for more details.

  • acrValues - Generates the acr_values parameter which refers to authentication context class reference and allows clients to declare the required assurance level requirements, e.g. authentication mechanisms. See Section 4. acr_values request values and level of assurance in OpenID Connect MODRNA Authentication Profile 1.0.

  • action - If the value is register, the user is redirected to the registration page. See Registration requested by client section for more details.If the value is UPDATE_PASSWORD or another supported required action, the user will be redirected to the reset password page or the other required action page. However, if the user is not authenticated, the user will be sent to the login page and redirected after authentication.See Application Initiated Action section for more details.

  • locale - Sets the 'ui_locales' query param in compliance with section 3.1.2.1 of the OIDC 1.0 specification.

  • cordovaOptions - Specifies the arguments that are passed to the Cordova in-app-browser (if applicable). Options hidden and location are not affected by these arguments. All available options are defined at https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-inappbrowser/. Example of use: { zoom: "no", hardwareback: "yes" };

createLoginUrl(options)

Returns the URL to login form.

Options is an optional Object, which supports same options as the function login .

logout(options)

Redirects to logout.

Options is an Object, where:

  • redirectUri - Specifies the uri to redirect to after logout.

createLogoutUrl(options)

Returns the URL to log out the user.

Options is an Object, where:

  • redirectUri - Specifies the uri to redirect to after logout.

register(options)

Redirects to registration form. Shortcut for login with option action = 'register'

Options are same as for the login method but 'action' is set to 'register'

createRegisterUrl(options)

Returns the url to registration page. Shortcut for createLoginUrl with option action = 'register'

Options are same as for the createLoginUrl method but 'action' is set to 'register'

accountManagement()

Redirects to the Account Console.

createAccountUrl(options)

Returns the URL to the Account Console.

Options is an Object, where:

  • redirectUri - Specifies the uri to redirect to when redirecting back to the application.

hasRealmRole(role)

Returns true if the token has the given realm role.

hasResourceRole(role, resource)

Returns true if the token has the given role for the resource (resource is optional, if not specified clientId is used).

loadUserProfile()

Loads the users profile.

Returns a promise that resolves with the profile.

For example:

try { const profile = await keycloak.loadUserProfile(); console.log('Retrieved user profile:', profile);} catch (error) { console.error('Failed to load user profile:', error);}

isTokenExpired(minValidity)

Returns true if the token has less than minValidity seconds left before it expires (minValidity is optional, if not specified 0 is used).

updateToken(minValidity)

If the token expires within minValidity seconds (minValidity is optional, if not specified 5 is used) the token is refreshed.If -1 is passed as the minValidity, the token will be forcibly refreshed.If the session status iframe is enabled, the session status is also checked.

Returns a promise that resolves with a boolean indicating whether or not the token has been refreshed.

For example:

try { const refreshed = await keycloak.updateToken(5); console.log(refreshed ? 'Token was refreshed' : 'Token is still valid');} catch (error) { console.error('Failed to refresh the token:', error);}

clearToken()

Clear authentication state, including tokens.This can be useful if application has detected the session was expired, for example if updating token fails.

Invoking this results in onAuthLogout callback listener being invoked.

Callback Events

The adapter supports setting callback listeners for certain events. Keep in mind that these have to be set before the call to the init() method.

For example:

keycloak.onAuthSuccess = () => console.log('Authenticated!');

The available events are:

  • onReady(authenticated) - Called when the adapter is initialized.

  • onAuthSuccess - Called when a user is successfully authenticated.

  • onAuthError - Called if there was an error during authentication.

  • onAuthRefreshSuccess - Called when the token is refreshed.

  • onAuthRefreshError - Called if there was an error while trying to refresh the token.

  • onAuthLogout - Called if the user is logged out (will only be called if the session status iframe is enabled, or in Cordova mode).

  • onTokenExpired - Called when the access token is expired. If a refresh token is available the token can be refreshed with updateToken, or in cases where it is not (that is, with implicit flow) you can redirect to the login screen to obtain a new access token.

2.6. Keycloak Node.js adapter

Keycloak provides a Node.js adapter built on top of Connect to protect server-side JavaScript apps - the goal was to be flexible enough to integrate with frameworks like Express.js.

The library can be downloaded directly from Keycloak organization and the source is available atGitHub.

To use the Node.js adapter, first you must create a client for your application in the Keycloak Admin Console. The adapter supports public, confidential, and bearer-only access type. Which one to choose depends on the use-case scenario.

Once the client is created, click Action at the top right and choose Download adapter config. For Format, choose *Keycloak OIDC JSON and click Download. The downloaded keycloak.json file is at the root folder of your project.

2.6.1. Installation

Assuming you have already installed Node.js, create a folder for your application:

mkdir myapp && cd myapp

Use npm init command to create a package.json for your application. Now add the Keycloak connect adapter in the dependencies list:

 "dependencies": { "keycloak-connect": "25.0.4" }

2.6.2. Usage

Instantiate a Keycloak class

The Keycloak class provides a central point for configurationand integration with your application. The simplest creationinvolves no arguments.

In the root directory of your project create a file called server.js and add the following code:

 const session = require('express-session'); const Keycloak = require('keycloak-connect'); const memoryStore = new session.MemoryStore(); const keycloak = new Keycloak({ store: memoryStore });

Install the express-session dependency:

 npm install express-session

To start the server.js script, add the following command in the 'scripts' section of the package.json:

 "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "node server.js" },

Now we have the ability to run our server with following command:

 npm run start

By default, this will locate a file named keycloak.json alongsidethe main executable of your application, in our case on the root folder, to initialize Keycloak specificsettings such as public key, realm name, various URLs.

In that case a Keycloak deployment is necessary to access Keycloak admin console.

Please visit links on how to deploy a Keycloak admin console withPodman or Docker

Now we are ready to obtain the keycloak.json file by visiting the Keycloak Admin Console → clients (left sidebar) → choose your client → Installation → Format Option → Keycloak OIDC JSON → Download

Paste the downloaded file on the root folder of our project.

Instantiation with this method results in all the reasonable defaultsbeing used. As alternative, it’s also possible to provide a configurationobject, rather than the keycloak.json file:

 const kcConfig = { clientId: 'myclient', bearerOnly: true, serverUrl: 'http://localhost:8080', realm: 'myrealm', realmPublicKey: 'MIIBIjANB...' }; const keycloak = new Keycloak({ store: memoryStore }, kcConfig);

Applications can also redirect users to their preferred identity provider by using:

 const keycloak = new Keycloak({ store: memoryStore, idpHint: myIdP }, kcConfig);
Configuring a web session store

If you want to use web sessions to manageserver-side state for authentication, you need to initialize theKeycloak(…​) with at least a store parameter, passing in the actualsession store that express-session is using.

 const session = require('express-session'); const memoryStore = new session.MemoryStore(); // Configure session app.use( session({ secret: 'mySecret', resave: false, saveUninitialized: true, store: memoryStore, }) ); const keycloak = new Keycloak({ store: memoryStore });
Passing a custom scope value

By default, the scope value openid is passed as a query parameter to Keycloak’s login URL, but you can add an additional custom value:

 const keycloak = new Keycloak({ scope: 'offline_access' });

2.6.3. Installing middleware

Once instantiated, install the middleware into your connect-capable app:

In order to do so, first we have to install Express:

 npm install express

then require Express in our project as outlined below:

 const express = require('express'); const app = express();

and configure Keycloak middleware in Express, by adding at the code below:

 app.use( keycloak.middleware() );

Last but not least, let’s set up our server to listen for HTTP requests on port 3000 by adding the following code to main.js:

 app.listen(3000, function () { console.log('App listening on port 3000'); });

2.6.4. Configuration for proxies

If the application is running behind a proxy that terminates an SSL connectionExpress must be configured per the express behind proxies guide.Using an incorrect proxy configuration can result in invalid redirect URIsbeing generated.

Example configuration:

 const app = express(); app.set( 'trust proxy', true ); app.use( keycloak.middleware() );

2.6.5. Protecting resources

Simple authentication

To enforce that a user must be authenticated before accessing a resource,simply use a no-argument version of keycloak.protect():

 app.get( '/complain', keycloak.protect(), complaintHandler );
Role-based authorization

To secure a resource with an application role for the current app:

 app.get( '/special', keycloak.protect('special'), specialHandler );

To secure a resource with an application role for a different app:

 app.get( '/extra-special', keycloak.protect('other-app:special'), extraSpecialHandler );

To secure a resource with a realm role:

 app.get( '/admin', keycloak.protect( 'realm:admin' ), adminHandler );
Resource-Based Authorization

Resource-Based Authorization allows you to protect resources, and their specific methods/actions,** based on a set of policies defined in Keycloak, thus externalizing authorization from your application. This is achieved by exposing a keycloak.enforcer method which you can use to protect resources.*

 app.get('/apis/me', keycloak.enforcer('user:profile'), userProfileHandler);

The keycloak-enforcer method operates in two modes, depending on the value of the response_mode configuration option.

 app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'token'}), userProfileHandler);

If response_mode is set to token, permissions are obtained from the server on behalf of the subject represented by the bearer token that was sent to your application. In this case, a new access token is issued by Keycloak with the permissions granted by the server. If the server did not respond with a token with the expected permissions, the request is denied. When using this mode, you should be able to obtain the token from the request as follows:

 app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'token'}), function (req, res) { const token = req.kauth.grant.access_token.content; const permissions = token.authorization ? token.authorization.permissions : undefined; // show user profile });

Prefer this mode when your application is using sessions and you want to cache previous decisions from the server, as well automatically handle refresh tokens. This mode is especially useful for applications acting as a client and resource server.

If response_mode is set to permissions (default mode), the server only returns the list of granted permissions, without issuing a new access token. In addition to not issuing a new token, this method exposes the permissions granted by the server through the request as follows:

 app.get('/apis/me', keycloak.enforcer('user:profile', {response_mode: 'permissions'}), function (req, res) { const permissions = req.permissions; // show user profile });

Regardless of the response_mode in use, the keycloak.enforcer method will first try to check the permissions within the bearer token that was sent to your application. If the bearer token already carries the expected permissions, there is no needto interact with the server to obtain a decision. This is specially useful when your clients are capable of obtaining access tokens from the server with the expected permissions before accessing a protected resource, so they can use some capabilities provided by Keycloak Authorization Services such as incremental authorization and avoid additional requests to the server when keycloak.enforcer is enforcing access to the resource.

By default, the policy enforcer will use the client_id defined to the application (for instance, via keycloak.json) to reference a client in Keycloak that supports Keycloak Authorization Services. In this case, the client can not be public given that it is actually a resource server.

If your application is acting as both a public client(frontend) and resource server(backend), you can use the following configuration to reference a differentclient in Keycloak with the policies that you want to enforce:

 keycloak.enforcer('user:profile', {resource_server_id: 'my-apiserver'})

It is recommended to use distinct clients in Keycloak to represent your frontend and backend.

If the application you are protecting is enabled with Keycloak authorization services and you have defined client credentials in keycloak.json, you can push additional claims to the server and make them available to your policies in order to make decisions.For that, you can define a claims configuration option which expects a function that returns a JSON with the claims you want to push:

 app.get('/protected/resource', keycloak.enforcer(['resource:view', 'resource:write'], { claims: function(request) { return { "http.uri": ["/protected/resource"], "user.agent": // get user agent from request } } }), function (req, res) { // access granted

For more details about how to configure Keycloak to protected your application resources, please take a look at the Authorization Services Guide.

Advanced authorization

To secure resources based on parts of the URL itself, assuming a role existsfor each section:

 function protectBySection(token, request) { return token.hasRole( request.params.section ); } app.get( '/:section/:page', keycloak.protect( protectBySection ), sectionHandler );

Advanced Login Configuration:

By default, all unauthorized requests will be redirected to the Keycloak login page unless your client is bearer-only.However, a confidential or public client may host both browsable and API endpoints. To prevent redirects on unauthenticatedAPI requests and instead return an HTTP 401, you can override the redirectToLogin function.

For example, this override checks if the URL contains /api/ and disables login redirects:

 Keycloak.prototype.redirectToLogin = function(req) { const apiReqMatcher = /\/api\//i; return !apiReqMatcher.test(req.originalUrl || req.url); };

2.6.6. Additional URLs

Explicit user-triggered logout

By default, the middleware catches calls to /logout to send the user through aKeycloak-centric logout workflow. This can be changed by specifying a logoutconfiguration parameter to the middleware() call:

 app.use( keycloak.middleware( { logout: '/logoff' } ));

When the user-triggered logout is invoked a query parameter redirect_url can be passed:

https://example.com/logoff?redirect_url=https%3A%2F%2Fexample.com%3A3000%2Flogged%2Fout

This parameter is then used as the redirect url of the OIDC logout endpoint and the user will be redirected tohttps://example.com/logged/out.

Keycloak Admin Callbacks

Also, the middleware supports callbacks from the Keycloak console to log out a singlesession or all sessions. By default, these type of admin callbacks occur relativeto the root URL of / but can be changed by providing an admin parameterto the middleware() call:

 app.use( keycloak.middleware( { admin: '/callbacks' } );

2.6.7. Complete example

A complete example using the Node.js adapter usage can be found in Keycloak quickstarts for Node.js

2.7. mod_auth_openidc Apache HTTPD Module

Keycloak does not provide any official support to mod_auth_openidc. The instructions below are best-effort and may not be up-to-date.We recommend that you stick to official mod_auth_openidc documentation for more details.

The mod_auth_openidc is an Apache HTTP plugin for OpenID Connect. If your language/environment supports using Apache HTTPDas a proxy, then you can use mod_auth_openidc to secure your web application with OpenID Connect. Configuration of this moduleis beyond the scope of this document. Please see the mod_auth_openidc GitHub repo for more details on configuration.

To configure mod_auth_openidc you’ll need

  • The client_id.

  • The client_secret.

  • The redirect_uri to your application.

  • The Keycloak openid-configuration url

  • mod_auth_openidc specific Apache HTTPD module config.

An example configuration would look like the following.

LoadModule auth_openidc_module modules/mod_auth_openidc.soServerName ${HOSTIP}<VirtualHost *:80> ServerAdmin webmaster@localhost DocumentRoot /var/www/html #this is required by mod_auth_openidc OIDCCryptoPassphrase a-random-secret-used-by-apache-oidc-and-balancer OIDCProviderMetadataURL ${KC_ADDR}/realms/${KC_REALM}/.well-known/openid-configuration OIDCClientID ${CLIENT_ID} OIDCClientSecret ${CLIENT_SECRET} OIDCRedirectURI http://${HOSTIP}/${CLIENT_APP_NAME}/redirect_uri # maps the preferred_username claim to the REMOTE_USER environment variable OIDCRemoteUserClaim preferred_username <Location /${CLIENT_APP_NAME}/> AuthType openid-connect Require valid-user </Location></VirtualHost>

Further information on how to configure mod_auth_openidc can be found on the mod_auth_openidcproject page.

2.8. Financial-grade API (FAPI) Support

Keycloak makes it easier for administrators to make sure that their clients are compliant with these specifications:

This compliance means that the Keycloak server will verify the requirementsfor the authorization server, which are mentioned in the specifications. Keycloak adapters do not have any specific support for the FAPI, hence the required validations on the client (application)side may need to be still done manually or through some other third-party solutions.

2.8.1. FAPI client profiles

To make sure that your clients are FAPI compliant, you can configure Client Policies in your realm as described in the Server Administration Guideand link them to the global client profiles for FAPI support, which are automatically available in each realm. You can use either fapi-1-baseline or fapi-1-advanced profile based on which FAPIprofile you need your clients to conform with. You can use also profiles fapi-2-security-profile or fapi-2-message-signing for the compliance with FAPI 2 Draft specifications.

In case you want to use Pushed Authorization Request (PAR), it is recommended that your client useboth the fapi-1-baseline profile and fapi-1-advanced for PAR requests. Specifically, the fapi-1-baseline profile contains pkce-enforcer executor, which makes surethat client use PKCE with secured S256 algorithm. This is not required for FAPI Advanced clients unless they use PAR requests.

In case you want to use CIBA in a FAPI compliant way, make sure that your clients use both fapi-1-advanced and fapi-ciba client profiles.There is a need to use the fapi-1-advanced profile, or other client profile containing the requested executors, as the fapi-ciba profile contains just CIBA-specific executors.When enforcing the requirements of the FAPI CIBA specification, there is a need for more requirements, such as enforcement of confidential clients or certificate-bound access tokens.

2.8.2. Open Finance Brasil Financial-grade API Security Profile

Keycloak is compliant with the Open Finance Brasil Financial-grade API Security Profile 1.0 Implementers Draft 3.This one is stricter in some requirements than the FAPI 1 Advanced specification and hence it may be needed to configure Client Policiesin the more strict way to enforce some of the requirements. Especially:

  • If your client does not use PAR, make sure that it uses encrypted OIDC request objects. This can be achieved by using a client profile with the secure-request-object executor configured with Encryption Required enabled.

  • Make sure that for JWS, the client uses the PS256 algorithm. For JWE, the client should use the RSA-OAEP with A256GCM. This may need to be set in all the Client Settings where these algorithms are applicable.

2.8.3. Australia Consumer Data Right (CDR) Security Profile

Keycloak is compliant with the Australia Consumer Data Right Security Profile.

If you want to apply the Australia CDR security profile, you need to use fapi-1-advanced profile because the Australia CDR security profile is based on FAPI 1.0 Advanced security profile. If your client also applies PAR, make sure that client applies RFC 7637 Proof Key for Code Exchange (PKCE) because the Australia CDR security profile requires that you apply PKCE when applying PAR. This can be achieved by using a client profile with the pkce-enforcer executor.

2.8.4. TLS considerations

As confidential information is being exchanged, all interactions shall be encrypted with TLS (HTTPS). Moreover, there are some requirements in the FAPI specification forthe cipher suites and TLS protocol versions used. To match these requirements, you can consider configure allowed ciphers. This configuration can be done by settingthe https-protocols and https-cipher-suites options. Keycloak uses TLSv1.3 by default and hence it is possibly not needed to change the default settings. However itmay be needed to adjust ciphers if you need to fall back to lower TLS version for some reason. For more details, see Configuring TLS guide.

2.9. OAuth 2.1 Support

Keycloak makes it easier for administrators to make sure that their clients are compliant with these specifications:

This compliance means that the Keycloak server will verify the requirementsfor the authorization server, which are mentioned in the specifications. Keycloak adapters do not have any specific support for the OAuth 2.1, hence the required validations on the client (application)side may need to be still done manually or through some other third-party solutions.

2.9.1. OAuth 2.1 client profiles

To make sure that your clients are OAuth 2.1 compliant, you can configure Client Policies in your realm as described in the Server Administration Guideand link them to the global client profiles for OAuth 2.1 support, which are automatically available in each realm. You can use either oauth-2-1-for-confidential-client profile for confidential clients or oauth-2-1-for-public-client profile for public clients.

OAuth 2.1 specification is still a draft and it may change in the future. Hence the Keycloak built-in OAuth 2.1 client profiles can change as well.
When using OAuth 2.1 profile for public clients, it is recommended to use DPoP preview feature as described in the Server Administration Guide because DPoP binds an access token and a refresh token together with the public part of a client’s key pair. This binding prevents an attacker from using stolen tokens.

2.10. Recommendations

This section describes some recommendations when securing your applications with Keycloak.

2.10.1. Validating access tokens

If you need to manually validate access tokens issued by Keycloak, you can invoke the Introspection Endpoint.The downside to this approach is that you have to make a network invocation to the Keycloak server. This can be slow and possibly overload theserver if you have too many validation requests going on at the same time. Keycloak issued access tokens are JSON Web Tokens (JWT) digitally signed and encoded using JSON Web Signature (JWS).Because they are encoded in this way, you can locally validate access tokens using the public key of the issuing realm. You can either hard code therealm’s public key in your validation code, or lookup and cache the public key using the certificate endpoint with the Key ID (KID) embedded within theJWS. Depending on what language you code in, many third party libraries exist and they can help you with JWS validation.

2.10.2. Redirect URIs

When using the redirect based flows, be sure to use valid redirect uris for your clients. The redirect uris should be as specific as possible. Thisespecially applies to client-side (public clients) applications. Failing to do so could result in:

  • Open redirects - this can allow attackers to create spoof links that looks like they are coming from your domain

  • Unauthorized entry - when users are already authenticated with Keycloak, an attacker can use a public client where redirect uris have not be configured correctly to gain access by redirecting the user without the users knowledge

In production for web applications always use https for all redirect URIs. Do not allow redirects to http.

A few special redirect URIs also exist:

http://127.0.0.1

This redirect URI is useful for native applications and allows the native application to create a web server on a random port that can be used to obtain theauthorization code. This redirect uri allows any port. Note that per OAuth 2.0 for Native Apps, the use oflocalhost is not recommended and the IP literal 127.0.0.1 should be used instead.

urn:ietf:wg:oauth:2.0:oob

If you cannot start a web server in the client (or a browser is not available), you can use the special urn:ietf:wg:oauth:2.0:oob redirect uri.When this redirect uri is used, Keycloak displays a page with the code in the title and in a box on the page.The application can either detect that the browser title has changed, or the user can copy and paste the code manually to the application.With this redirect uri, a user can use a different device to obtain a code to paste back to the application.

Securing Applications and Services Guide (2024)

References

Top Articles
Latest Posts
Article information

Author: Jamar Nader

Last Updated:

Views: 6172

Rating: 4.4 / 5 (55 voted)

Reviews: 94% of readers found this page helpful

Author information

Name: Jamar Nader

Birthday: 1995-02-28

Address: Apt. 536 6162 Reichel Greens, Port Zackaryside, CT 22682-9804

Phone: +9958384818317

Job: IT Representative

Hobby: Scrapbooking, Hiking, Hunting, Kite flying, Blacksmithing, Video gaming, Foraging

Introduction: My name is Jamar Nader, I am a fine, shiny, colorful, bright, nice, perfect, curious person who loves writing and wants to share my knowledge and understanding with you.