KEYCLOAK-2606: add support for native browsers on cordova

KEYCLOAK-2606 Added cordova native

KEYCLOAK-2606 Some more fixes and tweaks

Fix redirect in example realm

feature(cordova-native): fix universalLinks and kc options

Added 'cordova-native' to typings

Added an option to define a "default" redirectUri in keycloak.js

Added 'login' and 'logout' event to universalLinks configuration in config.xml

Improved 'cordova-native' example to always use a redirectUri and
update state after successfull logout

Setting the 'authenticated' flag for the keycloak instance to 'false'
after a logout redirect

KEYCLOAK-2606: Simplify example for cordova-native

I wanted to make it explicit which options are actually needed, so I didn't want to reuse the keycloak conf

KEYCLOAK-2606: simplify example

The update state after logout shouldn't be necessary as it is set in `keycloak.onAuthLogout = updateState;`
Not sure why it is called after the login promise...

Fixes
This commit is contained in:
Gregor Tudan 2018-06-09 23:26:16 +02:00 committed by Stian Thorgersen
parent 8e20986335
commit 3417b569c0
9 changed files with 741 additions and 5 deletions

View file

@ -29,7 +29,7 @@ export = Keycloak;
declare function Keycloak(config?: string|{}): Keycloak.KeycloakInstance;
declare namespace Keycloak {
type KeycloakAdapterName = 'cordova'|'default' | any;
type KeycloakAdapterName = 'cordova' | 'cordova-native' |'default' | any;
type KeycloakOnLoad = 'login-required'|'check-sso';
type KeycloakResponseMode = 'query'|'fragment';
type KeycloakResponseType = 'code'|'id_token token'|'code id_token token';
@ -98,6 +98,12 @@ declare namespace Keycloak {
*/
responseMode?: KeycloakResponseMode;
/**
* Specifies a default uri to redirect to after login or logout.
* This is currently supported for adapter 'cordova-native' and 'default'
*/
redirectUri?: string;
/**
* Set the OpenID Connect flow.
* @default standard

View file

@ -46,11 +46,10 @@
kc.authenticated = false;
callbackStorage = createCallbackStorage();
var adapters = ['default', 'cordova', 'cordova-native'];
if (initOptions && initOptions.adapter === 'cordova') {
adapter = loadAdapter('cordova');
} else if (initOptions && initOptions.adapter === 'default') {
adapter = loadAdapter();
if (initOptions && adapters.indexOf(initOptions.adapter) > -1) {
adapter = loadAdapter(initOptions.adapter);
} else if (initOptions && typeof initOptions.adapter === "object") {
adapter = initOptions.adapter;
} else {
@ -106,6 +105,10 @@
if (initOptions.timeSkew != null) {
kc.timeSkew = initOptions.timeSkew;
}
if(initOptions.redirectUri) {
kc.redirectUri = initOptions.redirectUri;
}
}
if (!kc.responseMode) {
@ -1339,6 +1342,75 @@
}
}
if (type == 'cordova-native') {
loginIframe.enable = false;
return {
login: function(options) {
var promise = createPromise();
var loginUrl = kc.createLoginUrl(options);
universalLinks.subscribe('keycloak', function(event) {
universalLinks.unsubscribe('keycloak');
window.cordova.plugins.browsertab.close();
var oauth = parseCallback(event.url);
processCallback(oauth, promise);
});
window.cordova.plugins.browsertab.openUrl(loginUrl);
return promise.promise;
},
logout: function(options) {
var promise = createPromise();
var logoutUrl = kc.createLogoutUrl(options);
universalLinks.subscribe('keycloak', function(event) {
universalLinks.unsubscribe('keycloak');
window.cordova.plugins.browsertab.close();
kc.clearToken();
promise.setSuccess();
});
window.cordova.plugins.browsertab.openUrl(logoutUrl);
return promise.promise;
},
register : function(options) {
var promise = createPromise();
var registerUrl = kc.createRegisterUrl(options);
universalLinks.subscribe('keycloak' , function(event) {
universalLinks.unsubscribe('keycloak');
window.cordova.plugins.browsertab.close();
var oauth = parseCallback(event.url);
processCallback(oauth, promise);
});
window.cordova.plugins.browsertab.openUrl(registerUrl);
return promise.promise;
},
accountManagement : function() {
var accountUrl = kc.createAccountUrl();
if (typeof accountUrl !== 'undefined') {
window.cordova.plugins.browsertab.openUrl(accountUrl);
} else {
throw "Not supported by the OIDC server";
}
},
redirectUri: function(options) {
if (options && options.redirectUri) {
return options.redirectUri;
} else if (kc.redirectUri) {
return kc.redirectUri;
} else {
return "http://localhost";
}
}
}
}
throw 'invalid adapter type: ' + type;
}

6
examples/cordova-native/.gitignore vendored Normal file
View file

@ -0,0 +1,6 @@
platforms
plugins
www/keycloak.js
www/keycloak.json
node_modules
ul_web_hooks

View file

@ -0,0 +1,36 @@
Basic Cordova Example
=====================
Before running this example you need to have Cordova installed with a phone or emulator available.
Start and configure Keycloak
----------------------------
Start Keycloak bound to an IP address available to the phone or emulator. For example:
bin/standalone.sh -b 192.168.0.10
Open the Keycloak admin console, click on Add Realm, click on 'Choose a JSON file', selct example-realm.json and click Upload.
Navigate to applications, click on 'Cordova', select 'Installation' and in the 'Format option' drop-down select 'keycloak.json'. Download this file to the www folder.
Download '/js/keycloak.js' from the server to the www folder as well. For example:
wget http://192.168.0.10:8080/auth/js/keycloak.js
Install to Android phone or emulator
------------------------------------
cordova platform add android
cordova run android
Once the application is opened you can login with username: 'user', and password: 'password'.
Troubleshooting
-----------------------------------------
* You always need to initialize keycloak after the 'deviceready' event. Otherwise Cordova mode won't be enabled for keycloak.js.
* 'http://localhost' should be listed in the allowed redirects in client configuration, but never 'file:///android_asset'.

View file

@ -0,0 +1,25 @@
<?xml version='1.0' encoding='utf-8'?>
<widget id="org.keycloak.examples.cordova" version="1.0.0" xmlns="http://www.w3.org/ns/widgets" xmlns:gap="http://phonegap.com/ns/1.0">
<name>Keycloak Auth</name>
<description>Keycloak Cordova Example</description>
<author href="http://www.keycloak.org">Keycloak Team</author>
<feature name="http://api.phonegap.com/1.0/device" />
<preference name="permissions" value="none" />
<preference name="AndroidLaunchMode" value="singleInstance" />
<gap:plugin name="cordova-plugin-inappbrowser" />
<gap:plugin name="cordova-plugin-whitelist" source="npm" version="1.0.0" />
<access origin="*" />
<allow-navigation href="*" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<preference name="AndroidLaunchMode" value="singleTask" />
<universal-links>
<host name="keycloak-cordova-example.github.io" scheme="https">
<path event="keycloak" url="/login" />
</host>
</universal-links>
<plugin name="cordova-plugin-browsertab" spec="~0.2.0" />
<plugin name="cordova-plugin-deeplinks" spec="^1.1.0" />
<engine name="ios" spec="^4.5.4" />
<engine name="android" spec="^6.4.0" />
</widget>

View file

@ -0,0 +1,61 @@
{
"realm": "example",
"enabled": true,
"sslRequired": "external",
"registrationAllowed": true,
"privateKey": "MIICXAIBAAKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQABAoGAfmO8gVhyBxdqlxmIuglbz8bcjQbhXJLR2EoS8ngTXmN1bo2L90M0mUKSdc7qF10LgETBzqL8jYlQIbt+e6TH8fcEpKCjUlyq0Mf/vVbfZSNaVycY13nTzo27iPyWQHK5NLuJzn1xvxxrUeXI6A2WFpGEBLbHjwpx5WQG9A+2scECQQDvdn9NE75HPTVPxBqsEd2z10TKkl9CZxu10Qby3iQQmWLEJ9LNmy3acvKrE3gMiYNWb6xHPKiIqOR1as7L24aTAkEAtyvQOlCvr5kAjVqrEKXalj0Tzewjweuxc0pskvArTI2Oo070h65GpoIKLc9jf+UA69cRtquwP93aZKtW06U8dQJAF2Y44ks/mK5+eyDqik3koCI08qaC8HYq2wVl7G2QkJ6sbAaILtcvD92ToOvyGyeE0flvmDZxMYlvaZnaQ0lcSQJBAKZU6umJi3/xeEbkJqMfeLclD27XGEFoPeNrmdx0q10Azp4NfJAY+Z8KRyQCR2BEG+oNitBOZ+YXF9KCpH3cdmECQHEigJhYg+ykOvr1aiZUMFT72HU0jnmQe2FVekuG+LJUt2Tm7GtMjTFoGpf0JwrVuZN39fOYAlo+nTixgeW7X8Y=",
"publicKey": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
"requiredCredentials": [ "password" ],
"users" : [
{
"username" : "user",
"enabled": true,
"email" : "sample-user@example",
"firstName": "Sample",
"lastName": "User",
"credentials" : [
{ "type" : "password",
"value" : "password" }
],
"realmRoles": [ "user" ],
"clientRoles": {
"account": ["view-profile", "manage-account"]
}
}
],
"roles" : {
"realm" : [
{
"name": "user",
"description": "User privileges"
},
{
"name": "admin",
"description": "Administrator privileges"
}
]
},
"scopeMappings": [
{
"client": "cordova",
"roles": ["user"]
}
],
"clients": [
{
"clientId": "cordova",
"enabled": true,
"publicClient": true,
"redirectUris": ["android-app://org.keycloak.examples.cordova/https/keycloak-cordova-example.github.io/login"],
"webOrigins": ["localhost"]
}
],
"clientScopeMappings": {
"account": [
{
"client": "cordova",
"roles": ["view-profile"]
}
]
}
}

383
examples/cordova-native/package-lock.json generated Normal file
View file

@ -0,0 +1,383 @@
{
"name": "org.keycloak.examples.cordova",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"base64-js": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
"integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "1.0.0",
"concat-map": "0.0.1"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"cordova-android": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/cordova-android/-/cordova-android-6.4.0.tgz",
"integrity": "sha1-VK6NpXKKjX5e/MYXLT3MoXvH/n0=",
"requires": {
"android-versions": "1.2.1",
"cordova-common": "2.1.0",
"elementtree": "0.1.6",
"nopt": "3.0.6",
"properties-parser": "0.2.3",
"q": "1.5.0",
"shelljs": "0.5.3"
},
"dependencies": {
"abbrev": {
"version": "1.1.0",
"bundled": true
},
"android-versions": {
"version": "1.2.1",
"bundled": true
},
"ansi": {
"version": "0.3.1",
"bundled": true
},
"balanced-match": {
"version": "1.0.0",
"bundled": true
},
"base64-js": {
"version": "0.0.8",
"bundled": true
},
"big-integer": {
"version": "1.6.25",
"bundled": true
},
"bplist-parser": {
"version": "0.1.1",
"bundled": true,
"requires": {
"big-integer": "1.6.25"
}
},
"brace-expansion": {
"version": "1.1.8",
"bundled": true,
"requires": {
"balanced-match": "1.0.0",
"concat-map": "0.0.1"
}
},
"concat-map": {
"version": "0.0.1",
"bundled": true
},
"cordova-common": {
"version": "2.1.0",
"bundled": true,
"requires": {
"ansi": "0.3.1",
"bplist-parser": "0.1.1",
"cordova-registry-mapper": "1.1.15",
"elementtree": "0.1.6",
"glob": "5.0.15",
"minimatch": "3.0.4",
"osenv": "0.1.4",
"plist": "1.2.0",
"q": "1.5.0",
"semver": "5.4.1",
"shelljs": "0.5.3",
"underscore": "1.8.3",
"unorm": "1.4.1"
}
},
"cordova-registry-mapper": {
"version": "1.1.15",
"bundled": true
},
"elementtree": {
"version": "0.1.6",
"bundled": true,
"requires": {
"sax": "0.3.5"
}
},
"glob": {
"version": "5.0.15",
"bundled": true,
"requires": {
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"once": "1.4.0",
"path-is-absolute": "1.0.1"
}
},
"inflight": {
"version": "1.0.6",
"bundled": true,
"requires": {
"once": "1.4.0",
"wrappy": "1.0.2"
}
},
"inherits": {
"version": "2.0.3",
"bundled": true
},
"lodash": {
"version": "3.10.1",
"bundled": true
},
"minimatch": {
"version": "3.0.4",
"bundled": true,
"requires": {
"brace-expansion": "1.1.8"
}
},
"nopt": {
"version": "3.0.6",
"bundled": true,
"requires": {
"abbrev": "1.1.0"
}
},
"once": {
"version": "1.4.0",
"bundled": true,
"requires": {
"wrappy": "1.0.2"
}
},
"os-homedir": {
"version": "1.0.2",
"bundled": true
},
"os-tmpdir": {
"version": "1.0.2",
"bundled": true
},
"osenv": {
"version": "0.1.4",
"bundled": true,
"requires": {
"os-homedir": "1.0.2",
"os-tmpdir": "1.0.2"
}
},
"path-is-absolute": {
"version": "1.0.1",
"bundled": true
},
"plist": {
"version": "1.2.0",
"bundled": true,
"requires": {
"base64-js": "0.0.8",
"util-deprecate": "1.0.2",
"xmlbuilder": "4.0.0",
"xmldom": "0.1.27"
}
},
"properties-parser": {
"version": "0.2.3",
"bundled": true
},
"q": {
"version": "1.5.0",
"bundled": true
},
"sax": {
"version": "0.3.5",
"bundled": true
},
"semver": {
"version": "5.4.1",
"bundled": true
},
"shelljs": {
"version": "0.5.3",
"bundled": true
},
"underscore": {
"version": "1.8.3",
"bundled": true
},
"unorm": {
"version": "1.4.1",
"bundled": true
},
"util-deprecate": {
"version": "1.0.2",
"bundled": true
},
"wrappy": {
"version": "1.0.2",
"bundled": true
},
"xmlbuilder": {
"version": "4.0.0",
"bundled": true,
"requires": {
"lodash": "3.10.1"
}
},
"xmldom": {
"version": "0.1.27",
"bundled": true
}
}
},
"cordova-plugin-browsertab": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/cordova-plugin-browsertab/-/cordova-plugin-browsertab-0.2.0.tgz",
"integrity": "sha1-Hgf5hy4VRnpQ59FKc/79h0+u1ko="
},
"cordova-plugin-compat": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/cordova-plugin-compat/-/cordova-plugin-compat-1.2.0.tgz",
"integrity": "sha1-C8ZXVyduvZIMASzpIOJ0F3V2Nz4="
},
"cordova-plugin-deeplinks": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/cordova-plugin-deeplinks/-/cordova-plugin-deeplinks-1.1.0.tgz",
"integrity": "sha512-xXixVrXfX9lvhMpi1qlzkiTeOmT7P5LfgqIBUCePYSutuscX+SeRGsVM38J8nhpYIefHAJqz7ULr4hT7tunUCA==",
"requires": {
"mkpath": "1.0.0",
"node-version-compare": "1.0.1",
"plist": "3.0.1",
"rimraf": "2.6.2",
"xml2js": "0.4.19"
}
},
"cordova-plugin-whitelist": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/cordova-plugin-whitelist/-/cordova-plugin-whitelist-1.3.3.tgz",
"integrity": "sha1-tehezbv+Wu3tQKG/TuI3LmfZb7Q="
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"once": "1.4.0",
"path-is-absolute": "1.0.1"
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "1.4.0",
"wrappy": "1.0.2"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "1.1.11"
}
},
"mkpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mkpath/-/mkpath-1.0.0.tgz",
"integrity": "sha1-67Opd+evHGg65v2hK1Raa6bFhT0="
},
"node-version-compare": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/node-version-compare/-/node-version-compare-1.0.1.tgz",
"integrity": "sha1-2Fv9IPCsreM1d/VmgscQnDTFUM0="
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1.0.2"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"plist": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz",
"integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==",
"requires": {
"base64-js": "1.3.0",
"xmlbuilder": "9.0.7",
"xmldom": "0.1.27"
}
},
"rimraf": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"requires": {
"glob": "7.1.2"
}
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xml2js": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
"integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
"requires": {
"sax": "1.2.4",
"xmlbuilder": "9.0.7"
}
},
"xmlbuilder": {
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
"integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
},
"xmldom": {
"version": "0.1.27",
"resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.27.tgz",
"integrity": "sha1-1QH5ezvbQDr4757MIFcxh6rawOk="
}
}
}

View file

@ -0,0 +1,24 @@
{
"name": "org.keycloak.examples.cordova",
"version": "1.0.0",
"displayName": "Keycloak Auth",
"cordova": {
"platforms": [
"ios",
"android"
],
"plugins": {
"cordova-plugin-browsertab": {},
"cordova-plugin-deeplinks": {},
"cordova-plugin-whitelist": {}
}
},
"dependencies": {
"cordova-android": "^6.4.0",
"cordova-ios": "^4.5.4",
"cordova-plugin-browsertab": "^0.2.0",
"cordova-plugin-compat": "^1.2.0",
"cordova-plugin-deeplinks": "^1.1.0",
"cordova-plugin-whitelist": "^1.3.3"
}
}

View file

@ -0,0 +1,123 @@
<!DOCTYPE html>
<!--
~ Copyright 2016 Red Hat, Inc. and/or its affiliates
~ and other contributors as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<html>
<head>
<title>Authentication Example</title>
<meta http-equiv="Content-Security-Policy" content="default-src * gap://ready; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'">
<script type="text/javascript" charset="utf-8" src="cordova.js"></script>
<script type="text/javascript" charset="utf-8" src="keycloak.js"></script>
<script type="text/javascript" charset="utf-8">
var keycloak = new Keycloak();
keycloak.onAuthSuccess = updateState;
keycloak.onAuthRefreshSuccess = updateState;
keycloak.onAuthLogout = updateState;
function updateState() {
if (keycloak.authenticated) {
document.getElementById('authenticated').style.display = 'block';
document.getElementById('not-authenticated').style.display = 'none';
document.getElementById('subject').innerText = keycloak.subject;
document.getElementById('username').innerText = keycloak.idTokenParsed.preferred_username;
document.getElementById('tokenExpires').innerText = new Date(keycloak.tokenParsed.exp * 1000).toLocaleString();
document.getElementById('tokenRefreshExpires').innerText = new Date(keycloak.refreshTokenParsed.exp * 1000).toLocaleString();
document.getElementById('token').innerText = JSON.stringify(keycloak.tokenParsed, null, ' ');
document.getElementById('idToken').innerText = JSON.stringify(keycloak.idTokenParsed, null, ' ');
} else {
document.getElementById('authenticated').style.display = 'none';
document.getElementById('not-authenticated').style.display = 'block';
}
}
function error() {
document.getElementById('authenticated').style.display = 'none';
document.getElementById('not-authenticated').style.display = 'block';
document.getElementById('error').innerText = 'Failed to initialize Keycloak adapter';
}
document.addEventListener("deviceready", function() {
keycloak.init({
adapter: 'cordova-native',
responseMode: 'query',
onLoad: 'check-sso',
redirectUri: 'android-app://org.keycloak.examples.cordova/https/keycloak-cordova-example.github.io/login'
}).success(updateState).error(error);
}, false);
</script>
<style>
td {
vertical-align: top;
}
tr.odd td {
background-color: #eee;
}
</style>
</head>
<body>
<div id="authenticated" style="display: none;">
<div>
<button onclick="keycloak.logout()">Log out</button>
<button onclick="keycloak.updateToken()">Refresh token</button>
<button onclick="keycloak.updateToken(9999)">Force Refresh token</button>
<button onclick="keycloak.accountManagement()">Manage account</button>
</div>
<div>
<table>
<tr>
<td>Subject</td>
<td id="subject"></td>
</tr>
<tr class="odd">
<td>Username</td>
<td id="username"></td>
</tr>
<tr>
<td>Token expires</td>
<td id="tokenExpires"></td>
</tr>
<tr class="odd">
<td>Refresh token expires</td>
<td id="tokenRefreshExpires"></td>
</tr>
<tr>
<td>Token</td>
<td><pre id="token"></pre></td>
</tr>
<tr class="odd">
<td>ID Token</td>
<td><pre id="idToken"></pre></td>
</tr>
</table>
</div>
</div>
<div id="not-authenticated" style="display: none;">
<div>
<button onclick="keycloak.login()">Log in</button>
</div>
<div>
<p id="error">Not authenticated</p>
</div>
</div>
</body>
</html>