keycloak-memoizeit

nasty merge

11/6/2013 2:12:07 AM

Changes

admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/login-register.css 284(+0 -284)

admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/login-register.less 322(+0 -322)

dist/assembly.xml 50(+50 -0)

dist/build.xml 37(+37 -0)

dist/pom.xml 96(+96 -0)

examples/js-google/index.html 24(+0 -24)

examples/js-google/keycloak.js 139(+0 -139)

examples/js-google/keycloak.js.orig 222(+0 -222)

examples/js-google/kinvey.html 13(+0 -13)

examples/js-google/testrealm.json 60(+0 -60)

forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-separators.png 0(+0 -0)

forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-social-separators.png 0(+0 -0)

model/pom.xml 2(+1 -1)

pom.xml 4(+3 -1)

server/pom.xml 149(+149 -0)

social/core/src/main/java/org/keycloak/social/AuthRequestBuilder.java 64(+0 -64)

social/core/src/main/java/org/keycloak/social/RequestDetailsBuilder.java 83(+0 -83)

testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthGrantServlet.java 111(+0 -111)

Details

diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/index.html b/admin-ui/src/main/resources/META-INF/resources/admin/index.html
index b953e92..9487218 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/index.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/index.html
@@ -5,12 +5,6 @@
     <meta charset="utf-8">
     <title>Keycloak</title>
 
-    <style type="text/css">
-        #idletimeout { background:#CC5100; border:3px solid #FF6500; color:#fff; font-family:arial, sans-serif; text-align:center; font-size:12px; padding:10px; position:relative; top:0px; left:0; right:0; z-index:100000; display:none; }
-        #idletimeout a { color:#fff; font-weight:bold }
-        #idletimeout span { font-weight:bold }
-    </style>
-
     <link rel="icon" href="/auth-server/admin-ui/img/favicon.ico">
 
     <!-- Frameworks -->
@@ -59,7 +53,7 @@
 
 <body class="admin-console" data-ng-controller="GlobalCtrl">
 <div id="idletimeout">
-    You will be logged off in <span></span>&nbsp;seconds due to inactivity.
+    You will be logged off in <strong><span></span> seconds</strong> due to inactivity.
     <a id="idletimeout-resume" href="#">Click here to continue using this web page</a>.
 </div>
 
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/app.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/app.js
index 4c8d2c2..7025d2e 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/app.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/app.js
@@ -4,29 +4,31 @@ var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders
 var resourceRequests = 0;
 
 module.config([ '$routeProvider', function($routeProvider) {
-	
-	$routeProvider
-
-	.when('/create/realm', {
-		templateUrl : 'partials/realm-detail.html',
-		resolve : {
-			realm : function(RealmLoader) {
-				return {};
-			}
-		},
-		controller : 'RealmDetailCtrl'
-	}).when('/realms/:realm', {
-		templateUrl : 'partials/realm-detail.html',
-		resolve : {
-			realm : function(RealmLoader) {
-				return RealmLoader();
-			}
-		},
-		controller : 'RealmDetailCtrl'
-	}).when('/realms', {
-		templateUrl : 'partials/realm-list.html',
-		controller : 'RealmListCtrl'
-	}).when('/realms/:realm/token-settings', {
+
+    $routeProvider
+        .when('/create/realm', {
+            templateUrl : 'partials/realm-detail.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return {};
+                }
+            },
+            controller : 'RealmDetailCtrl'
+        })
+        .when('/realms/:realm', {
+            templateUrl : 'partials/realm-detail.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                }
+            },
+            controller : 'RealmDetailCtrl'
+        })
+        .when('/realms', {
+            templateUrl : 'partials/realm-list.html',
+            controller : 'RealmListCtrl'
+        })
+        .when('/realms/:realm/token-settings', {
             templateUrl : 'partials/realm-tokens.html',
             resolve : {
                 realm : function(RealmLoader) {
@@ -34,7 +36,8 @@ module.config([ '$routeProvider', function($routeProvider) {
                 }
             },
             controller : 'RealmTokenDetailCtrl'
-        }).when('/realms/:realm/social-settings', {
+        })
+        .when('/realms/:realm/social-settings', {
             templateUrl : 'partials/realm-social.html',
             resolve : {
                 realm : function(RealmLoader) {
@@ -52,18 +55,28 @@ module.config([ '$routeProvider', function($routeProvider) {
             },
             controller : 'RealmRequiredCredentialsCtrl'
         })
-	.when('/create/user/:realm', {
-		templateUrl : 'partials/user-detail.html',
-		resolve : {
-			realm : function(RealmLoader) {
-				return RealmLoader();
-			},
-			user : function() {
-				return {};
-			}
-		},
-		controller : 'UserDetailCtrl'
-	}).when('/realms/:realm/users/:user', {
+        .when('/realms/:realm/smtp-settings', {
+            templateUrl : 'partials/realm-smtp.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                }
+            },
+            controller : 'RealmSMTPSettingsCtrl'
+        })
+        .when('/create/user/:realm', {
+            templateUrl : 'partials/user-detail.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                },
+                user : function() {
+                    return {};
+                }
+            },
+            controller : 'UserDetailCtrl'
+        })
+        .when('/realms/:realm/users/:user', {
             templateUrl : 'partials/user-detail.html',
             resolve : {
                 realm : function(RealmLoader) {
@@ -74,7 +87,8 @@ module.config([ '$routeProvider', function($routeProvider) {
                 }
             },
             controller : 'UserDetailCtrl'
-        }).when('/realms/:realm/users/:user/role-mappings', {
+        })
+        .when('/realms/:realm/users/:user/role-mappings', {
             templateUrl : 'partials/role-mappings.html',
             resolve : {
                 realm : function(RealmLoader) {
@@ -91,15 +105,16 @@ module.config([ '$routeProvider', function($routeProvider) {
                 }
             },
             controller : 'UserRoleMappingCtrl'
-        }).when('/realms/:realm/users', {
-		templateUrl : 'partials/user-list.html',
-		resolve : {
-			realm : function(RealmLoader) {
-				return RealmLoader();
-			}
-        },
-		controller : 'UserListCtrl'
-	})
+        })
+        .when('/realms/:realm/users', {
+            templateUrl : 'partials/user-list.html',
+            resolve : {
+                realm : function(RealmLoader) {
+                    return RealmLoader();
+                }
+            },
+            controller : 'UserListCtrl'
+        })
 
         .when('/create/role/:realm', {
             templateUrl : 'partials/role-detail.html',
@@ -112,7 +127,8 @@ module.config([ '$routeProvider', function($routeProvider) {
                 }
             },
             controller : 'RoleDetailCtrl'
-        }).when('/realms/:realm/roles/:role', {
+        })
+        .when('/realms/:realm/roles/:role', {
             templateUrl : 'partials/role-detail.html',
             resolve : {
                 realm : function(RealmLoader) {
@@ -123,7 +139,8 @@ module.config([ '$routeProvider', function($routeProvider) {
                 }
             },
             controller : 'RoleDetailCtrl'
-        }).when('/realms/:realm/roles', {
+        })
+        .when('/realms/:realm/roles', {
             templateUrl : 'partials/role-list.html',
             resolve : {
                 realm : function(RealmLoader) {
@@ -150,7 +167,8 @@ module.config([ '$routeProvider', function($routeProvider) {
                 }
             },
             controller : 'ApplicationRoleDetailCtrl'
-        }).when('/realms/:realm/applications/:application/roles/:role', {
+        })
+        .when('/realms/:realm/applications/:application/roles/:role', {
             templateUrl : 'partials/application-role-detail.html',
             resolve : {
                 realm : function(RealmLoader) {
@@ -164,7 +182,8 @@ module.config([ '$routeProvider', function($routeProvider) {
                 }
             },
             controller : 'ApplicationRoleDetailCtrl'
-        }).when('/realms/:realm/applications/:application/credentials', {
+        })
+        .when('/realms/:realm/applications/:application/credentials', {
             templateUrl : 'partials/application-credentials.html',
             resolve : {
                 realm : function(RealmLoader) {
@@ -175,7 +194,8 @@ module.config([ '$routeProvider', function($routeProvider) {
                 }
             },
             controller : 'ApplicationCredentialsCtrl'
-        }).when('/realms/:realm/applications/:application/roles', {
+        })
+        .when('/realms/:realm/applications/:application/roles', {
             templateUrl : 'partials/application-role-list.html',
             resolve : {
                 realm : function(RealmLoader) {
@@ -189,7 +209,8 @@ module.config([ '$routeProvider', function($routeProvider) {
                 }
             },
             controller : 'ApplicationRoleListCtrl'
-        }).when('/realms/:realm/applications/:application/scope-mappings', {
+        })
+        .when('/realms/:realm/applications/:application/scope-mappings', {
             templateUrl : 'partials/application-scope-mappings.html',
             resolve : {
                 realm : function(RealmLoader) {
@@ -208,8 +229,6 @@ module.config([ '$routeProvider', function($routeProvider) {
             controller : 'ApplicationScopeMappingCtrl'
         })
 
-
-
         .when('/create/application/:realm', {
             templateUrl : 'partials/application-detail.html',
             resolve : {
@@ -224,7 +243,8 @@ module.config([ '$routeProvider', function($routeProvider) {
                 }
             },
             controller : 'ApplicationDetailCtrl'
-        }).when('/realms/:realm/applications/:application', {
+        })
+        .when('/realms/:realm/applications/:application', {
             templateUrl : 'partials/application-detail.html',
             resolve : {
                 realm : function(RealmLoader) {
@@ -238,7 +258,8 @@ module.config([ '$routeProvider', function($routeProvider) {
                 }
             },
             controller : 'ApplicationDetailCtrl'
-        }).when('/realms/:realm/applications', {
+        })
+        .when('/realms/:realm/applications', {
             templateUrl : 'partials/application-list.html',
             resolve : {
                 realm : function(RealmLoader) {
@@ -250,33 +271,33 @@ module.config([ '$routeProvider', function($routeProvider) {
             },
             controller : 'ApplicationListCtrl'
         })
-	.otherwise({
-		templateUrl : 'partials/home.html'
-	});
+        .otherwise({
+            templateUrl : 'partials/home.html'
+        });
 } ]);
 
 module.config(function($httpProvider) {
-	$httpProvider.responseInterceptors.push('errorInterceptor');
+    $httpProvider.responseInterceptors.push('errorInterceptor');
 
-	var spinnerFunction = function(data, headersGetter) {
-		if (resourceRequests == 0) {
-			$('#loading').show();
-		}
-		resourceRequests++;
-		return data;
-	};
-	$httpProvider.defaults.transformRequest.push(spinnerFunction);
+    var spinnerFunction = function(data, headersGetter) {
+        if (resourceRequests == 0) {
+            $('#loading').show();
+        }
+        resourceRequests++;
+        return data;
+    };
+    $httpProvider.defaults.transformRequest.push(spinnerFunction);
 
-	$httpProvider.responseInterceptors.push('spinnerInterceptor');
+    $httpProvider.responseInterceptors.push('spinnerInterceptor');
 
 });
 
 module.factory('errorInterceptor', function($q, $window, $rootScope, $location, Auth) {
-	return function(promise) {
-		return promise.then(function(response) {
-			$rootScope.httpProviderError = null;
-			return response;
-		}, function(response) {
+    return function(promise) {
+        return promise.then(function(response) {
+            $rootScope.httpProviderError = null;
+            return response;
+        }, function(response) {
             if (response.status == 401) {
                 console.log('session timeout?');
                 Auth.loggedIn = false;
@@ -284,28 +305,28 @@ module.factory('errorInterceptor', function($q, $window, $rootScope, $location, 
             } else {
                 $rootScope.httpProviderError = response.status;
             }
-			return $q.reject(response);
-		});
-	};
+            return $q.reject(response);
+        });
+    };
 });
 
 module.factory('spinnerInterceptor', function($q, $window, $rootScope, $location) {
-	return function(promise) {
-		return promise.then(function(response) {
-			resourceRequests--;
-			if (resourceRequests == 0) {
-				$('#loading').hide();
-			}
-			return response;
-		}, function(response) {
-			resourceRequests--;
-			if (resourceRequests == 0) {
-				$('#loading').hide();
-			}
-
-			return $q.reject(response);
-		});
-	};
+    return function(promise) {
+        return promise.then(function(response) {
+            resourceRequests--;
+            if (resourceRequests == 0) {
+                $('#loading').hide();
+            }
+            return response;
+        }, function(response) {
+            resourceRequests--;
+            if (resourceRequests == 0) {
+                $('#loading').hide();
+            }
+
+            return $q.reject(response);
+        });
+    };
 });
 
 // collapsable form fieldsets
@@ -354,80 +375,80 @@ module.directive('collapsed', function() {
 
 
 module.directive('kcInput', function() {
-	var d = {
-		scope : true,
-		replace : false,
-		link : function(scope, element, attrs) {
-			var form = element.children('form');
-			var label = element.children('label');
-			var input = element.children('input');
-
-			var id = form.attr('name') + '.' + input.attr('name');
-
-			element.attr('class', 'control-group');
-
-			label.attr('class', 'control-label');
-			label.attr('for', id);
-
-			input.wrap('<div class="controls"/>');
-			input.attr('id', id);
-
-			if (!input.attr('placeHolder')) {
-				input.attr('placeHolder', label.text());
-			}
-
-			if (input.attr('required')) {
-				label.append(' <span class="required">*</span>');
-			}
-		}
-	};
-	return d;
+    var d = {
+        scope : true,
+        replace : false,
+        link : function(scope, element, attrs) {
+            var form = element.children('form');
+            var label = element.children('label');
+            var input = element.children('input');
+
+            var id = form.attr('name') + '.' + input.attr('name');
+
+            element.attr('class', 'control-group');
+
+            label.attr('class', 'control-label');
+            label.attr('for', id);
+
+            input.wrap('<div class="controls"/>');
+            input.attr('id', id);
+
+            if (!input.attr('placeHolder')) {
+                input.attr('placeHolder', label.text());
+            }
+
+            if (input.attr('required')) {
+                label.append(' <span class="required">*</span>');
+            }
+        }
+    };
+    return d;
 });
 
 module.directive('kcEnter', function() {
-	return function(scope, element, attrs) {
-		element.bind("keydown keypress", function(event) {
-			if (event.which === 13) {
-				scope.$apply(function() {
-					scope.$eval(attrs.kcEnter);
-				});
-
-				event.preventDefault();
-			}
-		});
-	};
+    return function(scope, element, attrs) {
+        element.bind("keydown keypress", function(event) {
+            if (event.which === 13) {
+                scope.$apply(function() {
+                    scope.$eval(attrs.kcEnter);
+                });
+
+                event.preventDefault();
+            }
+        });
+    };
 });
 
 
 module.filter('remove', function() {
-	return function(input, remove, attribute) {
-		if (!input || !remove) {
-			return input;
-		}
-
-		var out = [];
-		for ( var i = 0; i < input.length; i++) {
-			var e = input[i];
-
-			for (var j = 0; j < remove.length; j++) {
-				if (attribute) {
-					if (remove[j][attribute] == e[attribute]) {
-						e = null;
-						break;
-					}
-				} else {
-					if (remove[j] == e) {
-						e = null;
-						break;
-					}
-				}
-			}
-
-			if (e != null) {
-				out.push(e);
-			}
-		}
-
-		return out;
-	};
+    return function(input, remove, attribute) {
+        if (!input || !remove) {
+            return input;
+        }
+
+        var out = [];
+        for ( var i = 0; i < input.length; i++) {
+            var e = input[i];
+
+            for (var j = 0; j < remove.length; j++) {
+                if (attribute) {
+                    if (remove[j][attribute] == e[attribute]) {
+                        e = null;
+                        break;
+                    }
+                } else {
+                    if (remove[j] == e) {
+                        e = null;
+                        break;
+                    }
+                }
+            }
+
+            if (e != null) {
+                out.push(e);
+            }
+        }
+
+        return out;
+    };
 });
\ No newline at end of file
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js
index 1b4a4f5..fa11a54 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/controllers/realm.js
@@ -453,3 +453,38 @@ module.controller('RoleDetailCtrl', function($scope, realm, role, Role, $locatio
         });
     };
 });
+
+module.controller('RealmSMTPSettingsCtrl', function($scope, Current, Realm, realm, $http, $location, Dialog, Notifications) {
+    $scope.realm = {
+        id : realm.id, realm : realm.realm, social : realm.social,
+        smtpServer: realm.smtpServer
+    };
+
+    var oldCopy = angular.copy($scope.realm);
+    $scope.changed = false;
+
+    $scope.$watch('realm', function() {
+        if (!angular.equals($scope.realm, oldCopy)) {
+            $scope.changed = true;
+        }
+    }, true);
+
+    $scope.save = function() {
+        if ($scope.realmForm.$valid) {
+            var realmCopy = angular.copy($scope.realm);
+            $scope.changed = false;
+            Realm.update(realmCopy, function () {
+                $location.url("/realms/" + realm.id + "/smtp-settings");
+                Notifications.success("Your changes have been saved to the realm.");
+            });
+        } else {
+            $scope.realmForm.showErrors = true;
+        }
+    };
+
+    $scope.reset = function() {
+        $scope.realm = angular.copy(oldCopy);
+        $scope.changed = false;
+        $scope.realmForm.showErrors = false;
+    };
+});
\ No newline at end of file
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/js/services.js b/admin-ui/src/main/resources/META-INF/resources/admin/js/services.js
index 043e686..4ee4a90 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/js/services.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/js/services.js
@@ -16,15 +16,16 @@ module.service('Auth', function() {
 module.service('Dialog', function($dialog) {
 	var dialog = {};
 	dialog.confirmDelete = function(name, type, success) {
-		var title = 'Delete ' + name;
-		var msg = 'Are you sure you want to permanently delete this ' + type + '?';
+		var title = 'Delete ' + type.charAt(0).toUpperCase() + type.slice(1);
+		var msg = '<p class="primary">Are you sure you want to permanently delete the ' + type + ' "' + name + '"?</p>' +
+            '<p>This action can\'t be undone.</p>';
 		var btns = [ {
 			result : 'cancel',
 			label : 'Cancel'
 		}, {
 			result : 'ok',
-			label : 'Delete this ' + type,
-			cssClass : 'btn-primary'
+			label : 'Delete',
+			cssClass : 'destructive'
 		} ];
 
 		$dialog.messageBox(title, msg, btns).open().then(function(result) {
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/lib/angular/ui-bootstrap-tpls-0.4.0.js b/admin-ui/src/main/resources/META-INF/resources/admin/lib/angular/ui-bootstrap-tpls-0.4.0.js
index b587abd..9b62fe7 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/lib/angular/ui-bootstrap-tpls-0.4.0.js
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/lib/angular/ui-bootstrap-tpls-0.4.0.js
@@ -3004,10 +3004,10 @@ angular.module("template/dialog/message.html", []).run(["$templateCache", functi
     "	<h3>{{ title }}</h3>\n" +
     "</div>\n" +
     "<div class=\"modal-body\">\n" +
-    "	<p>{{ message }}</p>\n" +
+    "	<p ng-bind-html-unsafe=\"message\"></p>\n" +
     "</div>\n" +
     "<div class=\"modal-footer\">\n" +
-    "	<button ng-repeat=\"btn in buttons\" ng-click=\"close(btn.result)\" class=\"btn\" ng-class=\"btn.cssClass\">{{ btn.label }}</button>\n" +
+    "	<button ng-repeat=\"btn in buttons\" ng-click=\"close(btn.result)\" class=\"\" ng-class=\"btn.cssClass\">{{ btn.label }}</button> \n" +
     "</div>\n" +
     "</div>\n" +
     "</div>\n" +
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/menu.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/menu.html
index 4ae72a7..d62d21d 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/menu.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/menu.html
@@ -1,7 +1,7 @@
 <div class="header rcue">
     <div class="navbar utility">
         <div class="navbar-inner clearfix container">
-            <h1><a href="#"><strong>Keycloak</strong> Central Login</a></h1>
+            <h1><a href="#/realms/{{realm.id}}"><strong>Keycloak</strong> Central Login</a></h1>
             <ul class="nav pull-right" data-ng-hide="auth.loggedIn">
                 <li><a href="/auth-server/rest/saas/login">Login</a></li>
                 <li><a href="/auth-server/rest/saas/registrations">Register</a></li>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-credentials.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-credentials.html
index 1d4d9ff..0f9f849 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-credentials.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-credentials.html
@@ -9,6 +9,7 @@
                     <li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
                     <li class="active"><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
                     <li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
+                    <li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
                 </ul>
             </div>
             <div id="content">
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-detail.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-detail.html
index 1567a2f..d35d8cd 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-detail.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-detail.html
@@ -9,6 +9,7 @@
                     <li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
                     <li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
                     <li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
+                    <li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
                 </ul>
             </div>
             <div id="content">
@@ -76,6 +77,32 @@
                             </div>
                         </div>
                         <div class="form-group clearfix block">
+                            <label for="resetPasswordAllowed" class="control-label">Reset password</label>
+                            <div class="onoffswitch">
+                                <input type="checkbox" data-ng-model="realm.resetPasswordAllowed" class="onoffswitch-checkbox" name="resetPasswordAllowed" id="resetPasswordAllowed">
+                                <label for="resetPasswordAllowed" class="onoffswitch-label">
+                                            <span class="onoffswitch-inner">
+                                                <span class="onoffswitch-active">ON</span>
+                                                <span class="onoffswitch-inactive">OFF</span>
+                                            </span>
+                                    <span class="onoffswitch-switch"></span>
+                                </label>
+                            </div>
+                        </div>
+                        <div class="form-group clearfix block">
+                            <label for="verifyEmail" class="control-label">Verify email</label>
+                            <div class="onoffswitch">
+                                <input type="checkbox" data-ng-model="realm.verifyEmail" class="onoffswitch-checkbox" name="verifyEmail" id="verifyEmail">
+                                <label for="verifyEmail" class="onoffswitch-label">
+                                            <span class="onoffswitch-inner">
+                                                <span class="onoffswitch-active">ON</span>
+                                                <span class="onoffswitch-inactive">OFF</span>
+                                            </span>
+                                    <span class="onoffswitch-switch"></span>
+                                </label>
+                            </div>
+                        </div>
+                        <div class="form-group clearfix block">
                             <label for="accountManagement" class="control-label two-lines">User account management</label>
                             <div class="onoffswitch">
                                 <input type="checkbox" data-ng-model="realm.accountManagement" class="onoffswitch-checkbox"
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-smtp.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-smtp.html
new file mode 100755
index 0000000..6abd4ee
--- /dev/null
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-smtp.html
@@ -0,0 +1,134 @@
+<div id="wrapper" class="container">
+    <div class="row">
+        <div class="bs-sidebar col-md-3 clearfix" data-ng-include data-src="'partials/realm-menu.html'"></div>
+        <div id="content-area" class="col-md-9" role="main">
+            <div class="top-nav" data-ng-hide="createRealm">
+                <ul class="rcue-tabs">
+                    <li><a href="#/realms/{{realm.id}}">General</a></li>
+                    <li data-ng-show="realm.social"><a href="#/realms/{{realm.id}}/social-settings">Social</a></li>
+                    <li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
+                    <li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
+                    <li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
+                    <li class="active"><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
+                </ul>
+            </div>
+            <div id="content">
+                <ol class="breadcrumb">
+                    <li><a href="#/realms/{{realm.id}}">{{realm.realm}}</a></li>
+                    <li><a href="#/realms/{{realm.id}}">Settings</a></li>
+                    <li class="active">SMTP Configuration</li>
+                </ol>
+                <h2><span>{{realm.realm}}</span> SMTP Settings</h2>
+                <form name="realmForm" novalidate>
+                    <fieldset>
+                        <legend uncollapsed><span class="text">Required Settings</span></legend>
+                        <div class="form-group clearfix">
+                            <label for="smtpHost" class="control-label">Host <span class="required">*</span></label>
+                            <div class="controls">
+                                <input id="smtpHost" type="text" ng-model="realm.smtpServer.host" placeholder="SMTP Host" required>
+                            </div>
+                        </div>
+                        <div class="form-group clearfix">
+                            <label for="smtpPort" class="control-label">Port <span class="required">*</span></label>
+                            <div class="controls">
+                                <input id="smtpPort" type="text" ng-model="realm.smtpServer.port" placeholder="SMTP Port (defaults to 25)" required>
+                            </div>
+                        </div>
+                        <div class="form-group clearfix">
+                            <label for="smtpFrom" class="control-label">From <span class="required">*</span></label>
+                            <div class="controls">
+                                <input id="smtpFrom" type="email" ng-model="realm.smtpServer.from" placeholder="SMTP From" required>
+                            </div>
+                        </div>
+                        <div class="form-group clearfix">
+                            <label for="smtpSSL" class="control-label">Enable SSL</label>
+                            <div class="onoffswitch">
+                                <input type="checkbox" data-ng-model="realm.smtpServer.ssl" class="onoffswitch-checkbox" name="smtpSSL" id="smtpSSL">
+                                <label for="smtpSSL" class="onoffswitch-label">
+                                        <span class="onoffswitch-inner">
+                                            <span class="onoffswitch-active">ON</span>
+                                            <span class="onoffswitch-inactive">OFF</span>
+                                        </span>
+                                    <span class="onoffswitch-switch"></span>
+                                </label>
+                            </div>
+                        </div>
+                        <div class="form-group clearfix">
+                            <label for="smtpStartTLS" class="control-label">Enable StartTLS</label>
+                            <div class="onoffswitch">
+                                <input type="checkbox" data-ng-model="realm.smtpServer.starttls" class="onoffswitch-checkbox" name="smtpStartTLS" id="smtpStartTLS">
+                                <label for="smtpStartTLS" class="onoffswitch-label">
+                                        <span class="onoffswitch-inner">
+                                            <span class="onoffswitch-active">ON</span>
+                                            <span class="onoffswitch-inactive">OFF</span>
+                                        </span>
+                                    <span class="onoffswitch-switch"></span>
+                                </label>
+                            </div>
+                        </div>
+                    </fieldset>
+                    <fieldset>
+                        <legend collapsed><span class="text">Authentication</span></legend>
+                        <div class="form-group clearfix">
+                            <label for="smtpAuth" class="control-label">Enabled</label>
+                            <div class="onoffswitch">
+                                <input type="checkbox" data-ng-model="realm.smtpServer.auth" class="onoffswitch-checkbox" name="smtpAuth" id="smtpAuth">
+                                <label for="smtpAuth" class="onoffswitch-label">
+                                        <span class="onoffswitch-inner">
+                                            <span class="onoffswitch-active">ON</span>
+                                            <span class="onoffswitch-inactive">OFF</span>
+                                        </span>
+                                    <span class="onoffswitch-switch"></span>
+                                </label>
+                            </div>
+                        </div>
+                        <div class="form-group clearfix">
+                            <label for="smtpUsername" class="control-label">Username <span class="required" ng-show="realm.smtpServer.auth">*</span></label>
+                            <div class="controls">
+                                <input id="smtpUsername" type="text" ng-model="realm.smtpServer.user" placeholder="Login Username" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
+                            </div>
+                        </div>
+                        <div class="form-group clearfix">
+                            <label for="smtpPassword" class="control-label">Password <span class="required" ng-show="realm.smtpServer.auth">*</span></label>
+                            <div class="controls">
+                                <input id="smtpPassword" type="password" ng-model="realm.smtpServer.password" placeholder="Login Password" ng-disabled="!realm.smtpServer.auth" ng-required="realm.smtpServer.auth">
+                            </div>
+                        </div>
+                    </fieldset>
+<!--
+                    <fieldset class="border-top">
+                        <div class="form-group clearfix" ng-repeat="(name, setting) in smtpSettings | orderBy: setting.required">
+                            <label for="{{name}}" class="control-label">{{name.replace('mail.smtp.','')}} <span class="required" data-ng-show="setting.required">*</span></label>
+
+                            <div ng-show="setting.type == 'boolean'" class="onoffswitch">
+                                <input type="checkbox" data-ng-model="realm.smtp[name]" class="onoffswitch-checkbox" name="{{name}}" id="{{name}}">
+                                <label for="{{name}}" class="onoffswitch-label">
+                                        <span class="onoffswitch-inner">
+                                            <span class="onoffswitch-active">ON</span>
+                                            <span class="onoffswitch-inactive">OFF</span>
+                                        </span>
+                                    <span class="onoffswitch-switch"></span>
+                                </label>
+                            </div>
+                            <div ng-show="setting.type == 'String'" class="controls">
+                                <input id="{{name}}" type="text" ng-model="realm.smtp[name]" placeholder="SMTP {{name}} / {{ setting.required }}">
+                            </div>
+                            <div ng-show="setting.type == 'int'" class="controls">
+                                <input id="{{name}}" type="number" ng-model="realm.smtp[name]" placeholder="SMTP {{name}} / {{ setting.required }}">
+                            </div>
+                        </div>
+                    </fieldset>
+-->
+                   <div class="form-actions">
+                        <button type="submit" data-ng-click="save()" class="primary" data-ng-show="changed">Save
+                        </button>
+                        <button type="submit" data-ng-click="reset()" data-ng-show="changed">Clear changes
+                        </button>
+                    </div>
+
+                </form>
+            </div>
+        </div>
+        <div id="container-right-bg"></div>
+    </div>
+</div>
\ No newline at end of file
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-social.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-social.html
index a102740..a046cc5 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-social.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-social.html
@@ -9,6 +9,7 @@
                     <li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
                     <li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
                     <li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
+                    <li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
                 </ul>
             </div>
             <div id="content">
@@ -92,7 +93,7 @@
                 <div ng-include src="'partials/provider/'+ helpPId +'-help.html'"></div>
             </div>
             <div class="modal-footer">
-                <button class="btn" ng-click="closeHelp()">Close</button>
+                <button ng-click="closeHelp()">Close</button>
             </div>
         </div>
     </div>
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-tokens.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-tokens.html
index b87cf6d..4092a90 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-tokens.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/realm-tokens.html
@@ -9,6 +9,7 @@
                     <li><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
                     <li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
                     <li class="active"><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
+                    <li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
                 </ul>
             </div>
             <div id="content">
@@ -49,7 +50,7 @@
                             </div>
                         </div>
                         <div class="form-group input-select">
-                            <label for="accessCodeLifespanUserAction">Access code user action lifespan</label>
+                            <label for="accessCodeLifespanUserAction" class="two-lines">Access code user action lifespan</label>
                             <div class="input-group">
                                 <input type="text" data-ng-model="realm.accessCodeLifespanUserAction" id="accessCodeLifespanUserAction" name="accessCodeLifespanUserAction" class="tiny">
                                 <div class="select-rcue">
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-detail.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-detail.html
index 78eeda7..e9ee0c0 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-detail.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-detail.html
@@ -9,6 +9,7 @@
                     <li class="active"><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
                     <li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
                     <li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
+                    <li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
                 </ul>
             </div>
             <div id="content">
diff --git a/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-list.html b/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-list.html
index 69fbdcd..b1ae532 100755
--- a/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-list.html
+++ b/admin-ui/src/main/resources/META-INF/resources/admin/partials/role-list.html
@@ -9,6 +9,7 @@
                     <li class="active"><a href="#/realms/{{realm.id}}/roles">Roles</a></li>
                     <li><a href="#/realms/{{realm.id}}/required-credentials">Credentials</a></li>
                     <li><a href="#/realms/{{realm.id}}/token-settings">Token</a></li>
+                    <li><a href="#/realms/{{realm.id}}/smtp-settings">SMTP</a></li>
                 </ul>
             </div>
             <div id="content">
diff --git a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.css b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.css
index c339f2f..bf52b71 100644
--- a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.css
+++ b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.css
@@ -43,7 +43,34 @@ body {
   background-image: url(img/feedback-info-sign.png);
   background-color: #e4f3fa;
 }
+#idletimeout {
+  background: #CC5100;
+  color: #FFFFFF;
+  font-size: 1.1em;
+  padding: 0.90909090909091em;
+  text-align: center;
+  display: none;
+}
+#idletimeout a {
+  color: #fff;
+  font-weight: bold;
+}
+.loading span {
+  background: url(img/loader.gif) no-repeat center top;
+  position: fixed;
+  z-index: 1000;
+  top: 50%;
+  left: 50%;
+  margin-top: -2.27272727272727em;
+  margin-left: -2.27272727272727em;
+  padding-top: 2.90909090909091em;
+  font-size: 1.1em;
+  color: #666;
+}
 /* Header */
+.header.rcue {
+  z-index: 50;
+}
 .header.rcue .navbar.utility {
   background-color: #393F45;
   border-bottom: 1px solid #53565B;
@@ -65,36 +92,6 @@ body {
   min-height: 42px;
   max-width: 1170px;
 }
-.header.rcue .navbar.primary .select-rcue {
-  font-size: 0.76923076923077em;
-  margin-left: 1em;
-  margin-top: 0.7em;
-  display: inline-block;
-  vertical-align: middle;
-  background-color: #555a5e;
-  background-image: none;
-  background-image: url(img/sprite-arrow-down.png);
-  background-repeat: no-repeat;
-  background-position: right -26px;
-  border: 1px solid #676c6e;
-  border-radius: 2px;
-  padding-left: 0;
-}
-.header.rcue .navbar.primary .select-rcue:hover {
-  border-color: #7e8385;
-}
-.header.rcue .navbar.primary .select-rcue select {
-  color: #fff;
-}
-.header.rcue .navbar.primary .select-rcue select:-moz-focusring {
-  color: transparent;
-  text-shadow: 0 0 0 #fff;
-}
-.header.rcue .navbar.primary .select-rcue select option {
-  background-color: #fff;
-  color: #333;
-  padding: 0.36363636363636em 0.90909090909091em;
-}
 .header.rcue .navbar.primary .nav > li {
   /*
             .dropdown { 
@@ -215,7 +212,6 @@ body {
 .header.rcue .navbar.primary .nav > li .select-rcue select option {
   background-color: #fff;
   color: #333;
-  padding: 0.36363636363636em 0.90909090909091em;
 }
 .header.rcue .navbar.primary .nav > li a#refresh {
   border: none;
@@ -469,6 +465,42 @@ table + .feedback.inline.warning {
 td.token-cell button {
   margin-top: -1px;
 }
+/* Modal boxes */
+.modal .modal-dialog {
+  padding-top: 10em;
+}
+.modal .modal-content {
+  box-shadow: none;
+  border-radius: 0;
+  border: 1px solid #666;
+}
+.modal .modal-header {
+  background-color: #f8f8f8;
+  padding: 1.5em 2em;
+  border-bottom: none;
+}
+.modal .modal-header h3 {
+  font-size: 1.3em;
+  font-weight: bold;
+  font-family: "Open Sans", sans-serif;
+  margin: 0;
+}
+.modal .modal-body p {
+  font-size: 1.1em;
+}
+.modal .modal-body p.primary {
+  font-size: 1.1em;
+  font-weight: bold;
+  margin-bottom: 0.45454545454545em;
+}
+.modal .modal-footer {
+  border-top: 0;
+}
+.modal .modal-footer .primary,
+.modal .modal-footer .destructive {
+  float: right;
+  margin-left: 0.90909090909091em;
+}
 /* Page: User Account */
 .user form fieldset div:first-child {
   margin-top: 1em;
diff --git a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.less b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.less
index 4cca051..7ef77be 100644
--- a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.less
+++ b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/admin-console.less
@@ -60,11 +60,43 @@ body {
     }
 }
 
+#idletimeout {
+    background: #CC5100;
+    color: #FFFFFF;
+    font-size: 1.1em;
+    padding: 0.90909090909091em;
+    text-align: center;
+    display: none;
+    
+    a {
+        color: #fff;
+        font-weight: bold;
+    }
+}
+
+.loading {
+    
+    span {
+        background: url(img/loader.gif) no-repeat center top;
+        position: fixed;
+        z-index: 1000;
+        top: 50%;
+        left: 50%;
+        margin-top: -2.27272727272727em;
+        margin-left: -2.27272727272727em;
+        padding-top: 2.90909090909091em;
+        font-size: 1.1em;
+        color: #666;
+    }
+}
+
 
 /* Header */
 
 .header.rcue {
 
+    z-index: 50;
+
     .navbar.utility {
         background-color: #393F45;
         border-bottom: 1px solid #53565B;
@@ -88,41 +120,6 @@ body {
             min-height: 42px;
             max-width: 1170px;
         }
-
-        .select-rcue {
-            font-size: 0.76923076923077em;
-            margin-left: 1em;
-            margin-top: 0.7em;
-            display: inline-block;
-            vertical-align: middle;
-            background-color: #555a5e;
-            background-image: none;
-            background-image: url(img/sprite-arrow-down.png);
-            background-repeat: no-repeat;
-            background-position: right -26px;
-            border: 1px solid #676c6e;
-            border-radius: 2px;
-            padding-left: 0;
-            
-            &:hover {
-                border-color: #7e8385;
-            }
-            
-            select {
-                color: #fff;
-                
-                &:-moz-focusring {
-                    color: transparent;
-                    text-shadow: 0 0 0 #fff;
-                }
-                
-                option {
-                    background-color: #fff;
-                    color: #333;
-                    padding: 0.36363636363636em 0.90909090909091em;
-                }
-            }
-        }
         
         .nav > li {
         
@@ -165,7 +162,6 @@ body {
                     option {
                         background-color: #fff;
                         color: #333;
-                        padding: 0.36363636363636em 0.90909090909091em;
                     }
                 }
             }
@@ -567,6 +563,59 @@ td.token-cell button {
 }
 
 
+/* Modal boxes */
+
+.modal {
+    
+    .modal-dialog {
+        padding-top: 10em;
+    }
+    
+    .modal-content {
+        box-shadow: none;
+        border-radius: 0;
+        border: 1px solid #666;
+    }
+    
+    .modal-header {
+        background-color: #f8f8f8;
+        padding: 1.5em 2em;
+        border-bottom: none;
+        
+        h3 {
+            font-size: 1.3em;
+            font-weight: bold;
+            font-family: @open-sans;
+            margin: 0;
+        }
+    }
+    
+    .modal-body {
+        
+        p {
+            font-size: 1.1em;
+            
+            &.primary {
+                font-size: 1.1em;
+                font-weight: bold;
+                margin-bottom: 0.45454545454545em;
+            }
+        }
+    }
+    
+    .modal-footer {
+        border-top: 0;
+        
+        .primary,
+        .destructive {
+            float: right;
+            margin-left: 0.90909090909091em;
+        }
+        
+    }
+}
+
+
 /* Page: User Account */
 
 .user {
diff --git a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/forms.css b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/forms.css
index 8d99830..d83a677 100644
--- a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/forms.css
+++ b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/forms.css
@@ -16,12 +16,14 @@ input[type="email"],
 textarea {
   font-size: 1.1em;
   padding: 0 0.545454545454545em;
-  min-width: 18.1818181818182em;
   height: 2.36363636363636em;
+  /* 26px */
+
   border: 1px #b6b6b6 solid;
   border-radius: 2px;
   box-shadow: inset 0px 2px 2px rgba(0, 0, 0, 0.1);
   color: #333;
+  width: 18.1818em;
 }
 input[type="text"]:hover,
 input[type="password"]:hover,
@@ -51,6 +53,36 @@ input[type="email"].error:focus,
 textarea.error:focus {
   box-shadow: 0 0 5px #ba1212;
 }
+input[type="text"].tiny,
+input[type="password"].tiny,
+input[type="email"].tiny,
+textarea.tiny {
+  width: 4.54545454545455em;
+}
+input[type="text"].small,
+input[type="password"].small,
+input[type="email"].small,
+textarea.small {
+  width: 9.09090909090909em;
+}
+input[type="text"].medium,
+input[type="password"].medium,
+input[type="email"].medium,
+textarea.medium {
+  width: 18.1818em;
+}
+input[type="text"].large,
+input[type="password"].large,
+input[type="email"].large,
+textarea.large {
+  width: 27.2727272727273em;
+}
+input[type="text"].xlarge,
+input[type="password"].xlarge,
+input[type="email"].xlarge,
+textarea.xlarge {
+  width: 36.3636363636364em;
+}
 textarea {
   padding: 0.45em 0.545454545454545em;
   height: auto;
@@ -252,7 +284,7 @@ button.primary:focus,
 .search-comp .icon-search {
   position: absolute;
   right: 0.2em;
-  top: 0.4em;
+  top: 0.6em;
   opacity: 0.5;
   filter: alpha(opacity=50);
 }
@@ -457,6 +489,8 @@ fieldset.border-top {
 .form-group .required {
   font-size: 1.1em;
   color: #CB2915;
+  display: inline-block;
+  margin-top: -0.09090909090909em;
 }
 legend + .form-group {
   padding-top: 1em;
@@ -550,7 +584,7 @@ input[type="email"].tiny {
 }
 .select-rcue,
 .select2-container .select2-choice {
-  height: 26px;
+  height: 2.6em;
   border: 1px #b6b6b6 solid;
   border-radius: 2px;
   box-shadow: inset 0px 2px 2px rgba(0, 0, 0, 0.1);
@@ -593,7 +627,7 @@ input[type="email"].tiny {
 }
 .select-rcue option {
   line-height: 2em;
-  padding-left: 0.90909090909091em;
+  padding: 0.363636em 0.909091em;
 }
 .select-rcue option:hover {
   background-color: #d5ecf9;
@@ -788,7 +822,8 @@ input[type="email"].tiny {
   margin-top: 3em;
   margin-bottom: 5em;
 }
-.form-actions .primary {
+.form-actions .primary,
+.form-actions .destructive {
   float: right;
   margin-left: 0.90909090909091em;
 }
diff --git a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/forms.less b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/forms.less
index c965f0e..5fc4c0b 100644
--- a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/forms.less
+++ b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/forms.less
@@ -23,12 +23,12 @@ input[type="email"],
 textarea {
     font-size: 1.1em;
     padding: 0 0.545454545454545em;
-    min-width: 18.1818181818182em;
-    height: 2.36363636363636em;
+    height: 2.36363636363636em; /* 26px */
     border: 1px #b6b6b6 solid;
     border-radius: 2px;
     box-shadow: inset 0px 2px 2px rgba(0,0,0,0.1);
     color: #333;
+    width: 18.1818em;
     
     &:hover {
         border-color: #62afdb;
@@ -49,6 +49,26 @@ textarea {
             box-shadow: 0 0 5px #ba1212;
         }
     }
+    
+    &.tiny {
+        width: 4.54545454545455em;
+    }
+    
+    &.small {
+        width: 9.09090909090909em;
+    }
+    
+    &.medium {
+        width: 18.1818em;
+    }
+    
+    &.large {
+        width: 27.2727272727273em;
+    }
+    
+    &.xlarge {
+        width: 36.3636363636364em
+    }
 }
 
 textarea {
@@ -280,7 +300,7 @@ button.primary,
     .icon-search {
         position: absolute;
         right: 0.2em;
-        top: 0.4em;
+        top: 0.6em;
         opacity: 0.5;
         filter: alpha(opacity=50);
         
@@ -532,6 +552,8 @@ fieldset.border-top {
     .required {
         font-size: 1.1em;
         color: #CB2915;
+        display: inline-block;
+        margin-top: -0.09090909090909em;
     }
 }
 
@@ -656,7 +678,7 @@ input[type="email"] {
 
 .select-rcue,
 .select2-container .select2-choice {
-    height: 26px;
+    height: 2.6em;
     border: 1px #b6b6b6 solid;
     border-radius: 2px;
     box-shadow: inset 0px 2px 2px rgba(0,0,0,0.1);
@@ -707,7 +729,7 @@ input[type="email"] {
     
     option {
         line-height: 2em;
-        padding-left: 0.90909090909091em;
+        padding: 0.363636em 0.909091em;
         
         &:hover {
             background-color: #d5ecf9;
@@ -940,7 +962,8 @@ input[type="email"] {
     margin-top: 3em;
     margin-bottom: 5em;
     
-    .primary {
+    .primary,
+    .destructive {
         float: right;
         margin-left: 0.90909090909091em;
     }
diff --git a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/img/loader.gif b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/img/loader.gif
new file mode 100644
index 0000000..06ef39f
Binary files /dev/null and b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/img/loader.gif differ
diff --git a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/img/login-register-social.png b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/img/login-register-social.png
new file mode 100644
index 0000000..e86d738
Binary files /dev/null and b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/img/login-register-social.png differ
diff --git a/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/img/login-register-social.svg b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/img/login-register-social.svg
new file mode 100644
index 0000000..d28ebcc
--- /dev/null
+++ b/admin-ui-styles/src/main/resources/META-INF/resources/admin-ui/css/img/login-register-social.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="12px" height="400px" viewBox="0 0 12 400" enable-background="new 0 0 12 400" xml:space="preserve">
+<rect x="6.001" opacity="0.07" fill="#FFFFFF" enable-background="new    " width="0.997" height="190"/>
+<rect x="6" y="209" opacity="0.07" fill="#FFFFFF" enable-background="new    " width="1" height="191"/>
+<g opacity="0.15">
+	<path fill="#FFFFFF" d="M6.501,200.066c0,1.047-0.264,1.864-0.791,2.452S4.454,203.4,3.524,203.4c-0.574,0-1.084-0.135-1.529-0.404
+		c-0.445-0.27-0.789-0.656-1.031-1.16c-0.242-0.504-0.363-1.094-0.363-1.77c0-1.047,0.262-1.862,0.785-2.446
+		c0.523-0.584,1.25-0.876,2.18-0.876c0.898,0,1.612,0.299,2.142,0.896C6.238,198.237,6.501,199.047,6.501,200.066z M1.608,200.066
+		c0,0.821,0.164,1.446,0.492,1.875s0.811,0.645,1.447,0.645c0.636,0,1.12-0.214,1.45-0.643c0.33-0.428,0.495-1.053,0.495-1.877
+		c0-0.816-0.165-1.437-0.495-1.86s-0.817-0.636-1.462-0.636c-0.637,0-1.117,0.209-1.441,0.627
+		C1.77,198.615,1.608,199.238,1.608,200.066z"/>
+	<path fill="#FFFFFF" d="M11.136,196.744c0.285,0,0.541,0.023,0.768,0.07l-0.135,0.902c-0.266-0.059-0.5-0.088-0.703-0.088
+		c-0.52,0-0.964,0.211-1.333,0.633c-0.369,0.422-0.554,0.947-0.554,1.576v3.445H8.206v-6.422h0.803l0.111,1.189h0.047
+		c0.238-0.418,0.525-0.74,0.861-0.967C10.364,196.855,10.733,196.744,11.136,196.744z"/>
+</g>
+</svg>
diff --git a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
index 878092e..59347ca 100755
--- a/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/ApplicationRepresentation.java
@@ -18,6 +18,7 @@ public class ApplicationRepresentation {
     protected boolean enabled;
     protected List<CredentialRepresentation> credentials;
     protected List<RoleRepresentation> roles;
+    protected String[] defaultRoles;
     protected List<UserRoleMappingRepresentation> roleMappings;
     protected List<ScopeMappingRepresentation> scopeMappings;
     protected List<String> redirectUris;
@@ -164,4 +165,12 @@ public class ApplicationRepresentation {
     public void setWebOrigins(List<String> webOrigins) {
         this.webOrigins = webOrigins;
     }
+
+    public String[] getDefaultRoles() {
+        return defaultRoles;
+    }
+
+    public void setDefaultRoles(String[] defaultRoles) {
+        this.defaultRoles = defaultRoles;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
index 65281dc..c520fd3 100755
--- a/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/RealmRepresentation.java
@@ -28,7 +28,7 @@ public class RealmRepresentation {
     protected String privateKey;
     protected String publicKey;
     protected List<RoleRepresentation> roles;
-    protected String[] defaultRoles;
+    protected List<String> defaultRoles;
     protected Set<String> requiredCredentials;
     protected Set<String> requiredApplicationCredentials;
     protected Set<String> requiredOAuthClientCredentials;
@@ -220,11 +220,11 @@ public class RealmRepresentation {
         this.roles = roles;
     }
 
-    public String[] getDefaultRoles() {
+    public List<String> getDefaultRoles() {
         return defaultRoles;
     }
 
-    public void setDefaultRoles(String[] defaultRoles) {
+    public void setDefaultRoles(List<String> defaultRoles) {
         this.defaultRoles = defaultRoles;
     }
 

dist/assembly.xml 50(+50 -0)

diff --git a/dist/assembly.xml b/dist/assembly.xml
new file mode 100644
index 0000000..4c892d1
--- /dev/null
+++ b/dist/assembly.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly xmlns="urn:maven:assembly:1.1.0-SNAPSHOT">
+    <id>distro</id>
+
+    <formats>
+        <format>zip</format>
+        <format>tar.gz</format>
+    </formats>
+
+    <includeBaseDirectory>false</includeBaseDirectory>
+
+    <fileSets>
+        <fileSet>
+            <directory>${build.target.dir}</directory>
+            <outputDirectory>keycloak-${project.version}</outputDirectory>
+            <excludes>
+                <exclude>**/*.sh</exclude>
+                <exclude>domain/tmp/auth</exclude>
+                <exclude>domain/tmp/auth</exclude>
+                <exclude>**/*-users.properties</exclude>
+            </excludes>
+        </fileSet>
+        <fileSet>
+            <directory>${build.target.dir}</directory>
+            <outputDirectory>keycloak-${project.version}</outputDirectory>
+            <includes>
+                <include>**/*.sh</include>
+            </includes>
+            <fileMode>0755</fileMode>
+        </fileSet>
+        <fileSet>
+            <directory>${build.target.dir}</directory>
+            <outputDirectory>keycloak-${project.version}</outputDirectory>
+            <includes>
+                <include>**/*-users.properties</include>
+            </includes>
+            <fileMode>0600</fileMode>
+        </fileSet>
+        <fileSet>
+            <directory>${build.target.dir}</directory>
+            <outputDirectory>keycloak-${project.version}</outputDirectory>
+            <includes>
+                <include>domain/tmp/auth</include>
+                <include>standalone/tmp/auth</include>
+            </includes>
+            <directoryMode>0700</directoryMode>
+        </fileSet>
+    </fileSets>
+
+</assembly>

dist/build.xml 37(+37 -0)

diff --git a/dist/build.xml b/dist/build.xml
new file mode 100644
index 0000000..c9bfd95
--- /dev/null
+++ b/dist/build.xml
@@ -0,0 +1,37 @@
+<project name="keycloak-dist" basedir=".">
+    <target name="jboss">
+        <unzip src="${org.jboss.as:jboss-as-dist:zip}" dest="${project.build.directory}"/>
+        <chmod perm="755">
+            <fileset dir="${project.build.directory}/jboss-as-${jboss.version}/bin">
+                <include name="**/*.sh"/>
+            </fileset>
+        </chmod>
+        <move todir="${build.target.dir}" overwrite="true">
+            <fileset dir="${project.build.directory}/jboss-as-${jboss.version}">
+                <include name="**/*"/>
+            </fileset>
+        </move>
+        <delete dir="${project.build.directory}/jboss-as-${jboss.version}"/>
+    </target>
+
+    <target name="resteasy-modules">
+        <get src="http://sourceforge.net/projects/resteasy/files/Resteasy%20JAX-RS/${resteasy.version}/resteasy-jaxrs-${resteasy.version}-all.zip"
+             dest="${project.build.directory}" skipexisting="true"/>
+        <unzip src="${project.build.directory}/resteasy-jaxrs-${resteasy.version}-all.zip"
+               dest="${project.build.directory}">
+            <patternset>
+                <include name="resteasy-jaxrs-${resteasy.version}/resteasy-jboss-modules-${resteasy.version}.zip"/>
+            </patternset>
+            <mapper type="flatten"/>
+        </unzip>
+        <unzip src="${project.build.directory}/resteasy-jboss-modules-${resteasy.version}.zip"
+               dest="${build.target.dir}/modules"/>
+    </target>
+
+    <target name="keycloak-server">
+        <copy file="${org.keycloak:keycloak-server:war}"
+              tofile="${build.target.dir}/standalone/deployments/auth-server.war" overwrite="true"/>
+    </target>
+
+    <target name="all" depends="jboss, resteasy-modules, keycloak-server"/>
+</project>

dist/pom.xml 96(+96 -0)

diff --git a/dist/pom.xml b/dist/pom.xml
new file mode 100644
index 0000000..ef0ff99
--- /dev/null
+++ b/dist/pom.xml
@@ -0,0 +1,96 @@
+<?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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.keycloak</groupId>
+        <artifactId>keycloak-parent</artifactId>
+        <version>1.0-alpha-1</version>
+    </parent>
+
+    <artifactId>keycloak-dist</artifactId>
+    <name>Keycloak Dist</name>
+    <packaging>pom</packaging>
+
+    <properties>
+        <build.target.dir>${project.build.directory}/keycloak-${project.version}</build.target.dir>
+    </properties>
+
+    <profiles>
+        <profile>
+            <id>release</id>
+            <activation>
+                <property>
+                    <name>release</name>
+                    <value>true</value>
+                </property>
+            </activation>
+
+            <dependencies>
+                <dependency>
+                    <groupId>org.keycloak</groupId>
+                    <artifactId>keycloak-server</artifactId>
+                    <version>1.0-alpha-1</version>
+                    <type>war</type>
+                </dependency>
+                <dependency>
+                    <groupId>org.jboss.as</groupId>
+                    <artifactId>jboss-as-dist</artifactId>
+                    <version>${jboss.version}</version>
+                    <type>zip</type>
+                </dependency>
+            </dependencies>
+
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-antrun-plugin</artifactId>
+                        <version>1.7</version>
+                        <executions>
+                            <execution>
+                                <id>build</id>
+                                <phase>compile</phase>
+                                <configuration>
+                                    <target>
+                                        <ant antfile="build.xml" inheritRefs="false">
+                                            <target name="all"/>
+                                        </ant>
+                                    </target>
+                                </configuration>
+                                <goals>
+                                    <goal>run</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>assemble</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>single</goal>
+                                </goals>
+                                <configuration>
+                                    <descriptors>
+                                        <descriptor>assembly.xml</descriptor>
+                                    </descriptors>
+                                    <finalName>keycloak-${project.version}</finalName>
+                                    <appendAssemblyId>false</appendAssemblyId>
+                                    <outputDirectory>target/</outputDirectory>
+                                    <workDirectory>target/assembly/work</workDirectory>
+                                    <tarLongFileMode>gnu</tarLongFileMode>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-separator.png b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-separator.png
index 5ea210c..d626a45 100644
Binary files a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-separator.png and b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-separator.png differ
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-social.png b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-social.png
new file mode 100644
index 0000000..e86d738
Binary files /dev/null and b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-social.png differ
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-social-separator.png b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-social-separator.png
new file mode 100644
index 0000000..3f08929
Binary files /dev/null and b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/img/login-register-social-separator.png differ
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css
index 8fa9b44..bc25029 100644
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/css/login-register.css
@@ -49,13 +49,30 @@ body {
   width: 100%;
   min-width: 120em;
 }
+.rcue-login-register .form-area.separator,
+.rcue-login-register .form-area.social,
+.rcue-login-register .form-area.social.separator {
+  background-repeat: no-repeat;
+  background-position: 42.7em center;
+}
+.rcue-login-register .form-area.separator {
+  background-image: url(img/login-register-separator.png);
+  background-position: 43.2em center;
+}
+.rcue-login-register .form-area.social {
+  background-image: url(img/login-register-social.png);
+}
+.rcue-login-register .form-area.social.separator {
+  background-image: url(img/login-register-social-separator.png);
+}
 .rcue-login-register .background-area .section {
   float: left;
   padding: 0 4.5em 0 4.6em;
   width: auto;
   position: relative;
 }
-.rcue-login-register .background-area .separator .section {
+.rcue-login-register .background-area .separator .section,
+.rcue-login-register .background-area .social .section {
   padding-top: 1.5em;
   padding-bottom: 1.5em;
 }
@@ -65,15 +82,6 @@ body {
 .rcue-login-register .background-area .section:first-child {
   padding-right: 4.5em;
 }
-.rcue-login-register .form-area.separator {
-  background-image: url(img/login-register-separator.png);
-  background-repeat: no-repeat;
-  background-position: 43.2em center;
-}
-.rcue-login-register .form-area.social {
-  background-image: url(img/login-register-social-separators.png);
-  background-position: 39.6em center;
-}
 .rcue-login-register .section > p {
   font-size: 1.3em;
   margin-bottom: 1.53846153846154em;
@@ -120,7 +128,6 @@ body {
 .rcue-login-register form > div.aside-btn input[type="checkbox"] {
   margin-bottom: 0.54545454545455em;
   /* 6px */
-
 }
 .rcue-login-register form > input[type="button"],
 .rcue-login-register form > input[type="submit"]{
@@ -137,13 +144,10 @@ body {
   top: -0.636363636363636em;
 }
 .rcue-login-register .feedback.bottom-left {
-  left: 32.7em;
+  left: 35.7em;
   top: -9.2em;
   min-width: 35em;
 }
-.rcue-login-register.reset .feedback.bottom-left {
-  left: 35.7em;  
-}
 .rcue-login-register input.error[type="text"],
 .rcue-login-register input.error[type="password"],
 .rcue-login-register input.error[type="email"] {
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/login.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/login.ftl
index 2b24b4c..be4c793 100755
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/login.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/login.ftl
@@ -39,4 +39,4 @@
     </div>
 
     </#if>
-</@layout.registrationLayout>
\ No newline at end of file
+</@layout.registrationLayout>
diff --git a/forms/src/main/resources/META-INF/resources/forms/theme/default/login-oauth-grant.ftl b/forms/src/main/resources/META-INF/resources/forms/theme/default/login-oauth-grant.ftl
index edc7ef7..85121de 100755
--- a/forms/src/main/resources/META-INF/resources/forms/theme/default/login-oauth-grant.ftl
+++ b/forms/src/main/resources/META-INF/resources/forms/theme/default/login-oauth-grant.ftl
@@ -18,18 +18,20 @@
                     <span>${role.description}</span>
                 </li>
             </#list>
-        </ul>
 
-        <#list oauth.resourceRolesRequested?keys as resourceRole>
-            <p class="instruction"><strong>${resourceRole}</strong> requests access to:</p>
-            <ul>
-                <#list oauth.resourceRolesRequested[resourceRole] as role>
-                    <li>
-                        <span>${role.description}</span>
-                    </li>
-                </#list>
-            </ul>
-        </#list>
+            <#list oauth.resourceRolesRequested?keys as resourceRole>
+                <li>
+                    <strong>${resourceRole}</strong>
+                    <ul>
+                        <#list oauth.resourceRolesRequested[resourceRole] as role>
+                            <li>
+                                <span><#if role.description??>${role.description}<#else>${role.name}</#if></span>
+                            </li>
+                        </#list>
+                    </ul>
+                </li>
+            </#list>
+        </ul>
 
         <p class="terms">Keycloak Central Login and Google will use this information in accordance with their respective terms of service and privacy policies.</p>
         <form class="form-actions" action="${oauth.action}" method="POST">
diff --git a/model/api/src/main/java/org/keycloak/models/ApplicationModel.java b/model/api/src/main/java/org/keycloak/models/ApplicationModel.java
index efeccb8..e5374b8 100755
--- a/model/api/src/main/java/org/keycloak/models/ApplicationModel.java
+++ b/model/api/src/main/java/org/keycloak/models/ApplicationModel.java
@@ -1,5 +1,7 @@
 package org.keycloak.models;
 
+import java.util.List;
+
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
  * @version $Revision: 1 $
@@ -31,4 +33,9 @@ public interface ApplicationModel extends RoleContainerModel, RoleMapperModel, S
 
     void setBaseUrl(String url);
 
+    List<String> getDefaultRoles();
+
+    void addDefaultRole(String name);
+
+    void updateDefaultRoles(String[] defaultRoles);
 }
diff --git a/model/api/src/main/java/org/keycloak/models/Constants.java b/model/api/src/main/java/org/keycloak/models/Constants.java
index b0af34c..b02c9c2 100755
--- a/model/api/src/main/java/org/keycloak/models/Constants.java
+++ b/model/api/src/main/java/org/keycloak/models/Constants.java
@@ -12,5 +12,9 @@ public interface Constants {
     String IDENTITY_REQUESTER_ROLE = "KEYCLOAK_IDENTITY_REQUESTER";
     String WILDCARD_ROLE = "*";
 
+    String ACCOUNT_APPLICATION = "Account";
+    String ACCOUNT_PROFILE_ROLE = "view-profile";
+    String ACCOUNT_MANAGE_ROLE = "manage-account";
+
     String ACCOUNT_MANAGEMENT_APPLICATION = "Account Management";
 }
diff --git a/model/api/src/main/java/org/keycloak/models/RealmModel.java b/model/api/src/main/java/org/keycloak/models/RealmModel.java
index 401eb6a..3b0b149 100755
--- a/model/api/src/main/java/org/keycloak/models/RealmModel.java
+++ b/model/api/src/main/java/org/keycloak/models/RealmModel.java
@@ -84,7 +84,7 @@ public interface RealmModel extends RoleContainerModel, RoleMapperModel, ScopeMa
 
     UserModel addUser(String username);
 
-    List<RoleModel> getDefaultRoles();
+    List<String> getDefaultRoles();
     
     void addDefaultRole(String name);
     
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
index a93b669..00ed540 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/ApplicationAdapter.java
@@ -272,4 +272,61 @@ public class ApplicationAdapter implements ApplicationModel {
         return query;
     }
 
+    @Override
+    public List<String> getDefaultRoles() {
+        Collection<RoleEntity> entities = application.getDefaultRoles();
+        List<String> roles = new ArrayList<String>();
+        if (entities == null) return roles;
+        for (RoleEntity entity : entities) {
+            roles.add(entity.getName());
+        }
+        return roles;
+    }
+
+    @Override
+    public void addDefaultRole(String name) {
+        RoleModel role = getRole(name);
+        if (role == null) {
+            role = addRole(name);
+        }
+        Collection<RoleEntity> entities = application.getDefaultRoles();
+        for (RoleEntity entity : entities) {
+            if (entity.getId().equals(role.getId())) {
+                return;
+            }
+        }
+        entities.add(((RoleAdapter) role).getRole());
+        em.flush();
+    }
+
+    public static boolean contains(String str, String[] array) {
+        for (String s : array) {
+            if (str.equals(s)) return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void updateDefaultRoles(String[] defaultRoles) {
+        Collection<RoleEntity> entities = application.getDefaultRoles();
+        Set<String> already = new HashSet<String>();
+        List<RoleEntity> remove = new ArrayList<RoleEntity>();
+        for (RoleEntity rel : entities) {
+            if (!contains(rel.getName(), defaultRoles)) {
+                remove.add(rel);
+            } else {
+                already.add(rel.getName());
+            }
+        }
+        for (RoleEntity entity : remove) {
+            entities.remove(entity);
+        }
+        em.flush();
+        for (String roleName : defaultRoles) {
+            if (!already.contains(roleName)) {
+                addDefaultRole(roleName);
+            }
+        }
+        em.flush();
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java
index a3ab9b7..54d628d 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/entities/ApplicationEntity.java
@@ -33,6 +33,10 @@ public class ApplicationEntity {
     @JoinTable(name="APPLICATION_ROLES")
     Collection<RoleEntity> roles = new ArrayList<RoleEntity>();
 
+    @OneToMany(fetch = FetchType.LAZY, cascade ={CascadeType.REMOVE}, orphanRemoval = true)
+    @JoinTable(name="APPLICATION_DEFAULT_ROLES")
+    Collection<RoleEntity> defaultRoles = new ArrayList<RoleEntity>();
+
     public String getId() {
         return id;
     }
@@ -84,4 +88,12 @@ public class ApplicationEntity {
     public void setName(String name) {
         this.name = name;
     }
+
+    public Collection<RoleEntity> getDefaultRoles() {
+        return defaultRoles;
+    }
+
+    public void setDefaultRoles(Collection<RoleEntity> defaultRoles) {
+        this.defaultRoles = defaultRoles;
+    }
 }
diff --git a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
index 658588c..8eb89d5 100755
--- a/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
+++ b/model/jpa/src/main/java/org/keycloak/models/jpa/RealmAdapter.java
@@ -457,12 +457,12 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public List<RoleModel> getDefaultRoles() {
+    public List<String> getDefaultRoles() {
         Collection<RoleEntity> entities = realm.getDefaultRoles();
-        List<RoleModel> roles = new ArrayList<RoleModel>();
+        List<String> roles = new ArrayList<String>();
         if (entities == null) return roles;
         for (RoleEntity entity : entities) {
-            roles.add(new RoleAdapter(entity));
+            roles.add(entity.getName());
         }
         return roles;
     }
@@ -504,8 +504,8 @@ public class RealmAdapter implements RealmModel {
         }
         for (RoleEntity entity : remove) {
             entities.remove(entity);
-            em.remove(entity);
         }
+        em.flush();
         for (String roleName : defaultRoles) {
             if (!already.contains(roleName)) {
                 addDefaultRole(roleName);
@@ -543,6 +543,7 @@ public class RealmAdapter implements RealmModel {
         em.persist(user);
         applicationData.setApplicationUser(user);
         applicationData.setName(name);
+        applicationData.setEnabled(true);
         realm.getApplications().add(applicationData);
         em.persist(applicationData);
         em.flush();
diff --git a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
index f145933..c1a4dd2 100755
--- a/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
+++ b/model/mongo/src/main/java/org/keycloak/models/mongo/keycloak/adapters/ApplicationAdapter.java
@@ -281,4 +281,19 @@ public class ApplicationAdapter implements ApplicationModel {
         }
         return result;
     }
+
+    @Override
+    public List<String> getDefaultRoles() {
+        return null;  //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void addDefaultRole(String name) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
+
+    @Override
+    public void updateDefaultRoles(String[] defaultRoles) {
+        //To change body of implemented methods use File | Settings | File Templates.
+    }
 }
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/ApplicationAdapter.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/ApplicationAdapter.java
index 8ad09eb..436b23c 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/ApplicationAdapter.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/ApplicationAdapter.java
@@ -15,10 +15,7 @@ import org.picketlink.idm.model.sample.SampleModel;
 import org.picketlink.idm.query.IdentityQuery;
 import org.picketlink.idm.query.RelationshipQuery;
 
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 
 /**
  * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
@@ -257,4 +254,44 @@ public class ApplicationAdapter implements ApplicationModel {
         return roles;
     }
 
+    @Override
+    public List<String> getDefaultRoles() {
+        if ( applicationData.getDefaultRoles() != null) {
+            return Arrays.asList(applicationData.getDefaultRoles());
+        }
+        else {
+            return Collections.emptyList();
+        }
+    }
+
+    @Override
+    public void addDefaultRole(String name) {
+        if (getRole(name) == null) {
+            addRole(name);
+        }
+
+        String[] defaultRoles = applicationData.getDefaultRoles();
+        if (defaultRoles == null) {
+            defaultRoles = new String[1];
+        } else {
+            defaultRoles = Arrays.copyOf(defaultRoles, defaultRoles.length + 1);
+        }
+        defaultRoles[defaultRoles.length - 1] = name;
+
+        applicationData.setDefaultRoles(defaultRoles);
+        updateApplication();
+    }
+
+    @Override
+    public void updateDefaultRoles(String[] defaultRoles) {
+        for (String name : defaultRoles) {
+            if (getRole(name) == null) {
+                addRole(name);
+            }
+        }
+
+        applicationData.setDefaultRoles(defaultRoles);
+        updateApplication();
+    }
+
 }
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationData.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationData.java
index 8d5594a..5ce4aca 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationData.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationData.java
@@ -15,6 +15,7 @@ public class ApplicationData extends AbstractPartition {
     private String managementUrl;
     private String baseUrl;
     private User resourceUser;
+    private String[] defaultRoles;
 
     public ApplicationData() {
         super(null);
@@ -76,4 +77,13 @@ public class ApplicationData extends AbstractPartition {
         this.baseUrl = baseUrl;
     }
 
+    @AttributeProperty
+    public String[] getDefaultRoles() {
+        return defaultRoles;
+    }
+
+    public void setDefaultRoles(String[] defaultRoles) {
+        this.defaultRoles = defaultRoles;
+    }
+
 }
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationEntity.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationEntity.java
index 0eddf7e..0e8d23b 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationEntity.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/mappings/ApplicationEntity.java
@@ -34,6 +34,9 @@ public class ApplicationEntity implements Serializable {
     @AttributeValue
     private String baseUrl;
 
+    @AttributeValue
+    private String[] defaultRoles;
+
     @OneToOne
     @AttributeValue
     AccountTypeEntity resourceUser;
@@ -94,4 +97,13 @@ public class ApplicationEntity implements Serializable {
     public void setResourceUser(AccountTypeEntity resourceUser) {
         this.resourceUser = resourceUser;
     }
+
+    public String[] getDefaultRoles() {
+        return defaultRoles;
+    }
+
+    public void setDefaultRoles(String[] defaultRoles) {
+        this.defaultRoles = defaultRoles;
+    }
+
 }
diff --git a/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java b/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java
index ed71165..3279abf 100755
--- a/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java
+++ b/model/picketlink/src/main/java/org/keycloak/models/picketlink/RealmAdapter.java
@@ -43,13 +43,7 @@ import java.io.StringWriter;
 import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 /**
  * Meant to be a per-request object
@@ -767,17 +761,15 @@ public class RealmAdapter implements RealmModel {
     }
 
     @Override
-    public List<RoleModel> getDefaultRoles() {
-        List<RoleModel> defaultRoleModels = new ArrayList<RoleModel>();
-        if (realm.getDefaultRoles() != null) {
-            for (String name : realm.getDefaultRoles()) {
-                RoleAdapter role = getRole(name);
-                if (role != null) {
-                    defaultRoleModels.add(role);
-                }
-            }
+    public List<String> getDefaultRoles() {
+        if (realm.getDefaultRoles() == null) return Collections.emptyList();
+        List<String> list = new ArrayList<String>();
+        for (String role : realm.getDefaultRoles()) {
+            RoleModel model = getRole(role);
+            if (model == null) throw new RuntimeException("default role missing");
+            list.add(role);
         }
-        return defaultRoleModels;
+        return list;
     }
 
     @Override

model/pom.xml 2(+1 -1)

diff --git a/model/pom.xml b/model/pom.xml
index 3d0b0dc..26992ca 100755
--- a/model/pom.xml
+++ b/model/pom.xml
@@ -37,6 +37,6 @@
         <module>api</module>
         <module>picketlink</module>
         <module>jpa</module>
-        <module>mongo</module>
+        <!-- <module>mongo</module> -->
     </modules>
 </project>

pom.xml 4(+3 -1)

diff --git a/pom.xml b/pom.xml
index 3b446c8..eda9912 100755
--- a/pom.xml
+++ b/pom.xml
@@ -20,6 +20,7 @@
         <dom4j.version>1.6.1</dom4j.version>
         <mysql.version>5.1.25</mysql.version>
         <slf4j.version>1.6.1</slf4j.version>
+        <jboss.version>7.1.1.Final</jboss.version>
     </properties>
 
     <url>http://keycloak.org</url>
@@ -72,7 +73,8 @@
         <module>admin-ui</module>
         <module>examples</module>
         <module>testsuite</module>
-        <!--<module>ui</module> -->
+        <module>server</module>
+        <module>dist</module>
     </modules>
 
     <dependencyManagement>

server/pom.xml 149(+149 -0)

diff --git a/server/pom.xml b/server/pom.xml
new file mode 100755
index 0000000..51b450c
--- /dev/null
+++ b/server/pom.xml
@@ -0,0 +1,149 @@
+<?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-alpha-1</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>org.keycloak</groupId>
+    <artifactId>keycloak-server</artifactId>
+    <packaging>war</packaging>
+    <name>Keycloak Server</name>
+    <description/>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>jose-jwt</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-admin-ui</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-admin-ui-styles</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-services</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-picketlink</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-model-jpa</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-social-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-social-google</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-social-twitter</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-social-facebook</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-forms</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.picketlink</groupId>
+            <artifactId>picketlink-idm-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.picketlink</groupId>
+            <artifactId>picketlink-idm-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.picketlink</groupId>
+            <artifactId>picketlink-idm-simple-schema</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.picketlink</groupId>
+            <artifactId>picketlink-config</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>resteasy-jaxrs</artifactId>
+            <scope>provided</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>log4j</groupId>
+                    <artifactId>log4j</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-api</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-simple</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.resteasy</groupId>
+            <artifactId>jaxrs-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <version>1.3.161</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.1</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>auth-server</finalName>
+        <plugins>
+            <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/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java b/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java
new file mode 100755
index 0000000..cb91e73
--- /dev/null
+++ b/server/src/main/java/org/keycloak/server/KeycloakServerApplication.java
@@ -0,0 +1,28 @@
+package org.keycloak.server;
+
+import org.jboss.resteasy.jwt.JsonSerialization;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.services.managers.ApplianceBootstrap;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.RealmModel;
+import org.keycloak.services.resources.KeycloakApplication;
+
+import javax.servlet.ServletContext;
+import javax.ws.rs.core.Context;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class KeycloakServerApplication extends KeycloakApplication {
+
+    public KeycloakServerApplication(@Context ServletContext servletContext) {
+        super(servletContext);
+        KeycloakSession session = factory.createSession();
+        session.getTransaction().begin();
+        ApplianceBootstrap bootstrap = new ApplianceBootstrap();
+        bootstrap.bootstrap(session);
+        session.getTransaction().commit();
+    }
+
+}
diff --git a/server/src/main/resources/META-INF/persistence.xml b/server/src/main/resources/META-INF/persistence.xml
new file mode 100755
index 0000000..5d5eed0
--- /dev/null
+++ b/server/src/main/resources/META-INF/persistence.xml
@@ -0,0 +1,33 @@
+<persistence xmlns="http://java.sun.com/xml/ns/persistence"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
+    version="1.0">
+    <persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
+        <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
+
+        <class>org.picketlink.idm.jpa.model.sample.simple.AttributedTypeEntity</class>
+        <class>org.picketlink.idm.jpa.model.sample.simple.AccountTypeEntity</class>
+        <class>org.picketlink.idm.jpa.model.sample.simple.RoleTypeEntity</class>
+        <class>org.picketlink.idm.jpa.model.sample.simple.GroupTypeEntity</class>
+        <class>org.picketlink.idm.jpa.model.sample.simple.IdentityTypeEntity</class>
+        <class>org.picketlink.idm.jpa.model.sample.simple.RelationshipTypeEntity</class>
+        <class>org.picketlink.idm.jpa.model.sample.simple.RelationshipIdentityTypeEntity</class>
+        <class>org.picketlink.idm.jpa.model.sample.simple.PartitionTypeEntity</class>
+        <class>org.picketlink.idm.jpa.model.sample.simple.PasswordCredentialTypeEntity</class>
+        <class>org.picketlink.idm.jpa.model.sample.simple.DigestCredentialTypeEntity</class>
+        <class>org.picketlink.idm.jpa.model.sample.simple.X509CredentialTypeEntity</class>
+        <class>org.picketlink.idm.jpa.model.sample.simple.OTPCredentialTypeEntity</class>
+        <class>org.picketlink.idm.jpa.model.sample.simple.AttributeTypeEntity</class>
+        <class>org.keycloak.models.picketlink.mappings.RealmEntity</class>
+        <class>org.keycloak.models.picketlink.mappings.ApplicationEntity</class>
+
+        <exclude-unlisted-classes>true</exclude-unlisted-classes>
+
+        <properties>
+            <property name="hibernate.hbm2ddl.auto" value="create" />
+            <property name="hibernate.show_sql" value="false" />
+            <property name="hibernate.format_sql" value="false" />
+        </properties>
+    </persistence-unit>
+
+</persistence>
diff --git a/server/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/server/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
new file mode 100755
index 0000000..8caa96f
--- /dev/null
+++ b/server/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -0,0 +1,10 @@
+<jboss-deployment-structure>
+    <deployment>
+        <!-- This allows you to define additional dependencies, it is the same as using the Dependencies: manifest attribute -->
+        <dependencies>
+            <module name="org.jboss.resteasy.jose-jwt"/>
+            <module name="org.jboss.resteasy.resteasy-crypto"/>
+            <module name="org.bouncycastle"/>
+        </dependencies>
+    </deployment>
+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/server/src/main/webapp/WEB-INF/web.xml b/server/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..08bf314
--- /dev/null
+++ b/server/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+      version="3.0">
+
+	<module-name>auth-server</module-name>
+
+    <servlet>
+        <servlet-name>Resteasy</servlet-name>
+        <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServlet30Dispatcher</servlet-class>
+        <init-param>
+            <param-name>javax.ws.rs.Application</param-name>
+            <param-value>org.keycloak.server.KeycloakServerApplication</param-value>
+        </init-param>
+        <init-param>
+            <param-name>resteasy.servlet.mapping.prefix</param-name>
+            <param-value>/rest</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+        <async-supported>true</async-supported>
+    </servlet>
+
+    <filter>
+        <filter-name>Keycloak Session Management</filter-name>
+        <filter-class>org.keycloak.services.filters.KeycloakSessionServletFilter</filter-class>
+    </filter>
+
+    <filter-mapping>
+        <filter-name>Keycloak Session Management</filter-name>
+        <url-pattern>/rest/*</url-pattern>
+    </filter-mapping>
+
+    <servlet-mapping>
+        <servlet-name>Resteasy</servlet-name>
+        <url-pattern>/rest/*</url-pattern>
+    </servlet-mapping>
+
+</web-app>
diff --git a/services/src/main/java/org/keycloak/services/email/EmailSender.java b/services/src/main/java/org/keycloak/services/email/EmailSender.java
index 6bd1ba2..185ca83 100755
--- a/services/src/main/java/org/keycloak/services/email/EmailSender.java
+++ b/services/src/main/java/org/keycloak/services/email/EmailSender.java
@@ -48,26 +48,53 @@ public class EmailSender {
 
     private static final Logger log = Logger.getLogger(EmailSender.class);
 
-    private Properties properties;
+    private Map<String, String> config;
 
     public EmailSender(Map<String, String> config) {
-        properties = new Properties();
-        for (Entry<String, String> e : config.entrySet()) {
-            properties.put("mail.smtp." + e.getKey(), e.getValue());
-        }
+        this.config = config;
     }
 
     public void send(String address, String subject, String body) throws MessagingException {
-        Session session = Session.getInstance(properties);
+        Properties props = new Properties();
+        props.setProperty("mail.smtp.host", config.get("host"));
+
+        boolean auth = "true".equals(config.get("auth"));
+        boolean ssl = "true".equals(config.get("ssl"));
+        boolean starttls = "true".equals(config.get("starttls"));
+
+        if (config.containsKey("port")) {
+            props.setProperty("mail.smtp.port", config.get("port"));
+        }
+
+        if (auth) {
+            props.put("mail.smtp.auth", "true");
+        }
+
+        if (ssl) {
+            props.put("mail.smtp.socketFactory.port", config.get("port"));
+            props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
+        }
+
+        if (starttls) {
+            props.put("mail.smtp.starttls.enable", "true");
+        }
+
+        String from = config.get("from");
+
+        Session session = Session.getInstance(props);
 
         Message msg = new MimeMessage(session);
-        msg.setFrom(new InternetAddress(properties.getProperty("mail.smtp.from")));
+        msg.setFrom(new InternetAddress(from));
         msg.setSubject(subject);
         msg.setText(body);
         msg.saveChanges();
 
         Transport transport = session.getTransport("smtp");
-        transport.connect(properties.getProperty("mail.smtp.user"), properties.getProperty("mail.smtp.password"));
+        if (auth) {
+            transport.connect(config.get("user"), config.get("password"));
+        } else {
+            transport.connect();
+        }
         transport.sendMessage(msg, new InternetAddress[] { new InternetAddress(address) });
     }
 
diff --git a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
index a2464e8..67a8286 100755
--- a/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/ApplicationManager.java
@@ -70,6 +70,11 @@ public class ApplicationManager {
                 if (roleRep.getDescription() != null) role.setDescription(roleRep.getDescription());
             }
         }
+
+        if (resourceRep.getDefaultRoles() != null) {
+            applicationModel.updateDefaultRoles(resourceRep.getDefaultRoles());
+        }
+
         if (resourceRep.getRoleMappings() != null) {
             for (UserRoleMappingRepresentation mapping : resourceRep.getRoleMappings()) {
                 UserModel user = realm.getUser(mapping.getUsername());
@@ -114,6 +119,10 @@ public class ApplicationManager {
         resource.setSurrogateAuthRequired(rep.isSurrogateAuthRequired());
         resource.updateApplication();
 
+        if (rep.getDefaultRoles() != null) {
+            resource.updateDefaultRoles(rep.getDefaultRoles());
+        }
+
         List<String> redirectUris = rep.getRedirectUris();
         if (redirectUris != null) {
             resource.getApplicationUser().setRedirectUris(new HashSet<String>(redirectUris));
@@ -144,6 +153,10 @@ public class ApplicationManager {
             rep.setWebOrigins(new LinkedList<String>(webOrigins));
         }
 
+        if (!applicationModel.getDefaultRoles().isEmpty()) {
+            rep.setDefaultRoles(applicationModel.getDefaultRoles().toArray(new String[0]));
+        }
+
         return rep;
 
     }
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 8206eac..a3434b3 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -56,24 +56,27 @@ public class AuthenticationManager {
         String cookieName = KEYCLOAK_IDENTITY_COOKIE;
         URI uri = RealmsResource.realmBaseUrl(uriInfo).build(realm.getId());
         String cookiePath = uri.getPath();
-        return createLoginCookie(realm, user, cookieName, cookiePath);
+        return createLoginCookie(realm, user, null, cookieName, cookiePath);
     }
 
     public NewCookie createSaasIdentityCookie(RealmModel realm, UserModel user, UriInfo uriInfo) {
         String cookieName = SaasService.SAAS_IDENTITY_COOKIE;
         URI uri = SaasService.saasCookiePath(uriInfo).build();
         String cookiePath = uri.getPath();
-        return createLoginCookie(realm, user, cookieName, cookiePath);
+        return createLoginCookie(realm, user, null, cookieName, cookiePath);
     }
 
-    public NewCookie createAccountIdentityCookie(RealmModel realm, UserModel user, URI uri) {
+    public NewCookie createAccountIdentityCookie(RealmModel realm, UserModel user, UserModel client, URI uri) {
         String cookieName = AccountService.ACCOUNT_IDENTITY_COOKIE;
         String cookiePath = uri.getPath();
-        return createLoginCookie(realm, user, cookieName, cookiePath);
+        return createLoginCookie(realm, user, client, cookieName, cookiePath);
     }
 
-    protected NewCookie createLoginCookie(RealmModel realm, UserModel user, String cookieName, String cookiePath) {
+    protected NewCookie createLoginCookie(RealmModel realm, UserModel user, UserModel client, String cookieName, String cookiePath) {
         SkeletonKeyToken identityToken = createIdentityToken(realm, user.getLoginName());
+        if (client != null) {
+            identityToken.issuedFor(client.getLoginName());
+        }
         String encoded = encodeToken(realm, identityToken);
         boolean secureOnly = !realm.isSslNotRequired();
         logger.debug("creatingLoginCookie - name: {0} path: {1}", cookieName, cookiePath);
@@ -127,15 +130,17 @@ public class AuthenticationManager {
 
     public UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
         String cookieName = KEYCLOAK_IDENTITY_COOKIE;
-        return authenticateIdentityCookie(realm, uriInfo, headers, cookieName);
+        Auth auth = authenticateIdentityCookie(realm, uriInfo, headers, cookieName);
+        return auth != null ? auth.getUser() : null;
     }
 
     public UserModel authenticateSaasIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
         String cookieName = SaasService.SAAS_IDENTITY_COOKIE;
-        return authenticateIdentityCookie(realm, uriInfo, headers, cookieName);
+        Auth auth = authenticateIdentityCookie(realm, uriInfo, headers, cookieName);
+        return auth != null ? auth.getUser() : null;
     }
 
-    public UserModel authenticateAccountIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
+    public Auth authenticateAccountIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
         String cookieName = AccountService.ACCOUNT_IDENTITY_COOKIE;
         return authenticateIdentityCookie(realm, uriInfo, headers, cookieName);
     }
@@ -144,11 +149,19 @@ public class AuthenticationManager {
         UserModel user = authenticateSaasIdentityCookie(realm, uriInfo, headers);
         if (user != null) return user;
 
+        Auth auth = authenticateBearerToken(realm, headers);
+        return auth != null ? auth.getUser() : null;
+    }
+
+    public Auth authenticateAccountIdentity(RealmModel realm, UriInfo uriInfo, HttpHeaders headers) {
+        Auth auth = authenticateAccountIdentityCookie(realm, uriInfo, headers);
+        if (auth != null) return auth;
+
         return authenticateBearerToken(realm, headers);
     }
 
 
-    protected UserModel authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String cookieName) {
+    protected Auth authenticateIdentityCookie(RealmModel realm, UriInfo uriInfo, HttpHeaders headers, String cookieName) {
         Cookie cookie = headers.getCookies().get(cookieName);
         if (cookie == null) {
             logger.debug("authenticateCookie could not find cookie: {0}", cookieName);
@@ -163,13 +176,28 @@ public class AuthenticationManager {
                 expireIdentityCookie(realm, uriInfo);
                 return null;
             }
+
+            Auth auth = new Auth(token);
+
             UserModel user = realm.getUser(token.getPrincipal());
             if (user == null || !user.isEnabled()) {
                 logger.debug("Unknown user in identity cookie");
                 expireIdentityCookie(realm, uriInfo);
                 return null;
             }
-            return user;
+            auth.setUser(user);
+
+            if (token.getIssuedFor() != null) {
+                UserModel client = realm.getUser(token.getIssuedFor());
+                if (client == null || !client.isEnabled()) {
+                    logger.debug("Unknown client in identity cookie");
+                    expireIdentityCookie(realm, uriInfo);
+                    return null;
+                }
+                auth.setClient(client);
+            }
+
+            return auth;
         } catch (VerificationException e) {
             logger.debug("Failed to verify identity cookie", e);
             expireIdentityCookie(realm, uriInfo);
@@ -177,11 +205,11 @@ public class AuthenticationManager {
         return null;
     }
 
-    public UserModel authenticateBearerToken(RealmModel realm, HttpHeaders headers) {
+    public Auth authenticateBearerToken(RealmModel realm, HttpHeaders headers) {
         String tokenString = null;
         String authHeader = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
         if (authHeader == null) {
-            throw new NotAuthorizedException("Bearer");
+            return null;
         } else {
             String[] split = authHeader.trim().split("\\s+");
             if (split == null || split.length != 2) throw new NotAuthorizedException("Bearer");
@@ -195,11 +223,24 @@ public class AuthenticationManager {
             if (!token.isActive()) {
                 throw new NotAuthorizedException("token_expired");
             }
+
+            Auth auth = new Auth(token);
+
             UserModel user = realm.getUser(token.getPrincipal());
             if (user == null || !user.isEnabled()) {
                 throw new NotAuthorizedException("invalid_user");
             }
-            return user;
+            auth.setUser(user);
+
+            if (token.getIssuedFor() != null) {
+                UserModel client = realm.getUser(token.getIssuedFor());
+                if (client == null || !client.isEnabled()) {
+                    throw new NotAuthorizedException("invalid_user");
+                }
+                auth.setClient(client);
+            }
+
+            return auth;
         } catch (VerificationException e) {
             logger.error("Failed to verify token", e);
             throw new NotAuthorizedException("invalid_token");
@@ -271,4 +312,34 @@ public class AuthenticationManager {
         SUCCESS, ACCOUNT_DISABLED, ACTIONS_REQUIRED, INVALID_USER, INVALID_CREDENTIALS, MISSING_PASSWORD, MISSING_TOTP, FAILED
     }
 
+    public static class Auth {
+        private SkeletonKeyToken token;
+        private UserModel user;
+        private UserModel client;
+
+        public Auth(SkeletonKeyToken token) {
+            this.token = token;
+        }
+
+        public SkeletonKeyToken getToken() {
+            return token;
+        }
+
+        public UserModel getUser() {
+            return user;
+        }
+
+        public UserModel getClient() {
+            return client;
+        }
+
+        void setUser(UserModel user) {
+            this.user = user;
+        }
+
+        void setClient(UserModel client) {
+            this.client = client;
+        }
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index d131e84..8cd43a0 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -110,7 +110,7 @@ public class RealmManager {
             realm.updateRequiredApplicationCredentials(rep.getRequiredApplicationCredentials());
         }
         if (rep.getDefaultRoles() != null) {
-            realm.updateDefaultRoles(rep.getDefaultRoles());
+            realm.updateDefaultRoles(rep.getDefaultRoles().toArray(new String[rep.getDefaultRoles().size()]));
         }
 
         if (rep.getAccountManagement() != null && rep.getAccountManagement()) {
@@ -129,9 +129,11 @@ public class RealmManager {
     }
 
     private void enableAccountManagement(RealmModel realm) {
-        ApplicationModel application = realm.getApplicationById(Constants.ACCOUNT_MANAGEMENT_APPLICATION);
+        ApplicationModel application = realm.getApplicationById(Constants.ACCOUNT_APPLICATION);
         if (application == null) {
-            application = realm.addApplication(Constants.ACCOUNT_MANAGEMENT_APPLICATION);
+            application = realm.addApplication(Constants.ACCOUNT_APPLICATION);
+            application.addDefaultRole(Constants.ACCOUNT_PROFILE_ROLE);
+            application.addDefaultRole(Constants.ACCOUNT_MANAGE_ROLE);
 
             UserCredentialModel password = new UserCredentialModel();
             password.setType(UserCredentialModel.PASSWORD);
@@ -146,7 +148,7 @@ public class RealmManager {
     }
 
     private void disableAccountManagement(RealmModel realm) {
-        ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APPLICATION);
+        ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
         if (application != null) {
             application.setEnabled(false); // TODO Should we delete the application instead?
         }
@@ -410,9 +412,11 @@ public class RealmManager {
         rep.setLastName(user.getLastName());
         rep.setFirstName(user.getFirstName());
         rep.setEmail(user.getEmail());
-        Map<String, String> attrs = new HashMap<String, String>();
-        attrs.putAll(user.getAttributes());
-        rep.setAttributes(attrs);
+        if (user.getAttributes() != null && !user.getAttributes().isEmpty()) {
+            Map<String, String> attrs = new HashMap<String, String>();
+            attrs.putAll(user.getAttributes());
+            rep.setAttributes(attrs);
+        }
         return rep;
     }
 
@@ -444,16 +448,14 @@ public class RealmManager {
         rep.setSmtpServer(realm.getSmtpConfig());
         rep.setSocialProviders(realm.getSocialConfig());
 
-        ApplicationModel accountManagementApplication = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APPLICATION);
+        ApplicationModel accountManagementApplication = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
         rep.setAccountManagement(accountManagementApplication != null && accountManagementApplication.isEnabled());
 
-        List<RoleModel> defaultRoles = realm.getDefaultRoles();
-        if (defaultRoles.size() > 0) {
-            String[] d = new String[defaultRoles.size()];
-            for (int i = 0; i < d.length; i++) {
-                d[i] = defaultRoles.get(i).getName();
-            }
-            rep.setDefaultRoles(d);
+        List<String> defaultRoles = realm.getDefaultRoles();
+        if (!defaultRoles.isEmpty()) {
+            List<String> roleStrings = new ArrayList<String>();
+            roleStrings.addAll(defaultRoles);
+            rep.setDefaultRoles(roleStrings);
         }
 
         List<RequiredCredentialModel> requiredCredentialModels = realm.getRequiredCredentials();
diff --git a/services/src/main/java/org/keycloak/services/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
index f053173..d5b955f 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -15,6 +15,7 @@ import org.keycloak.representations.SkeletonKeyToken;
 import javax.ws.rs.core.MultivaluedMap;
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -51,12 +52,16 @@ public class TokenManager {
         List<RoleModel> realmRolesRequested = code.getRealmRolesRequested();
         MultivaluedMap<String, RoleModel> resourceRolesRequested = code.getResourceRolesRequested();
         Set<String> realmMapping = realm.getRoleMappingValues(user);
+        realmMapping.addAll(realm.getDefaultRoles());
 
         if (realmMapping != null && realmMapping.size() > 0 && (scopeMap == null || scopeMap.containsKey("realm"))) {
             Set<String> scope = realm.getScopeMappingValues(client);
             if (scope.size() > 0) {
                 Set<String> scopeRequest = null;
                 if (scopeMap != null) {
+                    if (scopeRequest == null) {
+                        scopeRequest = new HashSet<String>();
+                    }
                     scopeRequest.addAll(scopeMap.get("realm"));
                     if (scopeRequest.contains(Constants.WILDCARD_ROLE)) scopeRequest = null;
                 }
@@ -71,11 +76,15 @@ public class TokenManager {
         }
         for (ApplicationModel resource : realm.getApplications()) {
             Set<String> mapping = resource.getRoleMappingValues(user);
+            mapping.addAll(resource.getDefaultRoles());
             if (mapping != null && mapping.size() > 0 && (scopeMap == null || scopeMap.containsKey(resource.getName()))) {
                 Set<String> scope = resource.getScopeMappingValues(client);
                 if (scope.size() > 0) {
                     Set<String> scopeRequest = null;
                     if (scopeMap != null) {
+                        if (scopeRequest == null) {
+                            scopeRequest = new HashSet<String>();
+                        }
                         scopeRequest.addAll(scopeMap.get(resource.getName()));
                         if (scopeRequest.contains(Constants.WILDCARD_ROLE)) scopeRequest = null;
                     }
diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index eab8766..f176061 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -27,15 +27,13 @@ import org.jboss.resteasy.logging.Logger;
 import org.jboss.resteasy.spi.HttpRequest;
 import org.keycloak.AbstractOAuthClient;
 import org.keycloak.jaxrs.JaxrsOAuthClient;
-import org.keycloak.models.ApplicationModel;
-import org.keycloak.models.Constants;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserCredentialModel;
-import org.keycloak.models.UserModel;
+import org.keycloak.models.*;
 import org.keycloak.models.utils.TimeBasedOTP;
+import org.keycloak.representations.SkeletonKeyToken;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.services.managers.AccessCodeEntry;
 import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.managers.RealmManager;
 import org.keycloak.services.managers.TokenManager;
 import org.keycloak.services.messages.Messages;
 import org.keycloak.services.resources.flows.Flows;
@@ -44,23 +42,11 @@ import org.keycloak.services.resources.flows.Pages;
 import org.keycloak.services.resources.flows.Urls;
 import org.keycloak.services.validation.Validation;
 
-import javax.ws.rs.BadRequestException;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.ForbiddenException;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.QueryParam;
-import javax.ws.rs.core.Context;
-import javax.ws.rs.core.HttpHeaders;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.NewCookie;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.*;
+import javax.ws.rs.core.*;
 import javax.ws.rs.ext.Providers;
 import java.net.URI;
+import java.util.List;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -98,18 +84,42 @@ public class AccountService {
     }
 
     private Response forwardToPage(String path, String template) {
-        UserModel user = getUser(false);
-        if (user != null) {
-            return Flows.forms(realm, request, uriInfo).setUser(user).forwardToForm(template);
+        AuthenticationManager.Auth auth = getAuth(false);
+        if (auth != null) {
+            if (!hasAccess(auth)) {
+                return noAccess();
+            }
+            return Flows.forms(realm, request, uriInfo).setUser(auth.getUser()).forwardToForm(template);
         } else {
             return login(path);
         }
     }
 
-    @Path("")
+    private Response noAccess() {
+        return Flows.forms(realm, request, uriInfo).setError("No access").forwardToErrorPage();
+    }
+
+    @Path("/")
+    @OPTIONS
+    public Response accountPreflight() {
+        return Cors.add(request, Response.ok()).auth().preflight().build();
+    }
+
+    @Path("/")
     @GET
     public Response accountPage() {
-        return forwardToPage(null, Pages.ACCOUNT);
+        List<MediaType> types = headers.getAcceptableMediaTypes();
+        if (types.contains(MediaType.WILDCARD_TYPE) || (types.contains(MediaType.TEXT_HTML_TYPE))) {
+            return forwardToPage(null, Pages.ACCOUNT);
+        } else if (types.contains(MediaType.APPLICATION_JSON_TYPE)) {
+            AuthenticationManager.Auth auth = getAuth(true);
+            if (!hasAccess(auth, Constants.ACCOUNT_PROFILE_ROLE)) {
+                return Response.status(Response.Status.FORBIDDEN).build();
+            }
+            return Cors.add(request, Response.ok(RealmManager.toRepresentation(auth.getUser()))).auth().allowedOrigins(auth.getClient()).build();
+        } else {
+            return Response.notAcceptable(Variant.VariantListBuilder.newInstance().mediaTypes(MediaType.TEXT_HTML_TYPE, MediaType.APPLICATION_JSON_TYPE).build()).build();
+        }
     }
 
     @Path("social")
@@ -136,12 +146,16 @@ public class AccountService {
         return forwardToPage("access", Pages.ACCESS);
     }
 
-    @Path("")
+    @Path("/")
     @POST
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
     public Response processAccountUpdate(final MultivaluedMap<String, String> formData) {
+        AuthenticationManager.Auth auth = getAuth(true);
+        if (!hasAccess(auth)) {
+            return noAccess();
+        }
 
-        UserModel user = getUser(true);
+        UserModel user = auth.getUser();
 
         String error = Validation.validateUpdateProfileForm(formData);
         if (error != null) {
@@ -159,7 +173,13 @@ public class AccountService {
     @Path("totp-remove")
     @GET
     public Response processTotpRemove() {
-        UserModel user = getUser(true);
+        AuthenticationManager.Auth auth = getAuth(true);
+        if (!hasAccess(auth)) {
+            return noAccess();
+        }
+
+        UserModel user = auth.getUser();
+
         user.setTotp(false);
         return Flows.forms(realm, request, uriInfo).setError("successTotpRemoved").setErrorType(FormFlows.MessageType.SUCCESS)
                 .setUser(user).forwardToTotp();
@@ -169,7 +189,12 @@ public class AccountService {
     @POST
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
     public Response processTotpUpdate(final MultivaluedMap<String, String> formData) {
-        UserModel user = getUser(true);
+        AuthenticationManager.Auth auth = getAuth(true);
+        if (!hasAccess(auth)) {
+            return noAccess();
+        }
+
+        UserModel user = auth.getUser();
 
         String totp = formData.getFirst("totp");
         String totpSecret = formData.getFirst("totpSecret");
@@ -196,7 +221,12 @@ public class AccountService {
     @POST
     @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
     public Response processPasswordUpdate(final MultivaluedMap<String, String> formData) {
-        UserModel user = getUser(true);
+        AuthenticationManager.Auth auth = getAuth(true);
+        if (!hasAccess(auth)) {
+            return noAccess();
+        }
+
+        UserModel user = auth.getUser();
 
         FormFlows forms = Flows.forms(realm, request, uriInfo).setUser(user);
 
@@ -297,7 +327,7 @@ public class AccountService {
             }
             URI redirectUri = redirectBuilder.build(realm.getId());
 
-            NewCookie cookie = authManager.createAccountIdentityCookie(realm, accessCode.getUser(), Urls.accountBase(uriInfo.getBaseUri()).build(realm.getId()));
+            NewCookie cookie = authManager.createAccountIdentityCookie(realm, accessCode.getUser(), client, Urls.accountBase(uriInfo.getBaseUri()).build(realm.getId()));
             return Response.status(302).cookie(cookie).location(redirectUri).build();
         } finally {
             authManager.expireCookie(AbstractOAuthClient.OAUTH_TOKEN_REQUEST_STATE, uriInfo.getAbsolutePath().getPath());
@@ -319,7 +349,7 @@ public class AccountService {
         String authUrl = Urls.realmLoginPage(uriInfo.getBaseUri(), realm.getId()).toString();
         oauth.setAuthUrl(authUrl);
 
-        oauth.setClientId(Constants.ACCOUNT_MANAGEMENT_APPLICATION);
+        oauth.setClientId(Constants.ACCOUNT_APPLICATION);
 
         URI accountUri = Urls.accountPageBuilder(uriInfo.getBaseUri()).path(AccountService.class, "loginRedirect").build(realm.getId());
 
@@ -327,11 +357,42 @@ public class AccountService {
         return oauth.redirect(uriInfo, accountUri.toString(), path);
     }
 
-    private UserModel getUser(boolean required) {
-        UserModel user = authManager.authenticateAccountIdentityCookie(realm, uriInfo, headers);
-        if (user == null && required) {
+    private AuthenticationManager.Auth getAuth(boolean error) {
+        AuthenticationManager.Auth auth = authManager.authenticateAccountIdentity(realm, uriInfo, headers);
+        if (auth == null && error) {
             throw new ForbiddenException();
         }
-        return user;
+        return auth;
+    }
+
+    private boolean hasAccess(AuthenticationManager.Auth auth) {
+        return hasAccess(auth, null);
     }
+
+    private boolean hasAccess(AuthenticationManager.Auth auth, String role) {
+        UserModel client = auth.getClient();
+        if (realm.hasRole(client, Constants.APPLICATION_ROLE)) {
+            // Tokens from cookies don't have roles
+            if (hasRole(client, Constants.ACCOUNT_MANAGE_ROLE) || (role != null && hasRole(client, role))) {
+                return true;
+            }
+        }
+
+        SkeletonKeyToken.Access access = auth.getToken().getResourceAccess(application.getName());
+        if (access != null) {
+            if (access.isUserInRole(Constants.ACCOUNT_MANAGE_ROLE) || (role != null && access.isUserInRole(role))) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private boolean hasRole(UserModel user, String role) {
+        if (application.getDefaultRoles().contains(role)) {
+            return true;
+        }
+        return application.hasRole(user, role);
+    }
+
 }
diff --git a/services/src/main/java/org/keycloak/services/resources/Cors.java b/services/src/main/java/org/keycloak/services/resources/Cors.java
index 53c5eaa..42c34d1 100755
--- a/services/src/main/java/org/keycloak/services/resources/Cors.java
+++ b/services/src/main/java/org/keycloak/services/resources/Cors.java
@@ -1,19 +1,37 @@
 package org.keycloak.services.resources;
 
-import org.jboss.resteasy.spi.HttpRequest;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.ResponseBuilder;
-import java.util.Set;
+
+import org.jboss.resteasy.spi.HttpRequest;
+import org.keycloak.models.UserModel;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
  */
 public class Cors {
 
+    public static final long DEFAULT_MAX_AGE = TimeUnit.HOURS.toSeconds(1);
+    public static final String DEFAULT_ALLOW_METHODS = "GET, OPTIONS";
+
+    public static final String ORIGIN = "Origin";
+
+    public static final String ACCESS_CONTROL_ALLOW_ORIGIN = "Access-Control-Allow-Origin";
+    public static final String ACCESS_CONTROL_ALLOW_METHODS = "Access-Control-Allow-Methods";
+    public static final String ACCESS_CONTROL_ALLOW_HEADERS = "Access-Control-Allow-Headers";
+    public static final String ACCESS_CONTROL_ALLOW_CREDENTIALS = "Access-Control-Allow-Credentials";
+    public static final String ACCESS_CONTROL_MAX_AGE = "Access-Control-Max-Age";
+
     private HttpRequest request;
     private ResponseBuilder response;
     private Set<String> allowedOrigins;
+    private String[] allowedMethods;
+
+    private boolean preflight;
+    private boolean auth;
 
     public Cors(HttpRequest request, ResponseBuilder response) {
         this.request = request;
@@ -24,18 +42,60 @@ public class Cors {
         return new Cors(request, response);
     }
 
-    public Cors allowedOrigins(Set<String> allowedOrigins) {
-        this.allowedOrigins = allowedOrigins;
+    public Cors preflight() {
+        preflight = true;
+        return this;
+    }
+
+    public Cors auth() {
+        auth = true;
+        return this;
+    }
+
+    public Cors allowedOrigins(UserModel client) {
+        if (client != null) {
+            allowedOrigins = client.getWebOrigins();
+        }
+        return this;
+    }
+
+    public Cors allowedMethods(String... allowedMethods) {
+        this.allowedMethods = allowedMethods;
         return this;
     }
 
     public Response build() {
-        String origin = request.getHttpHeaders().getHeaderString("Origin");
-        if (origin == null || allowedOrigins == null || (!allowedOrigins.contains(origin))) {
+        String origin = request.getHttpHeaders().getHeaderString(ORIGIN);
+        if (origin == null) {
+            return response.build();
+        }
+
+        if (!preflight && (allowedOrigins == null || !allowedOrigins.contains(origin))) {
             return response.build();
         }
 
-        response.header("Access-Control-Allow-Origin", origin);
+        response.header(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
+
+        if (allowedMethods != null) {
+            StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < allowedMethods.length; i++) {
+                if (i > 0) {
+                    sb.append(", ");
+                }
+                sb.append(allowedMethods[i]);
+            }
+            response.header(ACCESS_CONTROL_ALLOW_METHODS, sb.toString());
+        } else {
+            response.header(ACCESS_CONTROL_ALLOW_METHODS, DEFAULT_ALLOW_METHODS);
+        }
+
+        response.header(ACCESS_CONTROL_ALLOW_CREDENTIALS, Boolean.toString(auth));
+        if (auth) {
+            response.header(ACCESS_CONTROL_ALLOW_HEADERS, "Authorization");
+        }
+
+        response.header(ACCESS_CONTROL_MAX_AGE, DEFAULT_MAX_AGE);
+
         return response.build();
     }
 
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index 07d1cb6..867c2c1 100755
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -3,9 +3,9 @@ package org.keycloak.services.resources;
 import org.keycloak.SkeletonKeyContextResolver;
 import org.keycloak.models.KeycloakSessionFactory;
 import org.keycloak.models.ModelProvider;
+import org.keycloak.services.managers.SocialRequestManager;
 import org.keycloak.services.managers.TokenManager;
 import org.keycloak.services.utils.PropertiesManager;
-import org.keycloak.social.SocialRequestManager;
 
 import javax.annotation.PreDestroy;
 import javax.servlet.ServletContext;
diff --git a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
index 1247995..f96f343 100755
--- a/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/RealmsResource.java
@@ -69,7 +69,7 @@ public class RealmsResource {
             throw new NotFoundException();
         }
 
-        ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_MANAGEMENT_APPLICATION);
+        ApplicationModel application = realm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
         if (application == null || !application.isEnabled()) {
             logger.debug("account management not enabled");
             throw new NotFoundException();
diff --git a/services/src/main/java/org/keycloak/services/resources/SocialResource.java b/services/src/main/java/org/keycloak/services/resources/SocialResource.java
index 1db79ea..908844c 100755
--- a/services/src/main/java/org/keycloak/services/resources/SocialResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/SocialResource.java
@@ -39,12 +39,11 @@ import org.keycloak.services.resources.flows.Urls;
 import org.keycloak.social.AuthCallback;
 import org.keycloak.social.AuthRequest;
 import org.keycloak.social.RequestDetails;
-import org.keycloak.social.RequestDetailsBuilder;
 import org.keycloak.social.SocialConstants;
 import org.keycloak.social.SocialProvider;
 import org.keycloak.social.SocialProviderConfig;
 import org.keycloak.social.SocialProviderException;
-import org.keycloak.social.SocialRequestManager;
+import org.keycloak.services.managers.SocialRequestManager;
 import org.keycloak.social.SocialUser;
 
 import javax.imageio.spi.ServiceRegistry;
@@ -181,19 +180,12 @@ public class SocialResource {
                 }
 
                 realm.addSocialLink(user, socialLink);
-
-                for (RoleModel role : realm.getDefaultRoles()) {
-                    realm.grantRole(user, role);
-                }
             }  else {
                 // Redirect user to registration screen with prefilled data from social provider
                 MultivaluedMap<String, String> formData = fillRegistrationFormWithSocialData(socialUser);
 
-                RequestDetailsBuilder reqDetailsBuilder = RequestDetailsBuilder.createFromRequestDetails(requestData);
-                reqDetailsBuilder.putSocialAttribute(SocialConstants.ATTR_SOCIAL_LINK, socialLink);
-
                 String requestId = UUID.randomUUID().toString();
-                socialRequestManager.addRequest(requestId, reqDetailsBuilder.build());
+                socialRequestManager.addRequest(requestId, RequestDetails.create(requestData).build());
                 boolean secureOnly = !realm.isSslNotRequired();
                 String cookiePath = Urls.socialBase(uriInfo.getBaseUri()).build().getPath();
                 logger.debug("creating cookie for social registration - name: {0} path: {1}", SocialConstants.SOCIAL_REGISTRATION_COOKIE,
@@ -241,7 +233,7 @@ public class SocialResource {
         try {
             AuthRequest authRequest = provider.getAuthUrl(config);
 
-            RequestDetails socialRequest = RequestDetailsBuilder.create(providerId)
+            RequestDetails socialRequest = RequestDetails.create(providerId)
                     .putSocialAttributes(authRequest.getAttributes()).putClientAttribute("realmId", realmId)
                     .putClientAttribute("clientId", clientId).putClientAttribute("scope", scope)
                     .putClientAttribute("state", state).putClientAttribute("redirectUri", redirectUri).build();
@@ -285,7 +277,6 @@ public class SocialResource {
         String scope = requestData.getClientAttribute("scope");
         String state = requestData.getClientAttribute("state");
         String redirectUri = requestData.getClientAttribute("redirectUri");
-        SocialLinkModel socialLink = (SocialLinkModel)requestData.getSocialAttribute(SocialConstants.ATTR_SOCIAL_LINK);
 
         Response response1 = tokenService.processRegisterImpl(clientId, scope, state, redirectUri, formData, true);
 
@@ -301,7 +292,7 @@ public class SocialResource {
             // Normally shouldn't happen
             throw new IllegalStateException("User " + username + " not found in the realm");
         }
-        realm.addSocialLink(user, socialLink);
+        realm.addSocialLink(user, new SocialLinkModel(requestData.getProviderId(), username));
 
         // Expire cookie and invalidate requestData
         String cookiePath = Urls.socialBase(uriInfo.getBaseUri()).build().getPath();
diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java
index 2e3b2aa..d9690df 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -323,10 +323,6 @@ public class TokenService {
             realm.updateCredential(user, credentials);
         }
 
-        for (RoleModel role : realm.getDefaultRoles()) {
-            realm.grantRole(user, role);
-        }
-
         return null;
     }
 
@@ -427,7 +423,7 @@ public class TokenService {
         logger.debug("accessRequest SUCCESS");
         AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
 
-        return Cors.add(request, Response.ok(res)).allowedOrigins(client.getWebOrigins()).build();
+        return Cors.add(request, Response.ok(res)).allowedOrigins(client).build();
     }
 
     protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) {
@@ -468,7 +464,7 @@ public class TokenService {
         }
         UserModel client = realm.getUser(clientId);
         if (client == null) {
-            logger.warn("Unknown login requester.");
+            logger.warn("Unknown login requester: " + clientId);
             oauth.forwardToSecurityFailure("Unknown login requester.");
             transaction.rollback();
             return null;
diff --git a/services/src/test/java/org/keycloak/services/email/EmailSenderTest.java b/services/src/test/java/org/keycloak/services/email/EmailSenderTest.java
index d4c5a66..e749f16 100755
--- a/services/src/test/java/org/keycloak/services/email/EmailSenderTest.java
+++ b/services/src/test/java/org/keycloak/services/email/EmailSenderTest.java
@@ -55,7 +55,7 @@ public class EmailSenderTest {
     }
 
     @Test
-    public void sendMail() throws AddressException, MessagingException, IOException {
+    public void sendMail() throws MessagingException, IOException {
         emailSender.send("test@test.com", "Test subject", "Test body");
 
         MimeMessage[] receivedMessages = greenMail.getReceivedMessages();
diff --git a/services/src/test/java/org/keycloak/test/AdapterTest.java b/services/src/test/java/org/keycloak/test/AdapterTest.java
index 210bdb7..1c86dfe 100755
--- a/services/src/test/java/org/keycloak/test/AdapterTest.java
+++ b/services/src/test/java/org/keycloak/test/AdapterTest.java
@@ -77,7 +77,7 @@ public class AdapterTest extends AbstractKeycloakTest {
         Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234");
         Assert.assertEquals(realmModel.isAutomaticRegistrationAfterSocialLogin(), true);
         Assert.assertEquals(1, realmModel.getDefaultRoles().size());
-        Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0).getName());
+        Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0));
     }
 
     @Test
@@ -106,7 +106,7 @@ public class AdapterTest extends AbstractKeycloakTest {
         Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234");
         Assert.assertEquals(realmModel.isAutomaticRegistrationAfterSocialLogin(), true);
         Assert.assertEquals(1, realmModel.getDefaultRoles().size());
-        Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0).getName());
+        Assert.assertEquals("foo", realmModel.getDefaultRoles().get(0));
 
         String id = realmModel.getId();
         System.out.println("id: " + id);
diff --git a/services/src/test/java/org/keycloak/test/ApplicationModelTest.java b/services/src/test/java/org/keycloak/test/ApplicationModelTest.java
index 34f2e41..a5e2a01 100755
--- a/services/src/test/java/org/keycloak/test/ApplicationModelTest.java
+++ b/services/src/test/java/org/keycloak/test/ApplicationModelTest.java
@@ -45,6 +45,8 @@ public class ApplicationModelTest extends AbstractKeycloakServerTest {
         application.setName("app-name");
         application.addRole("role-1");
         application.addRole("role-2");
+        application.addDefaultRole("role-1");
+        application.addDefaultRole("role-2");
 
         application.getApplicationUser().addRedirectUri("redirect-1");
         application.getApplicationUser().addRedirectUri("redirect-2");
@@ -83,6 +85,7 @@ public class ApplicationModelTest extends AbstractKeycloakServerTest {
         Assert.assertEquals(expected.getName(), actual.getName());
         Assert.assertEquals(expected.getBaseUrl(), actual.getBaseUrl());
         Assert.assertEquals(expected.getManagementUrl(), actual.getManagementUrl());
+        Assert.assertEquals(expected.getDefaultRoles(), actual.getDefaultRoles());
 
         UserModel auser = actual.getApplicationUser();
         UserModel euser = expected.getApplicationUser();
diff --git a/services/src/test/java/org/keycloak/test/ModelTest.java b/services/src/test/java/org/keycloak/test/ModelTest.java
index 4db17bf..33eb405 100755
--- a/services/src/test/java/org/keycloak/test/ModelTest.java
+++ b/services/src/test/java/org/keycloak/test/ModelTest.java
@@ -85,7 +85,7 @@ public class ModelTest extends AbstractKeycloakServerTest {
         Assert.assertEquals(expected.getPublicKeyPem(), actual.getPublicKeyPem());
         Assert.assertEquals(expected.getPrivateKeyPem(), actual.getPrivateKeyPem());
 
-        assertEquals(expected.getDefaultRoles(), actual.getDefaultRoles());
+        Assert.assertEquals(expected.getDefaultRoles(), actual.getDefaultRoles());
 
         Assert.assertEquals(expected.getSmtpConfig(), actual.getSmtpConfig());
         Assert.assertEquals(expected.getSocialConfig(), actual.getSocialConfig());
diff --git a/social/core/src/main/java/org/keycloak/social/AuthCallback.java b/social/core/src/main/java/org/keycloak/social/AuthCallback.java
index 8e21a21..d9c579a 100644
--- a/social/core/src/main/java/org/keycloak/social/AuthCallback.java
+++ b/social/core/src/main/java/org/keycloak/social/AuthCallback.java
@@ -28,11 +28,11 @@ import java.util.Map;
  */
 public class AuthCallback {
     
-    private Map<String, Object> attributes;
+    private Map<String, String> attributes;
 
     private Map<String, String[]> queryParams;
 
-    public AuthCallback(Map<String, Object> attributes, Map<String, String[]> queryParams) {
+    public AuthCallback(Map<String, String> attributes, Map<String, String[]> queryParams) {
         this.attributes = attributes;
         this.queryParams = queryParams;
     }
diff --git a/social/core/src/main/java/org/keycloak/social/AuthRequest.java b/social/core/src/main/java/org/keycloak/social/AuthRequest.java
index 69731e9..481885d 100644
--- a/social/core/src/main/java/org/keycloak/social/AuthRequest.java
+++ b/social/core/src/main/java/org/keycloak/social/AuthRequest.java
@@ -21,7 +21,9 @@
  */
 package org.keycloak.social;
 
+import javax.ws.rs.core.UriBuilder;
 import java.net.URI;
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -33,9 +35,17 @@ public class AuthRequest {
 
     private URI authUri;
 
-    private Map<String, Object> attributes;
+    private Map<String, String> attributes;
 
-    AuthRequest(String id, URI authUri, Map<String, Object> attributes) {
+    public static AuthRequestBuilder create(String id, String path) {
+        AuthRequestBuilder req = new AuthRequestBuilder();
+        req.id = id;
+        req.b = UriBuilder.fromUri(path);
+        req.attributes = new HashMap<String, String>();
+        return req;
+    }
+
+    private AuthRequest(String id, URI authUri, Map<String, String> attributes) {
         this.id = id;
         this.authUri = authUri;
         this.attributes = attributes;
@@ -49,8 +59,35 @@ public class AuthRequest {
         return authUri;
     }
 
-    public Map<String, Object> getAttributes() {
+    public Map<String, String> getAttributes() {
         return attributes;
     }
 
+    public static class AuthRequestBuilder {
+
+        private UriBuilder b;
+
+        private Map<String, String> attributes;
+
+        private String id;
+
+        private AuthRequestBuilder() {
+        }
+
+        public AuthRequestBuilder setQueryParam(String name, String value) {
+            b.queryParam(name, value);
+            return this;
+        }
+
+        public AuthRequestBuilder setAttribute(String name, String value) {
+            attributes.put(name, value);
+            return this;
+        }
+
+        public AuthRequest build() {
+            return new AuthRequest(id, b.build(), attributes);
+        }
+
+    }
+
 }
diff --git a/social/core/src/main/java/org/keycloak/social/RequestDetails.java b/social/core/src/main/java/org/keycloak/social/RequestDetails.java
index f77f59b..0d87812 100644
--- a/social/core/src/main/java/org/keycloak/social/RequestDetails.java
+++ b/social/core/src/main/java/org/keycloak/social/RequestDetails.java
@@ -21,6 +21,7 @@
  */
 package org.keycloak.social;
 
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -32,9 +33,27 @@ public class RequestDetails {
 
     private Map<String, String> clientAttributes;
 
-    private Map<String, Object> socialAttributes;
+    private Map<String, String> socialAttributes;
 
-    RequestDetails(String providerId, Map<String, String> clientAttributes, Map<String, Object> socialAttributes) {
+    public static RequestDetailsBuilder create(String providerId) {
+        RequestDetailsBuilder req = new RequestDetailsBuilder();
+        req.providerId = providerId;
+        req.clientAttributes = new HashMap<String, String>();
+        req.socialAttributes = new HashMap<String, String>();
+        return req;
+    }
+
+    public static RequestDetailsBuilder create(RequestDetails from) {
+        RequestDetailsBuilder req = new RequestDetailsBuilder();
+        req.providerId = from.getProviderId();
+        req.clientAttributes = new HashMap<String, String>();
+        req.clientAttributes.putAll(from.getClientAttributes());
+        req.socialAttributes = new HashMap<String, String>();
+        req.socialAttributes.putAll(from.getSocialAttributes());
+        return req;
+    }
+
+    private RequestDetails(String providerId, Map<String, String> clientAttributes, Map<String, String> socialAttributes) {
         this.providerId = providerId;
         this.clientAttributes = clientAttributes;
         this.socialAttributes = socialAttributes;
@@ -52,12 +71,50 @@ public class RequestDetails {
         return clientAttributes;
     }
 
-    public Object getSocialAttribute(String name) {
+    public String getSocialAttribute(String name) {
         return socialAttributes.get(name);
     }
 
-    public Map<String, Object> getSocialAttributes() {
+    public Map<String, String> getSocialAttributes() {
         return socialAttributes;
     }
 
+
+    public static class RequestDetailsBuilder {
+
+        private String providerId;
+
+        private Map<String, String> clientAttributes;
+
+        private Map<String, String> socialAttributes;
+
+        private RequestDetailsBuilder() {
+        }
+
+        public RequestDetailsBuilder putClientAttribute(String name, String value) {
+            clientAttributes.put(name, value);
+            return this;
+        }
+
+        public RequestDetailsBuilder putClientAttributes(Map<String, String> attributes) {
+            clientAttributes.putAll(attributes);
+            return this;
+        }
+
+        public RequestDetailsBuilder putSocialAttribute(String name, String value) {
+            socialAttributes.put(name, value);
+            return this;
+        }
+
+        public RequestDetailsBuilder putSocialAttributes(Map<String, String> attributes) {
+            socialAttributes.putAll(attributes);
+            return this;
+        }
+
+        public RequestDetails build() {
+            return new RequestDetails(providerId, clientAttributes, socialAttributes);
+        }
+
+    }
+
 }
diff --git a/social/core/src/main/java/org/keycloak/social/SocialProviderConfig.java b/social/core/src/main/java/org/keycloak/social/SocialProviderConfig.java
index d6d1276..4989861 100644
--- a/social/core/src/main/java/org/keycloak/social/SocialProviderConfig.java
+++ b/social/core/src/main/java/org/keycloak/social/SocialProviderConfig.java
@@ -50,8 +50,4 @@ public class SocialProviderConfig {
         return secret;
     }
 
-    public void setSecret(String secret) {
-        this.secret = secret;
-    }
-
 }
diff --git a/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookProvider.java b/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookProvider.java
index 2a7b488..ac9bc86 100755
--- a/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookProvider.java
+++ b/social/facebook/src/main/java/org/keycloak/social/facebook/FacebookProvider.java
@@ -4,7 +4,6 @@ import org.jboss.resteasy.client.jaxrs.ResteasyClient;
 import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
 import org.keycloak.social.AuthCallback;
 import org.keycloak.social.AuthRequest;
-import org.keycloak.social.AuthRequestBuilder;
 import org.keycloak.social.SocialProvider;
 import org.keycloak.social.SocialProviderConfig;
 import org.keycloak.social.SocialProviderException;
@@ -45,13 +44,9 @@ public class FacebookProvider implements SocialProvider {
     public AuthRequest getAuthUrl(SocialProviderConfig config) throws SocialProviderException {
         String state = UUID.randomUUID().toString();
 
-        AuthRequestBuilder b = AuthRequestBuilder.create(state, AUTHENTICATION_ENDPOINT_URL).setQueryParam("client_id", config.getKey())
+        return AuthRequest.create(state, AUTHENTICATION_ENDPOINT_URL).setQueryParam("client_id", config.getKey())
                 .setQueryParam("response_type", DEFAULT_RESPONSE_TYPE).setQueryParam("scope", DEFAULT_SCOPE)
-                .setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state);
-
-        b.setAttribute("state", state);
-
-        return b.build();
+                .setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state).setAttribute("state", state).build();
     }
 
     @Override
diff --git a/social/google/src/main/java/org/keycloak/social/google/GoogleProvider.java b/social/google/src/main/java/org/keycloak/social/google/GoogleProvider.java
index 2e2f186..2f743b7 100755
--- a/social/google/src/main/java/org/keycloak/social/google/GoogleProvider.java
+++ b/social/google/src/main/java/org/keycloak/social/google/GoogleProvider.java
@@ -21,6 +21,15 @@
  */
 package org.keycloak.social.google;
 
+import java.util.UUID;
+
+import org.keycloak.social.AuthCallback;
+import org.keycloak.social.AuthRequest;
+import org.keycloak.social.SocialProvider;
+import org.keycloak.social.SocialProviderConfig;
+import org.keycloak.social.SocialProviderException;
+import org.keycloak.social.SocialUser;
+
 import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
 import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
 import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
@@ -29,15 +38,6 @@ import com.google.api.client.json.jackson.JacksonFactory;
 import com.google.api.services.oauth2.Oauth2;
 import com.google.api.services.oauth2.model.Tokeninfo;
 import com.google.api.services.oauth2.model.Userinfo;
-import org.keycloak.social.AuthCallback;
-import org.keycloak.social.AuthRequest;
-import org.keycloak.social.AuthRequestBuilder;
-import org.keycloak.social.SocialProvider;
-import org.keycloak.social.SocialProviderConfig;
-import org.keycloak.social.SocialProviderException;
-import org.keycloak.social.SocialUser;
-
-import java.util.UUID;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -62,14 +62,10 @@ public class GoogleProvider implements SocialProvider {
     @Override
     public AuthRequest getAuthUrl(SocialProviderConfig config) throws SocialProviderException {
         String state = UUID.randomUUID().toString();
-        
-        AuthRequestBuilder b = AuthRequestBuilder.create(state, AUTH_PATH).setQueryParam("client_id", config.getKey())
-                .setQueryParam("response_type", DEFAULT_RESPONSE_TYPE).setQueryParam("scope", DEFAULT_SCOPE)
-                .setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state);
 
-        b.setAttribute("state", state);
-
-        return b.build();
+        return AuthRequest.create(state, AUTH_PATH).setQueryParam("client_id", config.getKey())
+                .setQueryParam("response_type", DEFAULT_RESPONSE_TYPE).setQueryParam("scope", DEFAULT_SCOPE)
+                .setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state).setAttribute("state", state).build();
     }
 
     @Override
diff --git a/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterProvider.java b/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterProvider.java
index 3ba2e04..8f7a508 100755
--- a/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterProvider.java
+++ b/social/twitter/src/main/java/org/keycloak/social/twitter/TwitterProvider.java
@@ -23,7 +23,6 @@ package org.keycloak.social.twitter;
 
 import org.keycloak.social.AuthCallback;
 import org.keycloak.social.AuthRequest;
-import org.keycloak.social.AuthRequestBuilder;
 import org.keycloak.social.SocialProvider;
 import org.keycloak.social.SocialProviderConfig;
 import org.keycloak.social.SocialProviderException;
@@ -50,7 +49,7 @@ public class TwitterProvider implements SocialProvider {
 
             RequestToken requestToken = twitter.getOAuthRequestToken(request.getCallbackUrl());
 
-            return AuthRequestBuilder.create(requestToken.getToken(), requestToken.getAuthenticationURL())
+            return AuthRequest.create(requestToken.getToken(), requestToken.getAuthenticationURL())
                     .setAttribute("token", requestToken.getToken()).setAttribute("tokenSecret", requestToken.getTokenSecret())
                     .build();
         } catch (Exception e) {
diff --git a/testsuite/integration/pom.xml b/testsuite/integration/pom.xml
index 32a0989..ffbe981 100755
--- a/testsuite/integration/pom.xml
+++ b/testsuite/integration/pom.xml
@@ -192,6 +192,10 @@
             <artifactId>selenium-java</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.seleniumhq.selenium</groupId>
+            <artifactId>selenium-chrome-driver</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.mongodb</groupId>
             <artifactId>mongo-java-driver</artifactId>
         </dependency>
diff --git a/testsuite/integration/src/main/resources/log4j.properties b/testsuite/integration/src/main/resources/log4j.properties
index b3c1c5c..bc27773 100644
--- a/testsuite/integration/src/main/resources/log4j.properties
+++ b/testsuite/integration/src/main/resources/log4j.properties
@@ -1,5 +1,7 @@
-log4j.rootLogger=debug, stdout
+log4j.rootLogger=info, stdout
 
 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n
\ No newline at end of file
+log4j.appender.stdout.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] %m%n
+
+log4j.logger.org.keycloak=debug
\ No newline at end of file
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
new file mode 100755
index 0000000..23ac614
--- /dev/null
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/account/ProfileTest.java
@@ -0,0 +1,245 @@
+package org.keycloak.testsuite.account;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpHeaders;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.json.JSONObject;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.keycloak.models.ApplicationModel;
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserModel;
+import org.keycloak.services.managers.RealmManager;
+import org.keycloak.testsuite.Constants;
+import org.keycloak.testsuite.OAuthClient;
+import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
+import org.keycloak.testsuite.pages.LoginPage;
+import org.keycloak.testsuite.pages.OAuthGrantPage;
+import org.keycloak.testsuite.rule.KeycloakRule;
+import org.keycloak.testsuite.rule.WebResource;
+import org.keycloak.testsuite.rule.WebRule;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.WebDriver;
+
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
+import java.net.URI;
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ProfileTest {
+
+    @ClassRule
+    public static KeycloakRule keycloakRule = new KeycloakRule(new KeycloakRule.KeycloakSetup() {
+        @Override
+        public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+            UserModel user = appRealm.getUser("test-user@localhost");
+            user.setFirstName("First");
+            user.setLastName("Last");
+            user.setAttribute("key1", "value1");
+            user.setAttribute("key2", "value2");
+
+            ApplicationModel accountApp = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
+
+            ApplicationModel app = appRealm.getApplicationNameMap().get("test-app");
+            accountApp.addScopeMapping(app.getApplicationUser(), org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE);
+
+            app.getApplicationUser().addWebOrigin("http://localtest.me:8081");
+
+            UserModel thirdParty = appRealm.getUser("third-party");
+            accountApp.addScopeMapping(thirdParty, org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE);
+        }
+    });
+
+    @Rule
+    public WebRule webRule = new WebRule(this);
+
+    @WebResource
+    protected WebDriver driver;
+
+    @WebResource
+    protected OAuthClient oauth;
+
+    @WebResource
+    protected AccountUpdateProfilePage profilePage;
+
+    @WebResource
+    protected LoginPage loginPage;
+
+    @WebResource
+    protected OAuthGrantPage grantPage;
+
+    private List<String> defaultRoles;
+
+    @Test
+    public void getProfile() throws Exception {
+        oauth.doLogin("test-user@localhost", "password");
+
+        String code = oauth.getCurrentQuery().get("code");
+        String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
+
+        HttpResponse response = doGetProfile(token, null);
+        assertEquals(200, response.getStatusLine().getStatusCode());
+        JSONObject profile = new JSONObject(IOUtils.toString(response.getEntity().getContent()));
+
+        assertEquals("test-user@localhost", profile.getString("username"));
+        assertEquals("test-user@localhost", profile.getString("email"));
+        assertEquals("First", profile.getString("firstName"));
+        assertEquals("Last", profile.getString("lastName"));
+
+        JSONObject attributes = profile.getJSONObject("attributes");
+        assertEquals(2, attributes.length());
+        assertEquals("value1", attributes.getString("key1"));
+        assertEquals("value2", attributes.getString("key2"));
+    }
+
+    @Test
+    public void getProfileCors() throws Exception {
+        oauth.doLogin("test-user@localhost", "password");
+
+        String code = oauth.getCurrentQuery().get("code");
+        String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
+
+        driver.navigate().to("http://localtest.me:8081/app");
+
+        String[] response = doGetProfileJs(token);
+        assertEquals("200", response[0]);
+    }
+
+    @Test
+    public void getProfileCorsInvalidOrigin() throws Exception {
+        oauth.doLogin("test-user@localhost", "password");
+
+        String code = oauth.getCurrentQuery().get("code");
+        String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
+
+        driver.navigate().to("http://invalid.localtest.me:8081");
+
+        try {
+            doGetProfileJs(token);
+            fail("Expected failure");
+        } catch (Throwable t) {
+        }
+    }
+
+    @Test
+    public void getProfileCookieAuth() throws Exception {
+        profilePage.open();
+        loginPage.login("test-user@localhost", "password");
+
+        String[] response = doGetProfileJs(null);
+        assertEquals("200", response[0]);
+
+        JSONObject profile = new JSONObject(response[1]);
+        assertEquals("test-user@localhost", profile.getString("username"));
+    }
+
+    @Test
+    public void getProfileNoAuth() throws Exception {
+        HttpResponse response = doGetProfile(null, null);
+        assertEquals(403, response.getStatusLine().getStatusCode());
+    }
+
+    @Test
+    public void getProfileNoAccess() throws Exception {
+        try {
+            keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+                @Override
+                public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                    ApplicationModel app = appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
+                    defaultRoles = app.getDefaultRoles();
+                    app.updateDefaultRoles(new String[0]);
+                }
+            });
+
+            oauth.doLogin("test-user@localhost", "password");
+
+            String code = oauth.getCurrentQuery().get("code");
+            String token = oauth.doAccessTokenRequest(code, "password").getAccessToken();
+
+            HttpResponse response = doGetProfile(token, null);
+            assertEquals(403, response.getStatusLine().getStatusCode());
+        } finally {
+            keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+                @Override
+                public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                    appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION).updateDefaultRoles((String[]) defaultRoles.toArray(new String[0]));
+                }
+            });
+        }
+    }
+
+    @Test
+    public void getProfileOAuthClient() throws Exception {
+        oauth.addScope(org.keycloak.models.Constants.ACCOUNT_APPLICATION, org.keycloak.models.Constants.ACCOUNT_PROFILE_ROLE);
+        oauth.clientId("third-party");
+        oauth.doLoginGrant("test-user@localhost", "password");
+
+        grantPage.accept();
+
+        String token = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get("code"), "password").getAccessToken();
+        HttpResponse response = doGetProfile(token, null);
+
+        assertEquals(200, response.getStatusLine().getStatusCode());
+        JSONObject profile = new JSONObject(IOUtils.toString(response.getEntity().getContent()));
+
+        assertEquals("test-user@localhost", profile.getString("username"));
+    }
+
+    @Test
+    public void getProfileOAuthClientNoScope() throws Exception {
+        oauth.addScope(org.keycloak.models.Constants.ACCOUNT_APPLICATION);
+        oauth.clientId("third-party");
+        oauth.doLoginGrant("test-user@localhost", "password");
+
+        String token = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get("code"), "password").getAccessToken();
+        HttpResponse response = doGetProfile(token, null);
+
+        assertEquals(403, response.getStatusLine().getStatusCode());
+    }
+
+    private URI getAccountURI() {
+        return UriBuilder.fromUri(Constants.AUTH_SERVER_ROOT + "/rest/realms/" + oauth.getRealm() + "/account").build();
+    }
+
+    private HttpResponse doGetProfile(String token, String origin) throws IOException {
+        HttpClient client = new DefaultHttpClient();
+        HttpGet get = new HttpGet(UriBuilder.fromUri(getAccountURI()).build());
+        if (token != null) {
+            get.setHeader(HttpHeaders.AUTHORIZATION, "bearer " + token);
+        }
+        if (origin != null) {
+            get.setHeader("Origin", origin);
+        }
+        get.setHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
+        return client.execute(get);
+    }
+
+    private String[] doGetProfileJs(String token) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("var req = new XMLHttpRequest();\n");
+        sb.append("req.open('GET', '" + getAccountURI().toString() + "', false);\n");
+        if (token != null) {
+            sb.append("req.setRequestHeader('Authorization', 'Bearer " + token + "');\n");
+        }
+        sb.append("req.setRequestHeader('Accept', 'application/json');\n");
+        sb.append("req.send(null);\n");
+        sb.append("return req.status + '///' + req.responseText;\n");
+
+        JavascriptExecutor js = (JavascriptExecutor) driver;
+        String response = (String) js.executeScript(sb.toString());
+        return response.split("///");
+    }
+}
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java
index eca156e..917d047 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionMultipleActionsTest.java
@@ -76,7 +76,7 @@ public class RequiredActionMultipleActionsTest {
     protected LoginUpdateProfilePage updateProfilePage;
 
     @Test
-    public void updateProfileAndPassword() {
+    public void updateProfileAndPassword() throws Exception {
         loginPage.open();
         loginPage.login("test-user@localhost", "password");
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionResetPasswordTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionResetPasswordTest.java
index b8a7b7a..28197d0 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionResetPasswordTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/actions/RequiredActionResetPasswordTest.java
@@ -81,7 +81,7 @@ public class RequiredActionResetPasswordTest {
     protected LoginPasswordUpdatePage changePasswordPage;
 
     @Test
-    public void tempPassword() {
+    public void tempPassword() throws Exception {
         loginPage.open();
         loginPage.login("test-user@localhost", "password");
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocial.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocial.java
index d296498..bab9f43 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocial.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/DummySocial.java
@@ -2,7 +2,6 @@ package org.keycloak.testsuite;
 
 import org.keycloak.social.AuthCallback;
 import org.keycloak.social.AuthRequest;
-import org.keycloak.social.AuthRequestBuilder;
 import org.keycloak.social.SocialProvider;
 import org.keycloak.social.SocialProviderConfig;
 import org.keycloak.social.SocialProviderException;
@@ -23,12 +22,8 @@ public class DummySocial implements SocialProvider {
     public AuthRequest getAuthUrl(SocialProviderConfig config) throws SocialProviderException {
         String state = UUID.randomUUID().toString();
 
-        AuthRequestBuilder b = AuthRequestBuilder.create(state, AUTH_PATH).setQueryParam("response_type", "token")
-                .setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state);
-
-        b.setAttribute("state", state);
-
-        return b.build();
+        return AuthRequest.create(state, AUTH_PATH).setQueryParam("response_type", "token")
+                .setQueryParam("redirect_uri", config.getCallbackUrl()).setQueryParam("state", state).setAttribute("state", state).build();
     }
 
     @Override
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java
index b035945..b38411e 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/AccountTest.java
@@ -21,29 +21,26 @@
  */
 package org.keycloak.testsuite.forms;
 
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.keycloak.models.RealmModel;
-import org.keycloak.models.UserCredentialModel;
-import org.keycloak.models.UserModel;
+import org.apache.http.HttpResponse;
+import org.junit.*;
+import org.keycloak.models.*;
 import org.keycloak.models.utils.TimeBasedOTP;
 import org.keycloak.representations.idm.CredentialRepresentation;
 import org.keycloak.services.managers.RealmManager;
 import org.keycloak.testsuite.OAuthClient;
-import org.keycloak.testsuite.pages.AccountPasswordPage;
-import org.keycloak.testsuite.pages.AccountTotpPage;
-import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
-import org.keycloak.testsuite.pages.AppPage;
+import org.keycloak.testsuite.pages.*;
 import org.keycloak.testsuite.pages.AppPage.RequestType;
-import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.rule.KeycloakRule;
 import org.keycloak.testsuite.rule.KeycloakRule.KeycloakSetup;
 import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.testsuite.rule.WebRule;
 import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.FindBy;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -77,8 +74,13 @@ public class AccountTest {
     @WebResource
     protected AccountTotpPage totpPage;
 
+    @WebResource
+    protected ErrorPage errorPage;
+
     private TimeBasedOTP totp = new TimeBasedOTP();
 
+    private List<String> defaultRoles;
+
     @After
     public void after() {
         keycloakRule.configure(new KeycloakSetup() {
@@ -185,4 +187,31 @@ public class AccountTest {
         Assert.assertTrue(driver.getPageSource().contains("Remove Google"));
     }
 
+    @Test
+    public void changeProfileNoAccess() throws Exception {
+        try {
+            keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+                @Override
+                public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                    ApplicationModel app = appRealm.getApplicationNameMap().get(Constants.ACCOUNT_APPLICATION);
+                    defaultRoles = app.getDefaultRoles();
+                    app.updateDefaultRoles(new String[0]);
+                }
+            });
+
+            profilePage.open();
+            loginPage.login("test-user@localhost", "password");
+
+            Assert.assertTrue(errorPage.isCurrent());
+            Assert.assertEquals("No access", errorPage.getError());
+        } finally {
+            keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
+                @Override
+                public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
+                    appRealm.getApplicationNameMap().get(org.keycloak.models.Constants.ACCOUNT_APPLICATION).updateDefaultRoles((String[]) defaultRoles.toArray(new String[0]));
+                }
+            });
+        }
+    }
+
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
index c637062..a86392b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTotpTest.java
@@ -93,7 +93,7 @@ public class LoginTotpTest {
     }
 
     @Test
-    public void loginWithTotpFailure() {
+    public void loginWithTotpFailure() throws Exception {
         loginPage.open();
         loginPage.login("test-user@localhost", "password");
 
@@ -106,7 +106,7 @@ public class LoginTotpTest {
     }
 
     @Test
-    public void loginWithTotpSuccess() {
+    public void loginWithTotpSuccess() throws Exception {
         loginPage.open();
         loginPage.login("test-user@localhost", "password");
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
index 3a60ae6..e5d7ef6 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OAuthGrantTest.java
@@ -21,13 +21,16 @@
  */
 package org.keycloak.testsuite.oauth;
 
+import java.io.IOException;
+import java.util.Map;
+
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
+import org.keycloak.representations.SkeletonKeyToken;
 import org.keycloak.testsuite.OAuthClient;
-import org.keycloak.testsuite.OAuthGrantServlet;
 import org.keycloak.testsuite.pages.LoginPage;
 import org.keycloak.testsuite.pages.OAuthGrantPage;
 import org.keycloak.testsuite.rule.KeycloakRule;
@@ -35,8 +38,6 @@ import org.keycloak.testsuite.rule.WebResource;
 import org.keycloak.testsuite.rule.WebRule;
 import org.openqa.selenium.WebDriver;
 
-import java.io.IOException;
-
 /**
  * @author <a href="mailto:vrockai@redhat.com">Viliam Rockai</a>
  */
@@ -45,11 +46,6 @@ public class OAuthGrantTest {
     @ClassRule
     public static KeycloakRule keycloakRule = new KeycloakRule();
 
-    @BeforeClass
-    public static void before() {
-        keycloakRule.deployServlet("grant", "/grant", OAuthGrantServlet.class);
-    }
-
     @Rule
     public WebRule webRule = new WebRule(this);
 
@@ -65,28 +61,13 @@ public class OAuthGrantTest {
     @WebResource
     protected OAuthGrantPage grantPage;
 
-    private static String GRANT_APP_URL = "http://localhost:8081/grant/";
-
-    private static String ACCESS_GRANTED = "Access rights granted.";
-    private static String ACCESS_NOT_GRANTED = "Access rights not granted.";
-
     private static String ROLE_USER = "Have User privileges";
     private static String ROLE_CUSTOMER = "Have Customer User privileges";
 
-    private static String GRANT_ROLE = "user";
-    private static String GRANT_APP = "test-app";
-    private static String GRANT_APP_ROLE = "customer-user";
-
     @Test
     public void oauthGrantAcceptTest() throws IOException {
-
-        driver.navigate().to(GRANT_APP_URL);
-
-        Assert.assertFalse(driver.getPageSource().contains(ACCESS_GRANTED));
-        Assert.assertFalse(driver.getPageSource().contains(ACCESS_NOT_GRANTED));
-
-        loginPage.isCurrent();
-        loginPage.login("test-user@localhost", "password");
+        oauth.clientId("third-party");
+        oauth.doLoginGrant("test-user@localhost", "password");
 
         grantPage.assertCurrent();
         Assert.assertTrue(driver.getPageSource().contains(ROLE_USER));
@@ -94,23 +75,50 @@ public class OAuthGrantTest {
 
         grantPage.accept();
 
-        Assert.assertTrue(driver.getPageSource().contains(ACCESS_GRANTED));
-        Assert.assertFalse(driver.getPageSource().contains(ACCESS_NOT_GRANTED));
+        Assert.assertTrue(oauth.getCurrentQuery().containsKey("code"));
+        OAuthClient.AccessTokenResponse accessToken = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get("code"), "password");
+
+        SkeletonKeyToken token = oauth.verifyToken(accessToken.getAccessToken());
 
-        Assert.assertTrue(driver.getPageSource().contains("Role:"+ GRANT_ROLE +"."));
-        Assert.assertTrue(driver.getPageSource().contains("App:"+ GRANT_APP +";"+ GRANT_APP_ROLE +"."));
+        SkeletonKeyToken.Access realmAccess = token.getRealmAccess();
+        Assert.assertEquals(1, realmAccess.getRoles().size());
+        Assert.assertTrue(realmAccess.isUserInRole("user"));
+
+        Map<String,SkeletonKeyToken.Access> resourceAccess = token.getResourceAccess();
+        Assert.assertEquals(1, resourceAccess.size());
+        Assert.assertEquals(1, resourceAccess.get("test-app").getRoles().size());
+        Assert.assertTrue(resourceAccess.get("test-app").isUserInRole("customer-user"));
     }
 
     @Test
-    public void oauthGrantCancelTest() throws IOException {
+    public void oauthGrantAcceptTestWithScope() throws IOException {
+        oauth.addScope("test-app", "customer-user");
+        oauth.clientId("third-party");
+        oauth.doLoginGrant("test-user@localhost", "password");
+
+        grantPage.assertCurrent();
+        Assert.assertTrue(driver.getPageSource().contains(ROLE_CUSTOMER));
+
+        grantPage.accept();
+
+        Assert.assertTrue(oauth.getCurrentQuery().containsKey("code"));
+        OAuthClient.AccessTokenResponse accessToken = oauth.doAccessTokenRequest(oauth.getCurrentQuery().get("code"), "password");
+
+        SkeletonKeyToken token = oauth.verifyToken(accessToken.getAccessToken());
 
-        driver.navigate().to(GRANT_APP_URL);
+        SkeletonKeyToken.Access realmAccess = token.getRealmAccess();
+        Assert.assertNull(realmAccess);
 
-        Assert.assertFalse(driver.getPageSource().contains(ACCESS_GRANTED));
-        Assert.assertFalse(driver.getPageSource().contains(ACCESS_NOT_GRANTED));
+        Map<String,SkeletonKeyToken.Access> resourceAccess = token.getResourceAccess();
+        Assert.assertEquals(1, resourceAccess.size());
+        Assert.assertEquals(1, resourceAccess.get("test-app").getRoles().size());
+        Assert.assertTrue(resourceAccess.get("test-app").isUserInRole("customer-user"));
+    }
 
-        loginPage.isCurrent();
-        loginPage.login("test-user@localhost", "password");
+    @Test
+    public void oauthGrantCancelTest() throws IOException {
+        oauth.clientId("third-party");
+        oauth.doLoginGrant("test-user@localhost", "password");
 
         grantPage.assertCurrent();
         Assert.assertTrue(driver.getPageSource().contains(ROLE_USER));
@@ -118,7 +126,7 @@ public class OAuthGrantTest {
 
         grantPage.cancel();
 
-        Assert.assertFalse(driver.getPageSource().contains(ACCESS_GRANTED));
-        Assert.assertTrue(driver.getPageSource().contains(ACCESS_NOT_GRANTED));
+        Assert.assertTrue(oauth.getCurrentQuery().containsKey("error"));
+        Assert.assertEquals("access_denied", oauth.getCurrentQuery().get("error"));
     }
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
index 4522d9e..c69208f 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/OAuthClient.java
@@ -30,10 +30,14 @@ import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.utils.URLEncodedUtils;
 import org.apache.http.impl.client.DefaultHttpClient;
 import org.apache.http.message.BasicNameValuePair;
+import org.jboss.resteasy.jose.Base64Url;
+import org.jboss.resteasy.jwt.JsonSerialization;
 import org.jboss.resteasy.security.PemUtils;
 import org.json.JSONObject;
 import org.junit.Assert;
 import org.keycloak.RSATokenVerifier;
+import org.keycloak.VerificationException;
+import org.keycloak.representations.SkeletonKeyScope;
 import org.keycloak.representations.SkeletonKeyToken;
 import org.openqa.selenium.By;
 import org.openqa.selenium.WebDriver;
@@ -67,17 +71,21 @@ public class OAuthClient {
 
     private String redirectUri = "http://localhost:8081/app/auth";
 
-    private String scope;
+    private SkeletonKeyScope scope;
 
     private String state;
 
     private PublicKey realmPublicKey;
 
-    public OAuthClient(WebDriver driver) throws Exception {
+    public OAuthClient(WebDriver driver) {
         this.driver = driver;
 
-        JSONObject realmJson = new JSONObject(IOUtils.toString(getClass().getResourceAsStream("/testrealm.json")));
-        realmPublicKey = PemUtils.decodePublicKey(realmJson.getString("publicKey"));
+        try {
+            JSONObject realmJson = new JSONObject(IOUtils.toString(getClass().getResourceAsStream("/testrealm.json")));
+            realmPublicKey = PemUtils.decodePublicKey(realmJson.getString("publicKey"));
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to retrieve realm public key", e);
+        }
     }
 
     public AuthorizationCodeResponse doLogin(String username, String password) {
@@ -90,7 +98,15 @@ public class OAuthClient {
         return new AuthorizationCodeResponse(this);
     }
 
-    public AccessTokenResponse doAccessTokenRequest(String code, String password) throws Exception {
+    public void doLoginGrant(String username, String password) {
+        openLoginForm();
+
+        driver.findElement(By.id("username")).sendKeys(username);
+        driver.findElement(By.id("password")).sendKeys(password);
+        driver.findElement(By.cssSelector("input[type=\"submit\"]")).click();
+    }
+
+    public AccessTokenResponse doAccessTokenRequest(String code, String password) {
         HttpClient client = new DefaultHttpClient();
         HttpPost post = new HttpPost(getAccessTokenUrl());
 
@@ -114,27 +130,19 @@ public class OAuthClient {
         UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters, Charset.forName("UTF-8"));
         post.setEntity(formEntity);
 
-        return new AccessTokenResponse(client.execute(post));
-    }
-
-    public SkeletonKeyToken verifyToken(String token) throws Exception {
-        return RSATokenVerifier.verifyToken(token, realmPublicKey, realm);
-    }
-
-    public boolean isAuthorizationResponse() {
-        return getCurrentRequest().equals(redirectUri) && getCurrentQuery().containsKey("code");
-    }
-
-    public String getState() {
-        return state;
-    }
-
-    public String getClientId() {
-        return clientId;
+        try {
+            return new AccessTokenResponse(client.execute(post));
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to retrieve access token", e);
+        }
     }
 
-    public String getResponseType() {
-        return responseType;
+    public SkeletonKeyToken verifyToken(String token) {
+        try {
+            return RSATokenVerifier.verifyToken(token, realmPublicKey, realm);
+        } catch (VerificationException e) {
+            throw new RuntimeException("Failed to verify token", e);
+        }
     }
 
     public String getCurrentRequest() {
@@ -174,10 +182,6 @@ public class OAuthClient {
         return redirectUri;
     }
 
-    public String getScope() {
-        return scope;
-    }
-
     public String getLoginFormUrl() {
         UriBuilder b = UriBuilder.fromUri(baseUrl + "/realms/" + realm + "/tokens/login");
         if (responseType != null) {
@@ -190,7 +194,12 @@ public class OAuthClient {
             b.queryParam("redirect_uri", redirectUri);
         }
         if (scope != null) {
-            b.queryParam("scope", scope);
+            try {
+
+                b.queryParam("scope", Base64Url.encode(JsonSerialization.toByteArray(scope, false)));
+            } catch (Exception e) {
+                throw new RuntimeException("Failed to serialize scope", e);
+            }
         }
         if (state != null) {
             b.queryParam("state", state);
@@ -223,8 +232,11 @@ public class OAuthClient {
         return this;
     }
 
-    public OAuthClient scope(String scope) {
-        this.scope = scope;
+    public OAuthClient addScope(String resource, String... roles) {
+        if (scope == null) {
+            scope = new SkeletonKeyScope();
+        }
+        scope.addAll(resource, roles);
         return this;
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AbstractPage.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AbstractPage.java
index 1183ece..c17b86a 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AbstractPage.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/pages/AbstractPage.java
@@ -41,6 +41,6 @@ public abstract class AbstractPage {
 
     abstract boolean isCurrent();
 
-    abstract void open();
+    abstract void open() throws Exception;
 
 }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/WebRule.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/WebRule.java
index ae12ea9..ef37e21 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/WebRule.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/rule/WebRule.java
@@ -54,6 +54,7 @@ public class WebRule extends ExternalResource {
 
         if (browser.equals("htmlunit")) {
             HtmlUnitDriver d = new HtmlUnitDriver();
+            d.getWebClient().getOptions().setJavaScriptEnabled(true);
             d.getWebClient().getOptions().setCssEnabled(false);
             driver = d;
         } else if (browser.equals("chrome")) {
diff --git a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java
index ece002b..12fced6 100755
--- a/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java
+++ b/testsuite/performance/src/test/java/org/keycloak/testsuite/performance/CreateUsersWorker.java
@@ -78,13 +78,6 @@ public class CreateUsersWorker implements Worker {
             user.setEmail(username + "@email.com");
         }
 
-        // Adding default roles of realm to user
-        if (addDefaultRoles) {
-            for (RoleModel role : realm.getDefaultRoles()) {
-                realm.grantRole(user, role);
-            }
-        }
-
         // Creating password (will be same as username)
         if (addPassword) {
             UserCredentialModel password = new UserCredentialModel();