Javascript Adapter
The Keycloak Server comes with a Javascript library you can use to secure HTML/Javascript applications. This
library is referenceable directly from the keycloak server. You can also download the adapter from Keycloak's download
site if you want a static copy. 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 have a non-confidential, public client. This makes it more
important that you register valid redirect URLs and make sure your domain name is secured.
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.
Once you've configured the application, click on the Installation tab and download the keycloak.json
file. This file should be hosted on your web-server at the same root as your HTML pages. Alternatively, you can manually
configure the adapter and specify the URL for this file.
Next, you have to initialize the adapter in your application. An example is shown below.
]]>
To specify the location of the keycloak.json file:
Or finally to manually configure the adapter:
You can also pass login-required or check-sso to the init function. Login
required will cause a redirect to the login form on the server, while check-sso will simply redirect to the auth server to check
if the user is already logged in to the realm. For example:
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.
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 += '
' + users[i] + '
';
}
document.getElementById('customers').innerHTML = html;
console.log('finished loading data');
}
}
}
req.send();
};
var loadFailure = function () {
document.getElementById('customers').innerHTML = 'Failed to load data. Check console log';
};
var reloadData = function () {
keycloak.updateToken().success(loadData).error(loadFailure);
}
]]>
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.updateToken() passing in the loadData() and
loadFailure() callbacks. The keycloak.updateToken() 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 when it is 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.
Session status iframe
By default, the JavaScript adapter creates a non-visible iframe that is used to detect if a single-sign out has occurred.
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.
Implicit and Hybrid Flow
By default, the JavaScript adapter uses OpenID Connect standard (Authorization code) flow, which
means that after authentication, the Keycloak server redirects the user back to your application, where the JavaScript adapter will exchange the code for an access token and a refresh token.
However, Keycloak also supports OpenID Connect Implicit flow
where an access token is sent immediately after successful authentication with Keycloak (there is no additional request for exchange code).
This could have better performance than standard flow, as there is no additional request to exchange the code for tokens. However, sending the access token
in the URL fragment could pose a security issue in some environments (access logs might expose tokens located in the URL).
To enable implicit flow, you need to enable the Implicit Flow Enabled flag for the client in the Keycloak admin console. You also need to pass
the parameter flow with value implicit to init method.
An example is below:
Note that with implicit flow, you are not given a refresh token after authentication. This makes it harder for your application to periodically update
the access token in background (without browser redirection). It's recommended that you implement an onTokenExpired callback method on the keycloak object, so you
are notified after the token is expired (For example you can call keycloak.login, which will redirect browser to Keycloak login screen and it will immediately
redirect you back if the SSO session is still valid and the user is still logged. However, make sure to save the application state before performing a redirect.)
Keycloak also has support for OpenID Connect Hybrid flow. This requires
the client to have both the Standard Flow Enabled and Implicit Flow Enabled flags enabled in the admin console.
The Keycloak server will then send 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 security risks might still apply.
However, one advantage over the implicit flow is that a refresh token is made available to the application (after the code-to-token request is finished).
For hybrid flow, you need to pass the parameter flow with value hybrid to init method.
Older browsers
The JavaScript adapter depends on Base64 (window.btoa and window.atob) and HTML5 History API. If you need to
support browsers that don't provide those (for example IE9) you'll need to add polyfillers. Example polyfill
libraries:
Base64 - https://github.com/davidchambers/Base64.jsHTML5 History - https://github.com/devote/HTML5-History-APIJavaScript Adapter referenceConstructorPropertiesauthenticated - true if the user is authenticatedtoken - the base64 encoded token that can be sent in the Authorization header in requests to servicestokenParsed - the parsed tokensubject - the user ididToken - the id token if claims is enabled for the application, null otherwiseidTokenParsed - the parsed id tokenrealmAccess - the realm roles associated with the tokenresourceAccess - the resource roles assocaited with the tokenrefreshToken - the base64 encoded token that can be used to retrieve a new tokenrefreshTokenParsed - the parsed refresh tokentimeSkew - estimated skew between local time and Keycloak server in secondsresponseMode - responseMode passed during initialization. See below for details. Default value is fragmentflow - OpenID Connect flow passed during initialization. See Implicit flow for details.responseType - responseType used for send to Keycloak server at login request. This is determined based on the flow value used during initialization,
but you have possibility to override it by directly set this valueMethodsinit(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 tokenrefreshToken - set an initial value for the refresh tokenidToken - set an initial value for the id token (only together with token or refreshToken)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.
See Implicit flow for details.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 loginprompt - 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 formaction - if value is 'register' then user is redirected to registration page, otherwise to login pagelocale - specifies the desired locale for the UIcreateLoginUrl(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 loginprompt - 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 logoutOptions is an Object, where:
redirectUri - specifies the uri to redirect to after logoutcreateLogoutUrl(options)Returns logout outOptions is an Object, where:
redirectUri - specifies the uri to redirect to after logoutregister(options)Redirects to registration form. It's a shortcut for doing login with option action = 'register'Options are same as login method but 'action' is overwritten to 'register'createRegisterUrl(options)Returns the url to registration page. It's a shortcut for doing createRegisterUrl with option action = 'register'Options are same as createLoginUrl method but 'action' is overwritten to 'register'accountManagement()Redirects to account managementcreateAccountUrl()Returns the url to account managementhasRealmRole(role)Returns true if the token has the given realm rolehasResourceRole(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 profileReturns 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:clearToken()
Clear authentication state, including tokens. This can be useful if application has detected the session
has expired, for example if updating token fails. Invoking this results in onAuthLogout callback listener
being invoked.
Callback EventsThe adapter supports setting callback listeners for certain events. For example:
onReady(authenticated) - called when the adapter is initializedonAuthSuccess - called when a user is successfully authenticatedonAuthError - called if there was an error during authenticationonAuthRefreshSuccess - called when the token is refreshedonAuthRefreshError - called if there was an error while trying to refresh the tokenonAuthLogout - 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 access token expired. When this happens you can for example refresh token, or if refresh not available (ie. with implicit flow) you can redirect to login screen