keycloak-uncached

Details

diff --git a/docbook/reference/en/en-US/modules/javascript-adapter.xml b/docbook/reference/en/en-US/modules/javascript-adapter.xml
index 03a303d..dd6c3ee 100755
--- a/docbook/reference/en/en-US/modules/javascript-adapter.xml
+++ b/docbook/reference/en/en-US/modules/javascript-adapter.xml
@@ -157,6 +157,7 @@ new Keycloak({ url: 'http://localhost/auth', realm: 'myrealm', clientId: 'myApp'
                 <listitem>tokenParsed - the parsed token</listitem>
                 <listitem>subject - the user id</listitem>
                 <listitem>idToken - the id token if claims is enabled for the application, null otherwise</listitem>
+                <listitem>idTokenParsed - the parsed id token</listitem>
                 <listitem>realmAccess - the realm roles associated with the token</listitem>
                 <listitem>resourceAccess - the resource roles assocaited with the token</listitem>
                 <listitem>refreshToken - the base64 encoded token that can be used to retrieve a new token</listitem>
diff --git a/docbook/reference/en/en-US/modules/MigrationFromOlderVersions.xml b/docbook/reference/en/en-US/modules/MigrationFromOlderVersions.xml
index 93987ad..3e05860 100755
--- a/docbook/reference/en/en-US/modules/MigrationFromOlderVersions.xml
+++ b/docbook/reference/en/en-US/modules/MigrationFromOlderVersions.xml
@@ -85,6 +85,7 @@
                 <listitem>The tomcat adapter valve has moved to a different package.  From <literal>org.keycloak.adapters.tomcat7.KeycloakAuthenticatorValve</literal> to <literal>org.keycloak.adapters.tomcat.KeycloakAuthenticatorValve</literal>
                 From the 'tomcat7' package to just 'tomcat'.
                 </listitem>
+                <listitem>JavaScript adapter now has idToken and idTokenParsed properties. If you use idToken to retrieve first name, email, etc. you need to change this to idTokenParsed.</listitem>
             </itemizedlist>
         </section>
         <section>
diff --git a/examples/js-console/src/main/webapp/index.html b/examples/js-console/src/main/webapp/index.html
index b0cbf39..afb2811 100644
--- a/examples/js-console/src/main/webapp/index.html
+++ b/examples/js-console/src/main/webapp/index.html
@@ -12,6 +12,7 @@
     <button onclick="loadProfile()">Get Profile</button>
     <button onclick="output(keycloak.tokenParsed)">Show Token</button>
     <button onclick="output(keycloak.refreshTokenParsed)">Show Refresh Token</button>
+    <button onclick="output(keycloak.idTokenParsed)">Show ID Token</button>
     <button onclick="showExpires()">Show Expires</button>
     <button onclick="output(keycloak.idToken)">Show ID Token</button>
     <button onclick="output(keycloak)">Show Details</button>
diff --git a/integration/js/src/main/resources/keycloak.js b/integration/js/src/main/resources/keycloak.js
index d412f19..d57c48d 100755
--- a/integration/js/src/main/resources/keycloak.js
+++ b/integration/js/src/main/resources/keycloak.js
@@ -70,7 +70,7 @@
                     }
 
                     if (initOptions.token || initOptions.refreshToken) {
-                        setToken(initOptions.token, initOptions.refreshToken);
+                        setToken(initOptions.token, initOptions.refreshToken, initOptions.idToken);
                         initPromise.setSuccess();
                     } else if (initOptions.onLoad) {
                         var options = {};
@@ -255,7 +255,7 @@
                             if (req.readyState == 4) {
                                 if (req.status == 200) {
                                     var tokenResponse = JSON.parse(req.responseText);
-                                    setToken(tokenResponse['access_token'], tokenResponse['refresh_token']);
+                                    setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token']);
                                     kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
                                     for (var p = refreshQueue.pop(); p != null; p = refreshQueue.pop()) {
                                         p.setSuccess(true);
@@ -325,7 +325,7 @@
                     if (req.readyState == 4) {
                         if (req.status == 200) {
                             var tokenResponse = JSON.parse(req.responseText);
-                            setToken(tokenResponse['access_token'], tokenResponse['refresh_token']);
+                            setToken(tokenResponse['access_token'], tokenResponse['refresh_token'], tokenResponse['id_token']);
                             kc.onAuthSuccess && kc.onAuthSuccess();
                             promise && promise.setSuccess();
                         } else {
@@ -411,7 +411,7 @@
 
         function clearToken() {
             if (kc.token) {
-                setToken(null, null);
+                setToken(null, null, null);
                 kc.onAuthLogout && kc.onAuthLogout();
                 if (kc.loginRequired) {
                     kc.login();
@@ -419,14 +419,14 @@
             }
         }
 
-        function setToken(token, refreshToken) {
+        function setToken(token, refreshToken, idToken) {
             if (token || refreshToken) {
                 setupCheckLoginIframe();
             }
 
             if (token) {
                 kc.token = token;
-                kc.tokenParsed = JSON.parse(decodeURIComponent(escape(window.atob( token.split('.')[1] ))));
+                kc.tokenParsed = decodeToken(token);
                 var sessionId = kc.realm + '/' + kc.tokenParsed.sub;
                 if (kc.tokenParsed.session_state) {
                     sessionId = sessionId + '/' + kc.tokenParsed.session_state;
@@ -436,34 +436,59 @@
                 kc.subject = kc.tokenParsed.sub;
                 kc.realmAccess = kc.tokenParsed.realm_access;
                 kc.resourceAccess = kc.tokenParsed.resource_access;
-
-                for (var i = 0; i < idTokenProperties.length; i++) {
-                    var n = idTokenProperties[i];
-                    if (kc.tokenParsed[n]) {
-                        if (!kc.idToken) {
-                            kc.idToken = {};
-                        }
-                        kc.idToken[n] = kc.tokenParsed[n];
-                    }
-                }
             } else {
                 delete kc.token;
                 delete kc.tokenParsed;
                 delete kc.subject;
                 delete kc.realmAccess;
                 delete kc.resourceAccess;
-                delete kc.idToken;
 
                 kc.authenticated = false;
             }
 
             if (refreshToken) {
                 kc.refreshToken = refreshToken;
-                kc.refreshTokenParsed = JSON.parse(atob(refreshToken.split('.')[1]));
+                kc.refreshTokenParsed = decodeToken(refreshToken);
             } else {
                 delete kc.refreshToken;
                 delete kc.refreshTokenParsed;
             }
+
+            if (idToken) {
+                kc.idToken = idToken;
+                kc.idTokenParsed = decodeToken(idToken);
+            } else {
+                delete kc.idToken;
+                delete kc.idTokenParsed;
+            }
+        }
+
+        function decodeToken(str) {
+            str = str.split('.')[1];
+
+            str = str.replace('/-/g', '+');
+            str = str.replace('/_/g', '/');
+            switch (str.length % 4)
+            {
+                case 0:
+                    break;
+                case 2:
+                    str += '==';
+                    break;
+                case 3:
+                    str += '=';
+                    break;
+                default:
+                    throw 'Invalid token';
+            }
+
+            str = (str + '===').slice(0, str.length + (str.length % 4));
+            str = str.replace(/-/g, '+').replace(/_/g, '/');
+
+            str = decodeURIComponent(escape(atob(str)));
+
+            str = JSON.parse(str);
+            return str;
         }
 
         function createUUID() {
@@ -763,57 +788,15 @@
 
             throw 'invalid adapter type: ' + type;
         }
-
-        var idTokenProperties = [
-            "name", 
-            "given_name", 
-            "family_name", 
-            "middle_name", 
-            "nickname", 
-            "preferred_username", 
-            "profile", 
-            "picture", 
-            "website", 
-            "email", 
-            "email_verified", 
-            "gender", 
-            "birthdate", 
-            "zoneinfo", 
-            "locale", 
-            "phone_number", 
-            "phone_number_verified", 
-            "address", 
-            "updated_at", 
-            "formatted", 
-            "street_address", 
-            "locality", 
-            "region", 
-            "postal_code", 
-            "country", 
-            "claims_locales"
-        ]
     }
 
     if ( typeof module === "object" && module && typeof module.exports === "object" ) {
-        // Expose KeyCloak as module.exports in loaders that implement the Node
-        // module pattern (including browserify). Do not create the global, since
-        // the user will be storing it themselves locally, and globals are frowned
-        // upon in the Node module world.
         module.exports = Keycloak;
     } else {
-        // Otherwise expose KeyCloak to the global object as usual
         window.Keycloak = Keycloak;
 
-        // Register as a named AMD module, since KeyCloak can be concatenated with other
-        // files that may use define, but not via a proper concatenation script that
-        // understands anonymous AMD modules. A named AMD is safest and most robust
-        // way to register. Lowercase jquery is used because AMD module names are
-        // derived from file names, and KeyCloak is normally delivered in a lowercase
-        // file name. Do this after creating the global so that if an AMD module wants
-        // to call noConflict to hide this version of KeyCloak, it will work.
         if ( typeof define === "function" && define.amd ) {
             define( "keycloak", [], function () { return Keycloak; } );
         }
     }
-
 })( window );