[[_javascript_adapter]] === JavaScript Adapter {project_name} comes with a client-side JavaScript library that can be used to secure HTML5/JavaScript applications. The JavaScript adapter has built-in support for Cordova applications. The library can be retrieved directly from the {project_name} server at `/auth/js/keycloak.js` and is also distributed as a ZIP archive. A best practice is to load the JavaScript adapter directly from {project_name} Server as it will automatically be updated when you upgrade the server. If you copy the adapter to your web application instead, make sure you upgrade the adapter only after you have upgraded the server. One important thing to note 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 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 JavaScript adapter you must first create a client for your application in the {project_name} Administration Console. Make sure `public` is selected for `Access Type`. You also need to configure valid redirect URIs and valid web origins. Be as specific as possible as failing to do so may result in a security vulnerability. Once the client is created click on the `Installation` tab select `Keycloak OIDC JSON` for `Format Option` then click `Download`. The downloaded `keycloak.json` file should be hosted on your web server at the same location as your HTML pages. Alternatively, you can skip the configuration file and manually configure the adapter. The following example shows how to initialize the JavaScript adapter: [source,html] ----
---- If the `keycloak.json` file is in a different location you can specify it: [source,javascript] ---- var keycloak = Keycloak('http://localhost:8080/myapp/keycloak.json'); ---- Alternatively, you can pass in a JavaScript object with the required configuration instead: [source,javascript] ---- var keycloak = Keycloak({ url: 'http://keycloak-server/auth', realm: 'myrealm', clientId: 'myapp' }); ---- By default to authenticate you need to call the `login` function. However, there are two options available to make the adapter automatically authenticate. You can pass `login-required` or `check-sso` to the init function. `login-required` will authenticate the client if the user is logged-in to {project_name} or display the login page if not. `check-sso` will only authenticate the client if the user is already logged-in, if the user is not logged-in the browser will be redirected back to the application and remain unauthenticated. To enable `login-required` set `onLoad` to `login-required` and pass to the init method: [source,javascript] ---- keycloak.init({ onLoad: 'login-required' }) ---- After the user is authenticated the application can make requests to RESTful services secured by {project_name} by including the bearer token in the `Authorization` header. For example: [source,javascript] ---- var loadData = function () { document.getElementById('username').innerText = keycloak.subject; var url = 'http://localhost:8080/restful-service'; 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) { alert('Success'); } else if (req.status == 403) { alert('Forbidden'); } } } req.send(); }; ---- 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 can do this by the `updateToken` method. The `updateToken` method returns a promise object which makes it easy to invoke the service only if the token was successfully refreshed and for example display an error to the user if it wasn't. For example: [source,javascript] ---- keycloak.updateToken(30).then(function() { loadData(); }).catch(function() { alert('Failed to refresh token'); }); ---- ==== Session Status iframe By default, the JavaScript adapter creates a hidden 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 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 {project_name} server, not your application. [[_javascript_implicit_flow]] ==== Implicit and Hybrid Flow By default, the JavaScript adapter uses the http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth[Authorization Code] flow. With this flow the {project_name} 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. {project_name} also supports the http://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth[Implicit] flow where an access token is sent immediately after successful authentication with {project_name}. This may have better performance than standard flow, as there is no additional request 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 or browser history. To enable implicit flow, you need to enable the `Implicit Flow Enabled` flag for the client in the {project_name} Administration Console. You also need to pass the parameter `flow` with value `implicit` to `init` method: [source,javascript] ---- keycloak.init({ flow: 'implicit' }) ---- One thing to note is that only an access token is provided and there is no refresh token. This means that once the access token has expired the application has to do the redirect to the {project_name} again to obtain a new access token. {project_name} also supports the http://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth[Hybrid] flow. This requires the client to have both the `Standard Flow Enabled` and `Implicit Flow Enabled` flags enabled in the admin console. The {project_name} 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 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: [source,javascript] ---- keycloak.init({ flow: 'hybrid' }) ---- [#hybrid-apps-with-cordova] ==== Hybrid Apps with Cordova Keycloak support hybird mobile apps developed with https://cordova.apache.org/[Apache Cordova]. The Javascript adapter has two modes for this: `cordova` and `cordova-native`: The default is cordova, which the adapter will automatically select if no adapter type has been configured and window.cordova is present. When logging in, it will open an https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-inappbrowser/[InApp Browser] that lets the user interact with {project_name} and afterwards returns to the app by redirecting to `http://localhost`. Because of this, you must whitelist this URL as a valid redirect-uri in the client configuration section of the Administration Console. While this mode is easy to setup, 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. Use this example app to help you get started: https://github.com/keycloak/keycloak/tree/master/examples/cordova The alternative mode `cordova-nativei` 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 app using a special URL. From there, the {project_name} adapter can finish the login by reading the code or token from the URL. You can activate the native mode by passing the adater type `cordova-native` to the `init` method: [source,javascript] ---- keycloak.init({ adapter: 'cordova-native' }) ---- This adapter required two additional plugins: * https://github.com/google/cordova-plugin-browsertab[cordova-plugin-browsertab]: allows the app to open webpages in the system's browser * https://github.com/e-imaxina/cordova-plugin-deeplinks[cordova-plugin-deeplinks]: allow the browser to redirect back to your app by special URLs The technical details for linking to an app differ on each plattform and special setup is needed. Please refer to the Android and iOS sections of the https://github.com/e-imaxina/cordova-plugin-deeplinks/blob/master/README.md[deeplinks plugin documentation] for further instructions. There are different kinds of links for opening apps: custom schemes (i.e. `myapp://login` or `android-app://com.example.myapp/https/example.com/login`) and https://developer.apple.com/ios/universal-links/[Universal Links (iOS)]) / https://developer.android.com/training/app-links/deep-linking[Deep Links (Android)]. While the former are easier to setup and tend to work more reliably, the later offer extra security as they are unique and only the owner of a domain can register them. Custom-URLs are deprecated on iOS. We recommend that you use universal links, combined with a fallback site with a custom-url link on it for best reliability. Furthermore, we recommend the following steps to improve compatibility with the Keycloak 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`: [source,xml] ----