JBoss.org Community Documentation

- Prev
- Next

## Chapter 7. Adapters

Keycloak can secure a wide variety of application types. This section defines which application types are supported and how to configure and install them so that you can use Keycloak to secure your applications.

## 7.1. General Adapter Config

Each adapter supported by Keycloak can be configured by a simple JSON text file. This is what one might look like:

    {
      "realm" : "demo",
      "resource" : "customer-portal",
      "realm-public-key" : "MIGfMA0GCSqGSIb3D...31LwIDAQAB",
      "auth-server-url" : "https://localhost:8443/auth",
      "ssl-required" : "external",
      "use-resource-role-mappings" : false,
      "enable-cors" : true,
      "cors-max-age" : 1000,
      "cors-allowed-methods" : [ "POST", "PUT", "DELETE", "GET" ],
      "bearer-only" : false,
      "expose-token" : true,
       "credentials" : {
          "secret" : "234234-234234-234234"
       },

       "connection-pool-size" : 20,
       "disable-trust-manager": false,
       "allow-any-hostname" : false,
       "truststore" : "path/to/truststore.jks",
       "truststore-password" : "geheim",
       "client-keystore" : "path/to/client-keystore.jks",
       "client-keystore-password" : "geheim",
       "client-key-password" : "geheim"
    }

Some of these configuration switches may be adapter specific and some are common across all adapters. For Java adapters you can use `${...}` enclosure as System property replacement. For example `${jboss.server.config.dir}`. Also, you can obtain a template for this config file from the admin console. Go to the realm and application you want a template for. Go to the `Installation` tab and this will provide you with a template that includes the public key of the realm.

Here is a description of each item:

realm

  Name of the realm representing the users of your distributed applications and services. This is REQUIRED.

resource

  Username of the application. Each application has a username that is used when the application connects with the Keycloak server to turn an access code into an access token (part of the OAuth 2.0 protocol). This is REQUIRED.

realm-public-key

  PEM format of public key. You can obtain this from the administration console. This is REQUIRED.

auth-server-url

  The base URL of the Keycloak Server. All other Keycloak pages and REST services are derived from this. It is usually of the form `https://host:port/auth` This is REQUIRED.

ssl-required

  Ensures that all communication to and from the Keycloak server from the adapter is over HTTPS. This is OPTIONAL. The default value is external meaning that HTTPS is required by default for external requests. Valid values are 'all', 'external' and 'none'.

use-resource-role-mappings

  If set to true, the adapter will look inside the token for application level role mappings for the user. If false, it will look at the realm level for user role mappings. This is OPTIONAL. The default value is false.

enable-cors

  This enables CORS support. It will handle CORS preflight requests. It will also look into the access token to determine valid origins. This is OPTIONAL. The default value is false.

cors-max-age

  If CORS is enabled, this sets the value of the `Access-Control-Max-Age` header. This is OPTIONAL. If not set, this header is not returned in CORS responses.

cors-allowed-methods

  If CORS is enabled, this sets the value of the `Access-Control-Allow-Methods` header. This should be a JSON list of strings. This is OPTIONAL. If not set, this header is not returned in CORS responses.

bearer-only

  This tells the adapter to only do bearer token authentication. That is, it will not do OAuth 2.0 redirects, but only accept bearer tokens through the `Authorization` header. This is OPTIONAL. The default value is false.

expose-token

  If `true`, an authenticated browser client (via a Javascript HTTP invocation) can obtain the signed access token via the URL `root/k_query_bearer_token`. This is OPTIONAL. The default value is false.

credentials

  Specify the credentials of the application. This is an object notation where the key is the credential type and the value if the value of the credential type. Currently only `password` is supported. This is REQUIRED.

connection-pool-size

  Adapters will make separate HTTP invocations to the Keycloak Server to turn an access code into an access token. This config option defines how many connections to the Keycloak Server should be pooled. This is OPTIONAL. The default value is `20`.

disable-trust-manager

  If the Keycloak Server requires HTTPS and this config option is set to `true` you do not have to specify a truststore. While convenient, this setting is not recommended as you will not be verifying the host name of the Keycloak Server. This is OPTIONAL. The default value is `false`.

allow-any-hostname

  If the Keycloak Server requires HTTPS and this config option is set to `true` the Keycloak Server's certificate is validated via the truststore, but host name validation is not done. This is not a recommended. This seting may be useful in test environments This is OPTIONAL. The default value is `false`.

truststore

  This setting is for Java adapters. This is the file path to a Java keystore file. Used for outgoing HTTPS communications to the Keycloak server. Client making HTTPS requests need a way to verify the host of the server they are talking to. This is what the trustore does. The keystore contains one or more trusted host certificates or certificate authorities. You can create this truststore by extracting the public certificate of the Keycloak server's SSL keystore. This is OPTIONAL if `ssl-required` is `none` or `disable-trust-manager` is `true`. The default value isfalse.

truststore-password

  Password for the truststore keystore. This is REQUIRED if `truststore` is set.

client-keystore

  Not supported yet, but we will support in future versions. This setting is for Java adapters. This is the file path to a Java keystore file. This keystore contains client certificate for two-way SSL when the adapter makes HTTPS requests to the Keycloak server. This is OPTIONAL.

client-keystore-password

  Not supported yet, but we will support in future versions. Password for the client keystore. This is REQUIRED if `client-keystore` is set.

client-key-password

  Not supported yet, but we will support in future versions. Password for the client's key. This is REQUIRED if `client-keystore` is set.

auth-server-url-for-backend-requests

  Alternative location of auth-server-url used just for backend requests. It must be absolute URI. Useful especially in cluster (see Relative URI Optimization) or if you would like to use https for browser requests but stick with http for backend requests etc.

always-refresh-token

  If true, Keycloak will refresh token in every request. More info in Refresh token in each request .

register-node-at-startup

  If true, then adapter will send registration request to Keycloak. It's false by default as useful just in cluster (See Registration of application nodes to Keycloak)

register-node-period

  Period for re-registration adapter to Keycloak. Useful in cluster. See Registration of application nodes to Keycloak for details.

token-store

  Possible values are session and cookie. Default is session, which means that adapter stores account info in HTTP Session. Alternative cookie means storage of info in cookie. See Stateless token store for details.

principal-attribute

  OpenID Connection ID Token attribute to populate the UserPrincipal name with. If token attribute is null, defaults to `sub` Possible values are `sub`, `preferred_username`, `email`, `name`, `nickname`, `given_name`, `family_name`.

## 7.2. JBoss/Wildfly Adapter

To be able to secure WAR apps deployed on JBoss AS 7.1.1, JBoss EAP 6.x, or Wildfly, you must install and configure the Keycloak Subsystem. You then have two options to secure your WARs. You can provide a keycloak config file in your WAR and change the auth-method to KEYCLOAK within web.xml. Alternatively, you don't have to crack open your WARs at all and can apply Keycloak via the Keycloak Subsystem configuration in standalone.xml. Both methods are described in this section.

### 7.2.1. Adapter Installation

There is a adapter zip file for AS7, EAP, and Wildfly in the `adapters/` directory in the Keycloak distribution.

Install on Wildfly:

    $ cd $WILDFLY_HOME
    $ unzip keycloak-wildfly-adapter-dist.zip

Install on JBoss EAP 6.x:

    $ cd $JBOSS_HOME
    $ unzip keycloak-eap6-adapter-dist.zip

Install on JBoss AS 7.1.1:

    $ cd $JBOSS_HOME
    $ unzip keycloak-as7-adapter-dist.zip

This zip file creates new JBoss Modules specific to the Wildfly Keycloak Adapter within your Wildfly distro.

After adding the Keycloak modules, you must then enable the Keycloak Subsystem within your app server's server configuration: `domain.xml` or `standalone.xml`.

For Wildfly:

    <server xmlns="urn:jboss:domain:1.4">

        <extensions>
            <extension module="org.keycloak.keycloak-wildfly-subsystem"/>
              ...
        </extensions>

        <profile>
            <subsystem xmlns="urn:jboss:domain:keycloak:1.0"/>
             ...
        </profile>

For JBoss AS 7.1.1 and EAP 6.x:

    <server xmlns="urn:jboss:domain:1.4">

        <extensions>
            <extension module="org.keycloak.keycloak-as7-subsystem"/>
             ...
        </extensions>

        <profile>
            <subsystem xmlns="urn:jboss:domain:keycloak:1.0"/>
              ...
        </profile>

Finally, for both AS7, EAP 6.x, and Wildfly installations you must specify a shared keycloak security domain. This security domain should be used with EJBs and other components when you need the security context created in the secured web tier to be propagated to the EJBs (other EE component) you are invoking. Otherwise this configuration is optional.

    <server xmlns="urn:jboss:domain:1.4">
     <subsystem xmlns="urn:jboss:domain:security:1.2">
        <security-domains>
    ...
          <security-domain name="keycloak">
             <authentication>
               <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule"
                             flag="required"/>
              </authentication>
          </security-domain>
        </security-domains>

For example, if you have a JAX-RS service that is an EJB within your WEB-INF/classes directory, you'll want to annotate it with the @SecurityDomain annotation as follows:

    import org.jboss.ejb3.annotation.SecurityDomain;
    import org.jboss.resteasy.annotations.cache.NoCache;

    import javax.annotation.security.RolesAllowed;
    import javax.ejb.EJB;
    import javax.ejb.Stateless;
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.Produces;
    import java.util.ArrayList;
    import java.util.List;

    @Path("customers")
    @Stateless
    @SecurityDomain("keycloak")
    public class CustomerService {

        @EJB
        CustomerDB db;

        @GET
        @Produces("application/json")
        @NoCache
        @RolesAllowed("db_user")
        public List<String> getCustomers() {
            return db.getCustomers();
        }
    }

We hope to improve our integration in the future so that you don't have to specify the @SecurityDomain annotation when you want to propagate a keycloak security context to the EJB tier.

### 7.2.2. Required Per WAR Configuration

This section describes how to secure a WAR directly by adding config and editing files within your WAR package.

The first thing you must do is create a `keycloak.json` adapter config file within the `WEB-INF` directory of your WAR. The format of this config file is describe in the general adapter configuration section.

Next you must set the `auth-method` to `KEYCLOAK` in `web.xml`. You also have to use standard servlet security to specify role-base constraints on your URLs. Here's an example pulled from one of the examples that comes distributed with Keycloak.

    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
          version="3.0">

    	<module-name>customer-portal</module-name>

        <security-constraint>
            <web-resource-collection>
                <web-resource-name>Admins</web-resource-name>
                <url-pattern>/admin/*</url-pattern>
            </web-resource-collection>
            <auth-constraint>
                <role-name>admin</role-name>
            </auth-constraint>
        </security-constraint>
        <security-constraint>
            <web-resource-collection>
                <web-resource-name>Customers</web-resource-name>
                <url-pattern>/customers/*</url-pattern>
            </web-resource-collection>
            <auth-constraint>
                <role-name>user</role-name>
            </auth-constraint>
        </security-constraint>

        <security-constraint>
            <web-resource-collection>
                <url-pattern>/*</url-pattern>
            </web-resource-collection>
            <user-data-constraint>
                <transport-guarantee>CONFIDENTIAL</transport-guarantee>
            </user-data-constraint>
        </security-constraint>

        <login-config>
            <auth-method>KEYCLOAK</auth-method>
            <realm-name>this is ignored currently/realm-name>
        </login-config>

        <security-role>
            <role-name>admin</role-name>
        </security-role>
        <security-role>
            <role-name>user</role-name>
        </security-role>
    </web-app>

### 7.2.3. Securing WARs via Keycloak Subsystem

You do not have to crack open a WAR to secure it with Keycloak. Alternatively, you can externally secure it via the Keycloak Subsystem. While you don't have to specify KEYCLOAK as an `auth-method`, you still have to define the `security-constraints` in `web.xml`. You do not, however, have to create a `WEB-INF/keycloak.json` file. This metadata is instead defined within XML in your server's `domain.xml` or `standalone.xml` subsystem configuration section.

    <server xmlns="urn:jboss:domain:1.4">

      <profile>
        <subsystem xmlns="urn:jboss:domain:keycloak:1.0">
           <secure-deployment name="WAR MODULE NAME.war">
              <realm>demo</realm>
              <realm-public-key>MIGfMA0GCSqGSIb3DQEBAQUAA</realm-public-key>
              <auth-server-url>http://localhost:8081/auth</auth-server-url>
              <ssl-required>external</ssl-required>
              <resource>customer-portal</resource>
              <credential name="secret">password</credential>
           </secure-deployment>
        </subsystem>
      </profile>

The `security-deployment` `name` attribute identifies the WAR you want to secure. Its value is the `module-name` defined in `web.xml` with `.war` appended. The rest of the configuration corresponds pretty much one to one with the `keycloak.json` configuration options defined in general adapter configuration. The exception is the `credential` element.

To make it easier for you, you can go to the Keycloak Adminstration Console and go to the Application/Installation tab of the application this WAR is aligned with. It provides an example XML file you can cut and paste.

There is an additional convenience format for this XML if you have multiple WARs you are deployment that are secured by the same domain. This format allows you to define common configuration items in one place under the `realm` element.

    <subsystem xmlns="urn:jboss:domain:keycloak:1.0">
        <realm name="demo">
            <realm-public-key>MIGfMA0GCSqGSIb3DQEBA</realm-public-key>
            <auth-server-url>http://localhost:8080/auth</auth-server-url>
            <ssl-required>external</ssl-required>
        </realm>
        <secure-deployment name="customer-portal.war">
            <realm>demo</realm>
            <resource>customer-portal</resource>
            <credential name="secret">password</credential>
        </secure-deployment>
        <secure-deployment name="product-portal.war">
            <realm>demo</realm>
            <resource>product-portal</resource>
            <credential name="secret">password</credential>
        </secure-deployment>
        <secure-deployment name="database.war">
            <realm>demo</realm>
            <resource>database-service</resource>
            <bearer-only>true</bearer-only>
        </secure-deployment>
    </subsystem>

## 7.3. Tomcat 7 Adapter

To be able to secure WAR apps deployed on Tomcat 7 you must install the Keycloak Tomcat 7 adapter into your Tomcat installation. You then have to provide some extra configuration in each WAR you deploy to Tomcat. Let's go over these steps.

### 7.3.1. Adapter Installation

There is a adapter zip file for Tomcat 7 in the `adapters/` directory in the Keycloak appliance or war distribution. You must unzip this file into Tomcat's `lib/` directory. Including adapter's jars within your WEB-INF/lib directory will not work! The Keycloak adapter is implemented as a Valve and valve code must reside in Tomcat's main lib/ directory.

    $ cd $TOMCAT_HOME/lib
    $ unzip keycloak-tomcat7-adapter-dist.zip

### 7.3.2. Required Per WAR Configuration

This section describes how to secure a WAR directly by adding config and editing files within your WAR package.

The first thing you must do is create a `META-INF/context.xml` file in your WAR package. This is a Tomcat specific config file and you must define a Keycloak specific Valve.

    <Context path="/your-context-path">
        <Valve className="org.keycloak.adapters.tomcat7.KeycloakAuthenticatorValve"/>
    </Context>

Next you must create a `keycloak.json` adapter config file within the `WEB-INF` directory of your WAR. The format of this config file is describe in the general adapter configuration section.

Finally you must specify both a `login-config` and use standard servlet security to specify role-base constraints on your URLs. Here's an example:

    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
          version="3.0">

    	<module-name>customer-portal</module-name>

        <security-constraint>
            <web-resource-collection>
                <web-resource-name>Customers</web-resource-name>
                <url-pattern>/*</url-pattern>
            </web-resource-collection>
            <auth-constraint>
                <role-name>user</role-name>
            </auth-constraint>
        </security-constraint>

        <security-constraint>
            <web-resource-collection>
                <url-pattern>/*</url-pattern>
            </web-resource-collection>
            <user-data-constraint>
                <transport-guarantee>CONFIDENTIAL</transport-guarantee>
            </user-data-constraint>
        </security-constraint>

        <login-config>
            <auth-method>BASIC</auth-method>
            <realm-name>this is ignored currently/realm-name>
        </login-config>

        <security-role>
            <role-name>admin</role-name>
        </security-role>
        <security-role>
            <role-name>user</role-name>
        </security-role>
    </web-app>

## 7.4. Pure Client Javascript Adapter

The Keycloak Server comes with a Javascript library you can use to secure pure HTML/Javascript applications. It works in the same way as other application adapters except that your browser is driving the OAuth redirect protocol rather than the server.

The disadvantage of using this approach is that you end up having a non-confidential, public client. This can be mitigated by registering valid redirect URLs. You are still vulnerable if somebody hijacks the IP/DNS name of your pure HTML/Javascript application though.

To use this adapter, you must first configure an application (or client) through the `Keycloak Admin Console`. You should select `public` for the `Client Type` field. As public clients can't be verified with a client secret you are required to configure one or more valid redirect uris as well. Once you've configured the application click on the `Installation` tab and download the `keycloak.json` file. This file should be hosted in your web-server at the same root as your HTML pages. Alternatively you can either specify the URL for this file, or manually configure the adapter.

Next you have to initialize the adapter in your application. An example on how to do this is shown below.

    <head>
        <script src="http://<keycloak server>/auth/js/keycloak.js"></script>
        <script>
            var keycloak = Keycloak();
            keycloak.init().success(function(authenticated) {
                alert(authenticated ? 'authenticated' : 'not authenticated');
            }).error(function() {
                alert('failed to initialize');
            });
        </script>
    </head>

To specify the location of the keycloak.json file:

    var keycloak = Keycloak('http://localhost:8080/myapp/keycloak.json'));

Or finally to manually configure the adapter:

    var keycloak = Keycloak({
        url: 'http://keycloak-server/auth',
        realm: 'myrealm',
        clientId: 'myapp'
    });

You can also pass `login-required` or `check-sso` to the init function. Login required will redirect to the login form on the server, while check-sso will redirect to the auth server to check if the user is already logged in to the realm. For example:

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

After you login, your application will be able to make REST calls using bearer token authentication. Here's an example pulled from the `customer-portal-js` example that comes with the distribution.

    <script>
        var loadData = function () {
            document.getElementById('username').innerText = keycloak.username;

            var url = 'http://localhost:8080/database/customers';

            var req = new XMLHttpRequest();
            req.open('GET', url, true);
            req.setRequestHeader('Accept', 'application/json');
            req.setRequestHeader('Authorization', 'Bearer ' + keycloak.token);

            req.onreadystatechange = function () {
                if (req.readyState == 4) {
                    if (req.status == 200) {
                        var users = JSON.parse(req.responseText);
                        var html = '';
                        for (var i = 0; i < users.length; i++) {
                            html += '<p>' + users[i] + '</p>';
                        }
                        document.getElementById('customers').innerHTML = html;
                        console.log('finished loading data');
                    }
                }
            }

            req.send();
        };

        var loadFailure = function () {
            document.getElementById('customers').innerHTML = '<b>Failed to load data.  Check console log</b>';

        };

        var reloadData = function () {
            keycloak.updateToken().success(loadData).error(loadFailure);
        }
    </script>

    <button onclick="loadData()">Submit</button>

The `loadData()` method builds an HTTP request setting the `Authorization` header to a bearer token. The `keycloak.token` points to the access token the browser obtained when it logged you in. The `loadFailure()` method is invoked on a failure. The `reloadData()` function calls `keycloak.onValidAccessToken()` passing in the `loadData()` and `loadFailure()` callbacks. The `keycloak.onValidAcessToken()` method checks to see if the access token hasn't expired. If it hasn't, and your oauth login returned a refresh token, this method will refresh the access token. Finally, if successful, it will invoke the success callback, which in this case is the `loadData()` method.

To refresh the token if it's expired call the `updateToken` method. This method returns a promise object which can be used to invoke a function on success or failure. This method can be used to wrap functions that should only be called with a valid token. For example the following method will refresh the token if it expires within 30 seconds, and then invoke the specified function. If the token is valid for more than 30 seconds it will just call the specified function.

    keycloak.updateToken(30).success(function() {
        // send request with valid token
    }).error(function() {
        alert('failed to refresh token');
    );

### 7.4.1. Session status iframe

By default the JavaScript adapter creates a non-visible iframe that is used to detect if a single-sign out has occured. This does not require any network traffic, instead the status is retrieved from a special status cookie. This feature can be disabled by setting `checkLoginIframe: false` in the options passed to the `init` method.

### 7.4.2. JavaScript Adapter reference

#### 7.4.2.1. Constructor

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

#### 7.4.2.2. Properties

- authenticated - true if the user is authenticated
- token - the base64 encoded token that can be sent in the `Authorization` header in requests to services
- tokenParsed - the parsed token
- subject - the user id
- idToken - the id token if claims is enabled for the application, null otherwise
- realmAccess - the realm roles associated with the token
- resourceAccess - the resource roles assocaited with the token
- refreshToken - the base64 encoded token that can be used to retrieve a new token
- refreshTokenParsed - the parsed refresh token

#### 7.4.2.3. Methods

##### init(options)

Called to initialize the adapter.

Options is an Object, where:

- onLoad - specifies an action to do on load, can be either 'login-required' or 'check-sso'
- token - set an initial value for the token
- refreshToken - set an initial value for the refresh token
- checkLoginIframe - set to enable/disable monitoring login state (default is true)
- checkLoginIframeInterval - set the interval to check login state (default is 5 seconds)

Returns promise to set functions to be invoked on success or error.

##### login(options)

Redirects to login form on (options is an optional object with redirectUri and/or prompt fields)

Options is an Object, where:

- redirectUri - specifies the uri to redirect to after login
- prompt - can be set to 'none' to check if the user is logged in already (if not logged in a login form is not displayed)
- loginHint - used to pre-fill the username/email field on the login form

##### createLoginUrl(options)

Returns the url to login form on (options is an optional object with redirectUri and/or prompt fields)

Options is an Object, where:

- redirectUri - specifies the uri to redirect to after login
- prompt - can be set to 'none' to check if the user is logged in already (if not logged in a login form is not displayed)

##### logout(options)

Redirects to logout

Options is an Object, where:

- redirectUri - specifies the uri to redirect to after logout

##### createLogoutUrl(options)

Returns logout out

Options is an Object, where:

- redirectUri - specifies the uri to redirect to after logout

##### accountManagement()

Redirects to account management

##### createAccountUrl()

Returns the url to account management

##### 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 promise to set functions to be invoked on success or 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 0 is used) the token is refreshed. If the session status iframe is enabled, the session status is also checked.

Returns promise to set functions that can be invoked if the token is still valid, or if the token is no longer valid. For example:

    keycloak.updateToken(5).success(function(refreshed) {
            if (refreshed) {
                alert('token was successfully refreshed');
            } else {
                alert('token is still valid');
            }
        }).error(function() {
            alert('failed to refresh the token, or the session has expired');
        });

#### 7.4.2.4. Callback Events

The adapter supports setting callback listeners for certain events. For example:

    keycloak.onAuthSuccess = function() { alert('authenticated'); }

- 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)

## 7.5. Installed Applications

Keycloak provides two special redirect uris for installed applications.

### 7.5.1. http://localhost

This returns the code to a web server on the client as a query parameter. Any port number is allowed. This makes it possible to start a web server for the installed application on any free port number without requiring changes in the `Admin Console`.

### 7.5.2. urn:ietf:wg:oauth:2.0:oob

If its not possible to start a web server in the client (or a browser is not available) it is possible to 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/paste the code manually to the application. With this redirect uri it is also possible for a user to use a different device to obtain a code to paste back to the application.

## 7.6. Logout

There are multiple ways you can logout from a web application. For Java EE servlet containers, you can call HttpServletRequest.logout(). For any other browser application, you can point the browser at the url `http://auth-server/auth/realms/{realm-name}/tokens/logout?redirect_uri=encodedRedirectUri`. This will log you out if you have an SSO session with your browser.

## 7.7. Multi Tenancy

Multi Tenancy, in our context, means that one single target application (WAR) can be secured by a single (or clustered) Keycloak server, authenticating its users against different realms. In practice, this means that one application needs to use different `keycloak.json` files. For this case, there are two possible solutions:

- The same WAR file deployed under two different names, each with its own Keycloak configuration (probably via the Keycloak Subsystem). This scenario is suitable when the number of realms is known in advance or when there's a dynamic provision of application instances. One example would be a service provider that dinamically creates servers/deployments for their clients, like a PaaS.
- A WAR file deployed once (possibly in a cluster), that decides which realm to authenticate against based on the request parameters. This scenario is suitable when there are an undefined number of realms. One example would be a SaaS provider that have only one deployment (perhaps in a cluster) serving several companies, differentiating between clients based on the hostname (`client1.acme.com`, `client2.acme.com`) or path (`/app/client1/`, `/app/client2/`) or even via a special HTTP Header.

This chapter of the reference guide focus on this second scenario.

Keycloak provides an extension point for applications that need to evaluate the realm on a request basis. During the authentication and authorization phase of the incoming request, Keycloak queries the application via this extension point and expects the application to return a complete representation of the realm. With this, Keycloak then proceeds the authentication and authorization process, accepting or refusing the request based on the incoming credentials and on the returned realm. For this scenario, an application needs to:

- Add a context parameter to the `web.xml`, named `keycloak.config.resolver`. The value of this property should be the fully qualified name of the a class extending `org.keycloak.adapters.KeycloakConfigResolver`.
- A concrete implementation of `org.keycloak.adapters.KeycloakConfigResolver`. Keycloak will call the `resolve(org.keycloak.adapters.HttpFacade.Request)` method and expects a complete `org.keycloak.adapters.KeycloakDeployment` in response. Note that Keycloak will call this for every request, so, take the usual performance precautions.

An implementation of this feature can be found on the examples.

- PrevChapter 6. Per Realm Admin Access Control
- Top of page
- Front page
- NextChapter 8. Social