keycloak-aplcache

Updates to keycloak.js

3/15/2014 9:53:52 AM

Details

diff --git a/examples/js-console/pom.xml b/examples/js-console/pom.xml
new file mode 100755
index 0000000..1e8dc6a
--- /dev/null
+++ b/examples/js-console/pom.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <parent>
+        <artifactId>keycloak-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>1.0-beta-1-SNAPSHOT</version>
+        <relativePath>../../../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.keycloak.example.demo</groupId>
+    <artifactId>js-console</artifactId>
+    <packaging>war</packaging>
+    <name>JS Console</name>
+    <description/>
+
+    <build>
+        <finalName>js-console</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.jboss.as.plugins</groupId>
+                <artifactId>jboss-as-maven-plugin</artifactId>
+                <version>7.4.Final</version>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.6</source>
+                    <target>1.6</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/examples/js-console/src/main/webapp/index.html b/examples/js-console/src/main/webapp/index.html
new file mode 100644
index 0000000..58513ad
--- /dev/null
+++ b/examples/js-console/src/main/webapp/index.html
@@ -0,0 +1,97 @@
+<html>
+<head>
+    <script src="http://localhost:8080/auth/js/keycloak.js"></script>
+</head>
+<body>
+
+<div>
+    <button onclick="keycloak.login()">Login</button>
+    <button onclick="keycloak.logout()">Logout</button>
+    <button onclick="refreshToken()">Refresh Token</button>
+    <button onclick="refreshToken(30)">Refresh Token (if <30s validity)</button>
+    <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="showExpires()">Show Expires</button>
+    <button onclick="output(keycloak.idToken)">Show ID Token</button>
+    <button onclick="output(keycloak)">Show Details</button>
+    <button onclick="output(keycloak.createLoginUrl())">Show Login URL</button>
+    <button onclick="output(keycloak.createLogoutUrl())">Show Logout URL</button>
+</div>
+
+<h2>Result</h2>
+<pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="output"></pre>
+
+<h2>Events</h2>
+<pre style="background-color: #ddd; border: 1px solid #ccc; padding: 10px;" id="events"></pre>
+
+
+<script>
+    function loadProfile() {
+        keycloak.loadUserProfile().success(function(profile) {
+            output(profile);
+        }).error(function() {
+            output('Failed to load profile');
+        });
+    }
+
+    function refreshToken(minValidity) {
+        keycloak.refreshAccessToken(minValidity).success(function(refreshed) {
+            if (refreshed) {
+                output(keycloak.tokenParsed);
+            } else {
+                output('Token not refreshed, valid for ' + Math.round(keycloak.tokenParsed.exp - new Date().getTime() / 1000) + ' seconds');
+            }
+        }).error(function() {
+            output('Failed to refresh token');
+        });
+    }
+
+    function showExpires() {
+        var o = 'Token Expires:\t\t' + new Date(keycloak.tokenParsed.exp * 1000).toLocaleString() + '\n';
+        o += 'Token Expires in:\t' + Math.round(keycloak.tokenParsed.exp - new Date().getTime() / 1000) + ' seconds\n';
+
+        o += 'Refresh Token Expires:\t' + new Date(keycloak.refreshTokenParsed.exp * 1000).toLocaleString() + '\n';
+        o += 'Refresh Expires in:\t' + Math.round(keycloak.refreshTokenParsed.exp - new Date().getTime() / 1000) + ' seconds';
+        output(o);
+    }
+
+    function output(data) {
+        if (typeof data === 'object') {
+            data = JSON.stringify(data, null, '  ');
+        }
+        document.getElementById('output').innerText = data;
+    }
+
+    function event(event) {
+        var e = document.getElementById('events').innerText;
+        document.getElementById('events').innerText = new Date().toLocaleString() + "\t" + event + "\n" + e;
+    }
+
+    var keycloak = Keycloak();
+
+    keycloak.onAuthSuccess = function () {
+        event('Auth Success');
+    };
+
+    keycloak.onAuthError = function () {
+        event('Auth Error');
+    };
+
+    keycloak.onAuthRefreshSuccess = function () {
+        event('Auth Refresh Success');
+    };
+
+    keycloak.onAuthRefreshError = function () {
+        event('Auth Refresh Error');
+    };
+
+    keycloak.init().success(function(authenticated) {
+        output('Init Success (' + (authenticated ? 'Authenticated' : 'Not Authenticated') + ')');
+    }).error(function() {
+        output('Init Error');
+    });
+
+</script>
+</body>
+</html>
diff --git a/examples/js-console/src/main/webapp/keycloak.json b/examples/js-console/src/main/webapp/keycloak.json
new file mode 100644
index 0000000..f166f87
--- /dev/null
+++ b/examples/js-console/src/main/webapp/keycloak.json
@@ -0,0 +1,8 @@
+{
+  "realm" : "example",
+  "realm-public-key" : "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrVrCuTtArbgaZzL1hvh0xtL5mc7o0NqPVnYXkLvgcwiC3BjLGw1tGEGoJaXDuSaRllobm53JBhjx33UNv+5z/UMG4kytBWxheNVKnL6GgqlNabMaFfPLPCF8kAgKnsi79NMo+n6KnSY8YeUmec/p2vjO2NjsSAVcWEQMVhJ31LwIDAQAB",
+  "auth-server-url" : "http://localhost:8080/auth",
+  "ssl-not-required" : true,
+  "resource" : "js-console",
+  "public-client" : true
+}
\ No newline at end of file
diff --git a/integration/js/src/main/resources/META-INF/resources/js/keycloak.js b/integration/js/src/main/resources/META-INF/resources/js/keycloak.js
index b3a6af4..6860b78 100755
--- a/integration/js/src/main/resources/META-INF/resources/js/keycloak.js
+++ b/integration/js/src/main/resources/META-INF/resources/js/keycloak.js
@@ -1,58 +1,108 @@
-var Keycloak = function (options) {
-    options = options || {};
-
+var Keycloak = function (config) {
     if (!(this instanceof Keycloak)) {
-        return new Keycloak(options);
+        return new Keycloak(config);
     }
 
     var kc = this;
+    kc.authenticated = false;
+
+    var configPromise = createPromise();
+    configPromise.name = 'config';
 
-    if (!options.url) {
-        var scripts = document.getElementsByTagName('script');
-        for (var i = 0; i < scripts.length; i++) {
-            if (scripts[i].src.match(/.*keycloak\.js/)) {
-                options.url = scripts[i].src.substr(0, scripts[i].src.indexOf('/auth/js/keycloak.js'));
-                break;
+    if (!config) {
+        loadConfig('keycloak.json', configPromise);
+    } else if (typeof config === 'string') {
+        loadConfig(config, configPromise);
+    } else {
+        if (!config['url']) {
+            var scripts = document.getElementsByTagName('script');
+            for (var i = 0; i < scripts.length; i++) {
+                if (scripts[i].src.match(/.*keycloak\.js/)) {
+                    config.url = scripts[i].src.substr(0, scripts[i].src.indexOf('/js/keycloak.js'));
+                    break;
+                }
             }
         }
+
+        if (!config.realm) {
+            throw 'realm missing';
+        }
+
+        if (!config.clientId) {
+            throw 'clientId missing';
+        }
+
+        kc.authServerUrl = config.url;
+        kc.realm = config.realm;
+        kc.clientId = config.clientId;
+
+        configPromise.setSuccess();
     }
 
-    if (!options.url) {
-        throw 'url missing';
+    kc.init = function (init) {
+        var promise = createPromise();
+        var callback = parseCallback(window.location.href);
+
+        function processInit() {
+            if (callback) {
+                window.history.replaceState({}, null, location.protocol + '//' + location.host + location.pathname + (callback.fragment ? '#' + callback.fragment : ''));
+                processCallback(callback, promise);
+                return;
+            } else if (init) {
+                if (init.code || init.error) {
+                    processCallback(init, promise);
+                    return;
+                } else if (init.token || init.refreshToken) {
+                    setToken(init.token, init.refreshToken);
+                } else if (init == 'login-required') {
+                    kc.login();
+                    return;
+                } else if (init == 'check-sso') {
+                    window.location = kc.createLoginUrl() + '&prompt=none';
+                    return;
+                }
+            }
+
+            promise.setSuccess(false);
+        }
+
+        configPromise.promise.success(processInit);
+
+        return promise.promise;
     }
 
-    if (!options.realm) {
-        throw 'realm missing';
+    kc.login = function (redirectUri) {
+        window.location.href = kc.createLoginUrl(redirectUri);
     }
 
-    if (!options.clientId) {
-        throw 'clientId missing';
+    kc.createLoginUrl = function(redirectUri) {
+        var state = createUUID();
+
+        sessionStorage.oauthState = state;
+        var url = getRealmUrl()
+            + '/tokens/login'
+            + '?client_id=' + encodeURIComponent(kc.clientId)
+            + '&redirect_uri=' + getEncodedRedirectUri(redirectUri)
+            + '&state=' + encodeURIComponent(state)
+            + '&response_type=code';
+
+        return url;
     }
 
-    kc.init = function (successCallback, errorCallback) {
-        if (window.oauth.callback) {
-            processCallback(successCallback, errorCallback);
-        } else if (options.token) {
-            kc.setToken(options.token, successCallback);
-        } else if (options.onload) {
-            switch (options.onload) {
-                case 'login-required' :
-                    window.location = kc.createLoginUrl(true);
-                    break;
-                case 'check-sso' :
-                    window.location = kc.createLoginUrl(false);
-                    break;
-            }
-        }
+    kc.logout = function(redirectUri) {
+        setToken(null, null);
+        window.location.href = kc.createLogoutUrl(redirectUri);
     }
 
-    kc.login = function () {
-        window.location.href = kc.createLoginUrl(true);
+    kc.clearToken = function() {
+        setToken(null, null);
     }
 
-    kc.logout = function () {
-        kc.setToken(undefined);
-        window.location.href = kc.createLogoutUrl();
+    kc.createLogoutUrl = function(redirectUri) {
+        var url = getRealmUrl()
+            + '/tokens/logout'
+            + '?redirect_uri=' + getEncodedRedirectUri(redirectUri);
+        return url;
     }
 
     kc.hasRealmRole = function (role) {
@@ -60,122 +110,131 @@ var Keycloak = function (options) {
         return access && access.roles.indexOf(role) >= 0 || false;
     }
 
-    kc.hasResourceRole = function (role, resource) {
+    kc.hasResourceRole = function(role, resource) {
         if (!kc.resourceAccess) {
             return false;
         }
 
-        var access = kc.resourceAccess[resource || options.clientId];
+        var access = kc.resourceAccess[resource || kc.clientId];
         return access && access.roles.indexOf(role) >= 0 || false;
     }
 
-    kc.loadUserProfile = function (success, error) {
-        var url = kc.getRealmUrl() + '/account';
+    kc.loadUserProfile = function() {
+        var url = getRealmUrl() + '/account';
         var req = new XMLHttpRequest();
         req.open('GET', url, true);
         req.setRequestHeader('Accept', 'application/json');
         req.setRequestHeader('Authorization', 'bearer ' + kc.token);
 
+        var promise = createPromise();
+
         req.onreadystatechange = function () {
             if (req.readyState == 4) {
                 if (req.status == 200) {
                     kc.profile = JSON.parse(req.responseText);
-                    success && success(kc.profile)
+                    promise.setSuccess(kc.profile);
                 } else {
-                    var response = { status: req.status, statusText: req.status };
-                    if (req.responseText) {
-                        response.data = JSON.parse(req.responseText);
-                    }
-                    error && error(response);
+                    promise.setError();
                 }
             }
         }
 
         req.send();
+
+        return promise.promise;
     }
 
-    /**
-     * checks to make sure token is valid.  If it is, it calls successCallback with no parameters.
-     * If it isn't valid, it tries to refresh the access token.  On successful refresh, it calls successCallback.
-     *
-     * @param successCallback
-     * @param errorCallback
-     */
-    kc.onValidAccessToken = function(successCallback, errorCallback) {
-        if (!kc.tokenParsed) {
-            console.log('no token');
-            errorCallback();
-            return;
+    kc.refreshAccessToken = function(minValidity) {
+        if (!kc.tokenParsed || !kc.refreshToken) {
+            throw 'Not authenticated';
         }
-        var currTime = new Date().getTime() / 1000;
-        if (currTime > kc.tokenParsed['exp']) {
-            if (!kc.refreshToken) {
-                console.log('no refresh token');
-                errorCallback();
-                return;
+
+        var promise = createPromise();
+
+        if (minValidity) {
+            var expiresIn = kc.tokenParsed['exp'] - (new Date().getTime() / 1000);
+            if (expiresIn > minValidity) {
+                promise.setSuccess(false);
+                return promise.promise;
             }
-            console.log('calling refresh');
-            var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
-            var url = kc.getRealmUrl() + '/tokens/refresh';
+        }
 
-            var req = new XMLHttpRequest();
-            req.open('POST', url, true, options.clientId, options.clientSecret);
-            req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+        var params = 'grant_type=refresh_token&' + 'refresh_token=' + kc.refreshToken;
+        var url = getRealmUrl() + '/tokens/refresh';
 
-            req.onreadystatechange = function () {
-                if (req.readyState == 4) {
-                    if (req.status == 200) {
-                        console.log('Refresh Success');
-                        var tokenResponse = JSON.parse(req.responseText);
-                        kc.refreshToken = tokenResponse['refresh_token'];
-                        kc.setToken(tokenResponse['access_token'], successCallback);
-                    } else {
-                        console.log('error on refresh HTTP invoke: ' + req.status);
-                        errorCallback && errorCallback({ authenticated: false, status: req.status, statusText: req.statusText });
-                    }
-                }
-            };
-            req.send(params);
+        var req = new XMLHttpRequest();
+        req.open('POST', url, true);
+        req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+
+        if (kc.clientId && kc.clientSecret) {
+            req.setRequestHeader('Authorization', 'Basic ' + btoa(kc.clientId + ':' + kc.clientSecret));
         } else {
-            console.log('Token is still valid');
-            successCallback();
+            params += '&client_id=' + encodeURIComponent(kc.clientId);
         }
 
+        req.onreadystatechange = function() {
+            if (req.readyState == 4) {
+                if (req.status == 200) {
+                    var tokenResponse = JSON.parse(req.responseText);
+                    setToken(tokenResponse['access_token'], tokenResponse['refresh_token']);
+                    kc.onAuthRefreshSuccess && kc.onAuthRefreshSuccess();
+                    promise.setSuccess(true);
+                } else {
+                    kc.onAuthRefreshError && kc.onAuthRefreshError();
+                    promise.setError();
+                }
+            }
+        };
+
+        req.send(params);
+
+        return promise.promise;
     }
 
-    kc.getRealmUrl = function() {
-        return options.url + '/auth/rest/realms/' + encodeURIComponent(options.realm);
+    kc.processCallback = function(url) {
+        var callback = parseCallback(url);
+        if (callback) {
+            var promise = createPromise();
+            processCallback(callback, promise);
+            return promise;
+        }
     }
 
-    function processCallback(successCallback, errorCallback) {
-        var code = window.oauth.code;
-        var error = window.oauth.error;
-        var prompt = window.oauth.prompt;
+    function getRealmUrl() {
+        return kc.authServerUrl + '/rest/realms/' + encodeURIComponent(kc.realm);
+    }
+
+    function processCallback(oauth, promise) {
+        var code = oauth.code;
+        var error = oauth.error;
+        var prompt = oauth.prompt;
 
         if (code) {
             var params = 'code=' + code;
-            var url = kc.getRealmUrl() + '/tokens/access/codes';
+            var url = getRealmUrl() + '/tokens/access/codes';
 
             var req = new XMLHttpRequest();
             req.open('POST', url, true);
             req.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
 
-            if (options.clientId && options.clientSecret) {
-                req.setRequestHeader('Authorization', 'Basic ' + btoa(options.clientId + ':' + options.clientSecret));
+            if (kc.clientId && kc.clientSecret) {
+                req.setRequestHeader('Authorization', 'Basic ' + btoa(kc.clientId + ':' + kc.clientSecret));
             } else {
-                params += '&client_id=' + encodeURIComponent(options.clientId);
+                params += '&client_id=' + encodeURIComponent(kc.clientId);
             }
 
             req.withCredentials = true;
 
-            req.onreadystatechange = function () {
+            req.onreadystatechange = function() {
                 if (req.readyState == 4) {
                     if (req.status == 200) {
                         var tokenResponse = JSON.parse(req.responseText);
-                        kc.refreshToken = tokenResponse['refresh_token'];
-                        kc.setToken(tokenResponse['access_token'], successCallback);
+                        setToken(tokenResponse['access_token'], tokenResponse['refresh_token']);
+                        kc.onAuthSuccess && kc.onAuthSuccess();
+                        promise.setSuccess(true);
                     } else {
-                        errorCallback && errorCallback({ authenticated: false, status: req.status, statusText: req.statusText });
+                        kc.onAuthError && kc.onAuthError();
+                        promise.setError();
                     }
                 }
             };
@@ -183,16 +242,38 @@ var Keycloak = function (options) {
             req.send(params);
         } else if (error) {
             if (prompt != 'none') {
-                setTimeout(function() {
-                    errorCallback && errorCallback({  authenticated: false, error: error })
-                }, 0);
+                kc.onAuthError && kc.onAuthError();
+                promise.setError();
             }
         }
     }
 
-    kc.setToken = function(token, successCallback) {
+    function loadConfig(url, configPromise) {
+        var req = new XMLHttpRequest();
+        req.open('GET', url, true);
+        req.setRequestHeader('Accept', 'application/json');
+
+        req.onreadystatechange = function () {
+            if (req.readyState == 4) {
+                if (req.status == 200) {
+                    var config = JSON.parse(req.responseText);
+
+                    kc.authServerUrl = config['auth-server-url'];
+                    kc.realm = config['realm'];
+                    kc.clientId = config['resource'];
+
+                    configPromise.setSuccess();
+                } else {
+                    configPromise.setError();
+                }
+            }
+        };
+
+        req.send();
+    }
+
+    function setToken(token, refreshToken) {
         if (token) {
-            window.oauth.token = token;
             kc.token = token;
             kc.tokenParsed = JSON.parse(atob(token.split('.')[1]));
             kc.authenticated = true;
@@ -209,45 +290,32 @@ var Keycloak = function (options) {
                     kc.idToken[n] = kc.tokenParsed[n];
                 }
             }
-
-            setTimeout(function() {
-                successCallback && successCallback({ authenticated: kc.authenticated, subject: kc.subject });
-            }, 0);
         } else {
-            delete window.oauth.token;
             delete kc.token;
-        }
-    }
-
-    kc.createLoginUrl = function(prompt) {
-        var state = createUUID();
+            delete kc.tokenParsed;
+            delete kc.subject;
+            delete kc.realmAccess;
+            delete kc.resourceAccess;
+            delete kc.idToken;
 
-        sessionStorage.oauthState = state;
-        var url = kc.getRealmUrl()
-            + '/tokens/login'
-            + '?client_id=' + encodeURIComponent(options.clientId)
-            + '&redirect_uri=' + getEncodedRedirectUri()
-            + '&state=' + encodeURIComponent(state)
-            + '&response_type=code';
-
-        if (prompt == false) {
-            url += '&prompt=none';
+            kc.authenticated = false;
         }
 
-        return url;
-    }
-
-    kc.createLogoutUrl = function() {
-        var url = kc.getRealmUrl()
-            + '/tokens/logout'
-            + '?redirect_uri=' + getEncodedRedirectUri();
-        return url;
+        if (refreshToken) {
+            kc.refreshToken = refreshToken;
+            kc.refreshTokenParsed = JSON.parse(atob(refreshToken.split('.')[1]));
+        } else {
+            delete kc.refreshToken;
+            delete kc.refreshTokenParsed;
+        }
     }
 
-    function getEncodedRedirectUri() {
+    function getEncodedRedirectUri(redirectUri) {
         var url;
-        if (options.redirectUri) {
-            url = options.redirectUri;
+        if (redirectUri) {
+            url = redirectUri;
+        } else if (kc.redirectUri) {
+            url = kc.redirectUri;
         } else {
             url = (location.protocol + '//' + location.hostname + (location.port && (':' + location.port)) + location.pathname);
             if (location.hash) {
@@ -269,7 +337,81 @@ var Keycloak = function (options) {
         var uuid = s.join('');
         return uuid;
     }
-    
+
+    function parseCallback(url) {
+
+        if (url.indexOf('?') != -1) {
+            var oauth = {};
+
+            var params = url.split('?')[1].split('&');
+            for (var i = 0; i < params.length; i++) {
+                var p = params[i].split('=');
+                switch (decodeURIComponent(p[0])) {
+                    case 'code':
+                        oauth.code = p[1];
+                        break;
+                    case 'error':
+                        oauth.error = p[1];
+                        break;
+                    case 'state':
+                        oauth.state = decodeURIComponent(p[1]);
+                        break;
+                    case 'redirect_fragment':
+                        oauth.fragment = decodeURIComponent(p[1]);
+                        break;
+                    case 'prompt':
+                        oauth.prompt = p[1];
+                        break;
+                }
+            }
+
+            if (oauth.state && oauth.state == sessionStorage.oauthState) {
+                delete sessionStorage.oauthState;
+                return oauth;
+            }
+        }
+    }
+
+    function createPromise() {
+        var p = {
+            setSuccess: function(result) {
+                p.success = true;
+                p.result = result;
+                if (p.successCallback) {
+                    p.successCallback(result);
+                }
+            },
+
+            setError: function(result) {
+                p.error = true;
+                p.result = result;
+                if (p.errorCallback) {
+                    p.errorCallback(result);
+                }
+            },
+
+            promise: {
+                success: function(callback) {
+                    if (p.success) {
+                        callback(p.result);
+                    } else if (!p.error) {
+                        p.successCallback = callback;
+                    }
+                    return p.promise;
+                },
+                error: function(callback) {
+                    if (p.error) {
+                        callback(p.result);
+                    } else if (!p.success) {
+                        p.errorCallback = callback;
+                    }
+                    return p.promise;
+                }
+            }
+        }
+        return p;
+    }
+
     var idTokenProperties = [
         "name", 
         "given_name", 
@@ -298,45 +440,4 @@ var Keycloak = function (options) {
         "country", 
         "claims_locales"
     ]
-}
-
-window.oauth = (function () {
-    var oauth = {};
-
-    var params = window.location.search.substring(1).split('&');
-    for (var i = 0; i < params.length; i++) {
-        var p = params[i].split('=');
-        switch (decodeURIComponent(p[0])) {
-            case 'code':
-                oauth.code = p[1];
-                break;
-            case 'error':
-                oauth.error = p[1];
-                break;
-            case 'state':
-                oauth.state = decodeURIComponent(p[1]);
-                break;
-            case 'redirect_fragment':
-                oauth.fragment = decodeURIComponent(p[1]);
-                break;
-            case 'prompt':
-                oauth.prompt = p[1];
-                break;
-        }
-    }
-
-    if (oauth.state && oauth.state == sessionStorage.oauthState) {
-        oauth.callback = true;
-        delete sessionStorage.oauthState;
-    } else {
-        oauth.callback = false;
-    }
-
-    if (oauth.callback) {
-        window.history.replaceState({}, null, location.protocol + '//' + location.host + location.pathname + (oauth.fragment ? '#' + oauth.fragment : ''));
-    } else if (oauth.fragment) {
-        window.history.replaceState({}, null, location.protocol + '//' + location.host + location.pathname + (oauth.fragment ? '#' + oauth.fragment : ''));
-    }
-
-    return oauth;
-}());
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java b/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java
index 1da9807..262bf60 100755
--- a/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java
+++ b/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java
@@ -37,8 +37,9 @@ public class KeycloakServerApplication extends KeycloakApplication {
         try {
             RealmManager manager = new RealmManager(session);
 
-            if (rep.getId() == null) {
-                throw new RuntimeException("Realm id not specified");
+            if (rep.getId() != null && manager.getRealm(rep.getId()) != null) {
+                log.info("Not importing realm " + rep.getRealm() + " realm already exists");
+                return;
             }
 
             if (manager.getRealmByName(rep.getRealm()) != null) {