diff --git a/.docker/dockerfiles/develop/Dockerfile b/.docker/dockerfiles/develop/Dockerfile
index bbce2753d91daf01b6b15a8e2c6df8c2e4eb93ef..5707cfbc01710ce9ad5467f50802aefeabc3ee10 100644
--- a/.docker/dockerfiles/develop/Dockerfile
+++ b/.docker/dockerfiles/develop/Dockerfile
@@ -2,10 +2,6 @@ FROM node:0.10
 
 MAINTAINER buildmaster@rocket.chat
 
-RUN apt-get update \
-&&  apt-get install -y graphicsmagick \
-&&  rm -rf /var/lib/apt/lists/*
-
 RUN groupadd -r rocketchat \
 &&  useradd -r -g rocketchat rocketchat \
 &&  mkdir /app  \
@@ -16,7 +12,7 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB
 
 WORKDIR /app
 
-RUN curl -fSL "https://s3.amazonaws.com/build/rocket.chat-develop.tgz" -o rocket.chat.tgz \
+RUN curl -fSL https://rocket.chat/releases/develop/download -o rocket.chat.tgz \
 &&  tar zxvf ./rocket.chat.tgz \
 &&  rm ./rocket.chat.tgz  \
 &&  cd /app/bundle/programs/server \
diff --git a/.docker/dockerfiles/latest/Dockerfile b/.docker/dockerfiles/latest/Dockerfile
index 296f2e76dc47f3b3ded90bedb37a988abd7b5292..ed09ceb5bf895a4b96a451f44706d635a79503de 100644
--- a/.docker/dockerfiles/latest/Dockerfile
+++ b/.docker/dockerfiles/latest/Dockerfile
@@ -12,10 +12,7 @@ RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EB
 
 WORKDIR /app
 
-RUN URL="https://builds.rocket.chat/releases/latest" \
-&&  FILE="/rocket.chat.tgz" \
-&&  HEADER=$(curl -I -s "$URL" | grep -Fi Location: | sed -En 's/.*(https?:\/\/[a-zA-Z0-9\/.-_]*).*$/\1/p' | sed 's/\/tag\//\/download\//' ) \
-&&  curl -fSL "$HEADER$FILE" -o rocket.chat.tgz \
+RUN curl -fSL https://rocket.chat/releases/latest/download -o rocket.chat.tgz \
 &&  tar zxvf ./rocket.chat.tgz \
 &&  rm ./rocket.chat.tgz  \
 &&  cd /app/bundle/programs/server \
diff --git a/.meteor/versions b/.meteor/versions
index a894cf14bf30a7604d1346a0a653af74c4663071..18a8a4d48ade916b58a45db71e468a26d6f8dfc5 100644
--- a/.meteor/versions
+++ b/.meteor/versions
@@ -6,7 +6,6 @@ accounts-meteor-developer@1.0.6
 accounts-oauth@1.1.8
 accounts-password@1.1.4
 accounts-twitter@1.0.6
-alanning:roles@1.2.14
 aldeed:simple-schema@1.5.3
 arunoda:streams@0.1.17
 autoupdate@1.2.4
@@ -148,7 +147,7 @@ rocketchat:mentions-flextab@0.0.1
 rocketchat:message-attachments@0.0.1
 rocketchat:message-pin@0.0.1
 rocketchat:message-star@0.0.1
-rocketchat:oauth2-server@1.1.1
+rocketchat:oauth2-server@1.2.0
 rocketchat:oauth2-server-config@1.0.0
 rocketchat:oembed@0.0.1
 rocketchat:slashcommands-invite@0.0.1
diff --git a/.travis/docker.sh b/.travis/docker.sh
index 84eb7f7463d50a4fe0197d55ff43dacf5ead8314..1982a9ef008e439d7d7a6ffc47c68ee718f1f824 100755
--- a/.travis/docker.sh
+++ b/.travis/docker.sh
@@ -7,7 +7,7 @@ CURL_URL="https://registry.hub.docker.com/u/rocketchat/rocket.chat/trigger/$PUSH
 if [[ -v "$TRAVIS_TAG" ]]; then
   CURL_DATA='{"source_type":"Tag","source_name":"'"$TRAVIS_TAG"'"}';
 else
-  CURL_DATA='{"docker_tag":"develop"}';
+  CURL_DATA='{"source_type":"Branch","source_name":"develop"}';
 fi
 
 curl -H "Content-Type: application/json" --data "$CURL_DATA" -X POST "$CURL_URL"
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 72c9a4ea913eb89a7389de95601e7d297e894221..0000000000000000000000000000000000000000
--- a/Dockerfile
+++ /dev/null
@@ -1,36 +0,0 @@
-FROM node:0.10
-
-MAINTAINER buildmaster@rocket.chat
-
-RUN groupadd -r rocketchat \
-&&  useradd -r -g rocketchat rocketchat \
-&&  mkdir /app  \
-&&  mkdir /app/uploads
-
-# gpg: key 4FD08014: public key "Rocket.Chat Buildmaster <buildmaster@rocket.chat>" imported
-RUN gpg --keyserver ha.pool.sks-keyservers.net --recv-keys 0E163286C20D07B9787EBE9FD7F9D0414FD08104
-
-WORKDIR /app
-
-RUN URL="https://github.com/RocketChat/Rocket.Chat/releases/latest" \
-&&  FILE="/rocket.chat.tgz" \
-&&  HEADER=$(curl -I -s "$URL" | grep -Fi Location: | sed -En 's/.*(https?:\/\/[a-zA-Z0-9\/.-_]*).*$/\1/p' | sed 's/\/tag\//\/download\//' ) \
-&&  curl -fSL "$HEADER$FILE" -o rocket.chat.tgz \
-&&  tar zxvf ./rocket.chat.tgz \
-&&  rm ./rocket.chat.tgz  \
-&&  cd /app/bundle/programs/server \
-&&  npm install
-
-USER rocketchat
-
-VOLUME /app/uploads
-WORKDIR /app/bundle
-
-# needs a mongoinstance - defaults to container linking with alias 'mongo'
-ENV MONGO_URL=mongodb://mongo:27017/rocketchat \
-    PORT=3000 \
-    ROOT_URL=http://localhost:3000 \
-    Accounts_AvatarStorePath=/app/uploads
-
-EXPOSE 3000
-CMD ["node", "main.js"]
diff --git a/HISTORY.md b/HISTORY.md
index 625dae07616436eec88a0ce6d7775b6eb7930b60..a1e5feccfb9f774d5b501465e11cd9ce0b3cac93 100644
--- a/HISTORY.md
+++ b/HISTORY.md
@@ -1,7 +1,12 @@
-## v.NEXT
+## NEXT
 
+-
 
-## v0.12.0, 2016-Jan-04
+## 0.12.1, 2016-Jan-05
+
+- Fix problem with middleware that tries to parse json body
+
+## 0.12.0, 2016-Jan-04
 
 - Settings: unset section if none is given on update
 - Hide registration and forgot password links when hidding login form
@@ -19,7 +24,7 @@
 - Try to parse all request bodies as JSON
 - New password reset screen
 
-## v0.11.0, 2015-Dec-28
+## 0.11.0, 2015-Dec-28
 
 - Add role bot to users of integrations in scope bot
 - Add route to cadastre new integrations via API
@@ -62,15 +67,15 @@
 - Turn channel and triggerWords optional in triggers
 - Using branding image from main APP
 
-## v0.10.2, 2015-Dec-22
+## 0.10.2, 2015-Dec-22
 
 - Fixes image preview bugs with filenames containing spaces
 
-## v0.10.1, 2015-Dec-21
+## 0.10.1, 2015-Dec-21
 
 - Fix upload permissions introduced in raik:ufs 0.3.4
 
-## v0.10.0, 2015-Dec-21
+## 0.10.0, 2015-Dec-21
 
 - Accept property *msg* as text in attachments
 - Add "Room has been deleted" entry
@@ -170,7 +175,7 @@
 - Use attachments to render preview of uploads and use relative paths
 - Using flow-router group routes
 
-## v0.9.0, 2015-Dec-14
+## 0.9.0, 2015-Dec-14
 
 - Fix broken image-link when og:image contains "&amp;" (e.g. Google Maps)
 - Error message when file upload media type it not accepted
@@ -212,7 +217,7 @@
 - Fixed blockquote non-continous border
 - Moved accountBox HTML to new separated template
 
-## v0.8.0, 2015-Dec-8
+## 0.8.0, 2015-Dec-8
 
 - Fixed error: when allow change username was set to false, registration
 - Improve message rendering removing MessageAction from render time
@@ -243,6 +248,6 @@
 - Clear iOS app badge on app startup
 - Fix for image swipebox to show in RTL interface
 
-## v0.1.0, 2015-May-19
+## 0.1.0, 2015-May-19
 
 - Initial public launch
diff --git a/client/startup/startup.coffee b/client/startup/startup.coffee
index f7043af49469bccef656de087027c9970acd8a41..ed209ee71b3bc758fac84fb479c923fe394c2a1e 100644
--- a/client/startup/startup.coffee
+++ b/client/startup/startup.coffee
@@ -24,6 +24,9 @@ Meteor.startup ->
 	loadedLaguages = []
 
 	@setLanguage = (language) ->
+		if !language
+			return
+
 		if loadedLaguages.indexOf(language) > -1
 			return
 
diff --git a/docker-compose.yml b/docker-compose.yml
index 33a72bd0126ab9835c1d98fb8b07fdb1c7dc6ba1..2637c3c86a24cae08c2ba61cee9b63c0a86d2d5b 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -13,8 +13,6 @@ rocketchat:
     - PORT=3000
     - ROOT_URL=http://yourhost:3000
     - MONGO_URL=mongodb://mongo:27017/rocketchat
-# uncomment and set the line below if you need to support mobile apps
-#   - DDP_DEFAULT_CONNECTION_URL=http://yourhost:3000
   links:
     - mongo:mongo
   ports:
@@ -24,7 +22,7 @@ rocketchat:
 hubot:
   image: rocketchat/hubot-rocketchat
   environment:
-    - ROCKETCHAT_URL=yourhost:3000
+    - ROCKETCHAT_URL=rocketchat:3000
     - ROCKETCHAT_ROOM=GENERAL
     - ROCKETCHAT_USER=bot
     - ROCKETCHAT_PASSWORD=botpassword
diff --git a/i18n/en.i18n.json b/i18n/en.i18n.json
index 6c2d6a8f75653941ae9800c116262b4c895a2b77..482eea38ba63c201b36a90bd8004bef036c8e6ca 100644
--- a/i18n/en.i18n.json
+++ b/i18n/en.i18n.json
@@ -2,6 +2,7 @@
   "Access_not_authorized" : "Access not authorized",
   "Access_online_demo" : "Access the online demo",
   "Access_Online_Demo" : "Access the Online Demo",
+  "Access_Token_URL" : "Access Token URL",
   "Accounts" : "Accounts",
   "Accounts_AllowedDomainsList" : "Allowed Domains List",
   "Accounts_AllowedDomainsList_Description" : "Comma-separated list of allowed domains",
@@ -86,6 +87,7 @@
   "are_also_typing" : "are also typing",
   "are_typing" : "are typing",
   "Are_you_sure" : "Are you sure?",
+  "Authorization_URL" : "Authorization URL",
   "Auto_Load_Images" : "Auto Load Images",
   "Avatar_changed_successfully" : "Avatar changed successfully",
   "Avatar_URL" : "Avatar URL",
diff --git a/packages/rocketchat-authorization/README.md b/packages/rocketchat-authorization/README.md
index 239b085c856dc0d1280af7d604b5f5a40c2d2eb7..c2365d83f6986f4c0c0b0889aa1f4c9b147942c3 100644
--- a/packages/rocketchat-authorization/README.md
+++ b/packages/rocketchat-authorization/README.md
@@ -1,6 +1,6 @@
-Supports role or permission based authorization, and defines the association between them. 
+Supports role or permission based authorization, and defines the association between them.
 
-A user is associated with role(s), and a role is associated with permission(s).  This package depends on alanning:roles for the role/user association, while the role/permission association is handled internally.  Thus, the underlying alanning:roles has no concept of a permission or the association between a role and permission.   
+A user is associated with role(s), and a role is associated with permission(s).  This package depends on alanning:roles for the role/user association, while the role/permission association is handled internally.  Thus, the underlying alanning:roles has no concept of a permission or the association between a role and permission.
 
 Authorization checks can be done based on a role or permission.  However, permission based checks are preferred because they loosely associate an action with a role.  For example:
 
@@ -19,13 +19,12 @@ if hasRole(userId, ['admin','site-moderator','moderator'])
 
 Usage:
 ```
-# assign user to moderator role.  Permissions scoped globally
-# user can moderate (e.g. edit channel name, delete private group message) for all rooms
-RocketChat.authz.addUsersToRoles(userId, 'moderator')
+# assign user to admin role.  Permissions scoped globally
+RocketChat.authz.addUserRoles(userId, 'admin')
 
 # assign user to moderator role.  Permissions scoped to the specified room
 # user can moderate (e.g. edit channel name, delete private group message) for only one room specified by the roomId
-RocketChat.authz.addUsersToRoles(userId, 'moderator', roomId )
+RocketChat.authz.addUserRoles(userId, 'moderator', roomId )
 
 # check if user can modify message for any room
 RocketChat.authz.hasPermission(userId, 'edit-message')
@@ -37,5 +36,5 @@ RocketChat.authz.hasPermission(userId, 'edit-message', roomId)
 
 Notes:
 1. Roles are statically defined.  UI needs to be implemented to dynamically assign permission(s) to a Role
-2. 'admin', 'moderator', 'user' role identifiers should NOT be changed (unless you update the associated code) because they are referenced when creating users and creating rooms.  
-3. edit, delete message permissions are at either the global or room scope.  i.e. role with edit-message with GLOBAL scope can edit ANY message regardless of the room type.  However, role with edit-message with room scope can only edit messages for the room.  The global scope is associated with the admin role while the "room-scoped" permission is assigned to the room "moderator" (room creator).  If we want a middle ground that allows for edit-message for only channel/group/direct, then we need to create individual edit-c-message, edit-p-message, edit-d-message permissions. 
+2. 'admin', 'moderator', 'user' role identifiers should NOT be changed (unless you update the associated code) because they are referenced when creating users and creating rooms.
+3. edit, delete message permissions are at either the global or room scope.  i.e. role with edit-message with GLOBAL scope can edit ANY message regardless of the room type.  However, role with edit-message with room scope can only edit messages for the room.  The global scope is associated with the admin role while the "room-scoped" permission is assigned to the room "moderator" (room creator).  If we want a middle ground that allows for edit-message for only channel/group/direct, then we need to create individual edit-c-message, edit-p-message, edit-d-message permissions.
diff --git a/packages/rocketchat-authorization/client/hasPermission.coffee b/packages/rocketchat-authorization/client/hasPermission.coffee
index 9d636b9552e7bc47ebb78e80fbb66b60af6a75c1..015ec854ee72935b6bc854010e417cc3f31b1973 100644
--- a/packages/rocketchat-authorization/client/hasPermission.coffee
+++ b/packages/rocketchat-authorization/client/hasPermission.coffee
@@ -1,25 +1,29 @@
-atLeastOne = (toFind, toSearch) ->
-	console.log 'toFind: ', toFind if window.rocketDebug
-	console.log 'toSearch: ', toSearch if window.rocketDebug
-	return  not _.isEmpty(_.intersection(toFind, toSearch))
-
-all = (toFind, toSearch) ->
-	toFind = _.uniq(toFind)
-	toSearch = _.uniq(toSearch)
-	return _.isEmpty( _.difference( toFind, toSearch))
+atLeastOne = (permissions, scope) ->
+	return _.some permissions, (permissionId) ->
+		permission = ChatPermissions.findOne permissionId
+		return _.some permission.roles, (roleName) ->
+			role = RocketChat.models.Roles.findOne roleName
+			roleScope = role?.scope
+			return RocketChat.models[roleScope]?.isUserInRole?(Meteor.userId(), roleName, scope)
+
+all = (permissions, scope) ->
+	return _.every permissions, (permissionId) ->
+		permission = ChatPermissions.findOne permissionId
+		return _.some permission.roles, (roleName) ->
+			role = RocketChat.models.Roles.findOne roleName
+			roleScope = role?.scope
+			return RocketChat.models[roleScope]?.isUserInRole?(Meteor.userId(), roleName, scope)
 
 Template.registerHelper 'hasPermission', (permission, scope) ->
-	unless _.isString( scope )
-		scope = Roles.GLOBAL_GROUP
-	return hasPermission( permission, scope, atLeastOne)
+	return hasPermission(permission, scope, atLeastOne)
 
-RocketChat.authz.hasAllPermission = (permissions, scope=Roles.GLOBAL_GROUP) ->
-	return hasPermission( permissions, scope, all )
+RocketChat.authz.hasAllPermission = (permissions, scope) ->
+	return hasPermission(permissions, scope, all)
 
-RocketChat.authz.hasAtLeastOnePermission = (permissions, scope=Roles.GLOBAL_GROUP) ->
+RocketChat.authz.hasAtLeastOnePermission = (permissions, scope) ->
 	return hasPermission(permissions, scope, atLeastOne)
 
-hasPermission = (permissions, scope=Roles.GLOBAL_GROUP, strategy) ->
+hasPermission = (permissions, scope, strategy) ->
 	userId = Meteor.userId()
 
 	unless userId
@@ -30,10 +34,4 @@ hasPermission = (permissions, scope=Roles.GLOBAL_GROUP, strategy) ->
 
 	permissions = [].concat permissions
 
-	roleNames = Roles.getRolesForUser(userId, scope)
-
-	userPermissions = []
-	for roleName in roleNames
-		userPermissions = userPermissions.concat(_.pluck(ChatPermissions.find({roles : roleName }).fetch(), '_id'))
-
-	return strategy( permissions, userPermissions)
+	return strategy(permissions, scope)
diff --git a/packages/rocketchat-authorization/client/hasRole.coffee b/packages/rocketchat-authorization/client/hasRole.coffee
index 3140a74bfe635cfc05d6ec20b8c59f4eb84f67bd..aff335e48b2fd0f7ae37fce3f2d00bb98796124c 100644
--- a/packages/rocketchat-authorization/client/hasRole.coffee
+++ b/packages/rocketchat-authorization/client/hasRole.coffee
@@ -1,8 +1,3 @@
-RocketChat.authz.hasRole = (userId, roleName, scope=Roles.GLOBAL_GROUP) ->
-	unless Meteor.userId()
-		return false
-
-	roleName = [].concat roleName
-
-	# per alanning:roles, returns true if user is in ANY roles
-	return Roles.userIsInRole(userId, roleName, scope)
+RocketChat.authz.hasRole = (userId, roleNames, scope) ->
+	roleNames = [].concat roleNames
+	return RocketChat.models.Roles.isUserInRoles(userId, roleNames, scope) # true if user is in ANY role
diff --git a/packages/rocketchat-authorization/client/collection.coffee b/packages/rocketchat-authorization/client/lib/ChatPermissions.coffee
similarity index 96%
rename from packages/rocketchat-authorization/client/collection.coffee
rename to packages/rocketchat-authorization/client/lib/ChatPermissions.coffee
index b719f7f9ed648c4d5df0d16de2fd541787017d97..e9adaae10f2f65de5c9d31f3283895af25ec4649 100644
--- a/packages/rocketchat-authorization/client/collection.coffee
+++ b/packages/rocketchat-authorization/client/lib/ChatPermissions.coffee
@@ -1 +1 @@
-@ChatPermissions = new Meteor.Collection 'rocketchat_permissions'
\ No newline at end of file
+@ChatPermissions = new Meteor.Collection 'rocketchat_permissions'
diff --git a/packages/rocketchat-authorization/client/lib/models/Roles.coffee b/packages/rocketchat-authorization/client/lib/models/Roles.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..5d94d584c613bbc6d950efde4d3c28314197c5e9
--- /dev/null
+++ b/packages/rocketchat-authorization/client/lib/models/Roles.coffee
@@ -0,0 +1,14 @@
+RocketChat.models.Roles = new Meteor.Collection 'rocketchat_roles'
+
+RocketChat.models.Roles.findUsersInRole = (name, scope, options) ->
+	role = @findOne name
+	roleScope = role?.scope or 'Users'
+	RocketChat.models[roleScope]?.findUsersInRoles?(name, scope, options)
+
+RocketChat.models.Roles.isUserInRoles = (userId, roles, scope) ->
+	roles = [].concat roles
+	_.some roles, (roleName) =>
+		role = @findOne roleName
+		roleScope = role?.scope or 'Users'
+		return RocketChat.models[roleScope]?.isUserInRole?(userId, roleName, scope)
+
diff --git a/packages/rocketchat-authorization/client/lib/models/Subscriptions.js b/packages/rocketchat-authorization/client/lib/models/Subscriptions.js
new file mode 100644
index 0000000000000000000000000000000000000000..7ff02a801037048cd704df777f0a559dce497751
--- /dev/null
+++ b/packages/rocketchat-authorization/client/lib/models/Subscriptions.js
@@ -0,0 +1,35 @@
+Meteor.subscribe('scopedRoles', 'Subscriptions');
+
+if (_.isUndefined(RocketChat.models.Subscriptions)) {
+	RocketChat.models.Subscriptions = {}
+}
+
+RocketChat.models.Subscriptions.isUserInRole = function(userId, roleName, roomId) {
+	query = {
+		rid: roomId,
+		roles: roleName
+	};
+
+	return !_.isUndefined(this.findOne(query));
+}
+
+RocketChat.models.Subscriptions.findUsersInRoles = function(roles, scope, options) {
+	roles = [].concat(roles);
+
+	var query = {
+		roles: { $in: roles }
+	}
+
+	if (scope) {
+		query.rid = scope;
+	}
+
+	subscriptions = this.find(query).fetch();
+
+	users = _.compact(_.map(subscriptions, function(subscription) {
+		if ('undefined' !== typeof subscription.u && 'undefined' !== typeof subscription.u._id)
+			return subscription.u._id
+	}));
+
+	return RocketChat.models.Users.find({ _id: { $in: users } }, options);
+}
diff --git a/packages/rocketchat-authorization/client/lib/models/Users.js b/packages/rocketchat-authorization/client/lib/models/Users.js
new file mode 100644
index 0000000000000000000000000000000000000000..e7f61495105807867555a801164b9265caf04dcc
--- /dev/null
+++ b/packages/rocketchat-authorization/client/lib/models/Users.js
@@ -0,0 +1,24 @@
+Meteor.subscribe('scopedRoles', 'Users');
+
+if (_.isUndefined(RocketChat.models.Users)) {
+	RocketChat.models.Users = {}
+}
+
+RocketChat.models.Users.isUserInRole = function(userId, roleName) {
+	query = {
+		_id: userId,
+		roles: roleName
+	};
+
+	return !_.isUndefined(this.findOne(query));
+}
+
+RocketChat.models.Users.findUsersInRoles = function(roles, scope, options) {
+	roles = [].concat(roles);
+
+	var query = {
+		roles: { $in: roles }
+	}
+
+	return this.find(query, options);
+}
diff --git a/packages/rocketchat-authorization/client/startup.coffee b/packages/rocketchat-authorization/client/startup.coffee
index 144f7ea88f9ae3f0735cec28551a19b7085bcc5e..61f0527598d0fe448a263d6f5c9d82ca8d390b88 100644
--- a/packages/rocketchat-authorization/client/startup.coffee
+++ b/packages/rocketchat-authorization/client/startup.coffee
@@ -1,3 +1,5 @@
+Meteor.subscribe 'roles'
+
 RocketChat.authz.subscription = Meteor.subscribe 'permissions'
 
 RocketChat.AdminBox.addOption
diff --git a/packages/rocketchat-authorization/client/views/permissions.coffee b/packages/rocketchat-authorization/client/views/permissions.coffee
index 0e134582401e8e84e1224610ec2572324770ec6c..af92f2c126605ba8bacee8042285ef1fd42c6d01 100644
--- a/packages/rocketchat-authorization/client/views/permissions.coffee
+++ b/packages/rocketchat-authorization/client/views/permissions.coffee
@@ -8,7 +8,7 @@ Template.permissions.helpers
 
 	granted: (roles) ->
 		if roles?
-			return 'checked' if roles.indexOf(@name) isnt -1
+			return 'checked' if roles.indexOf(@_id) isnt -1
 
 	hasPermission: ->
 		return RocketChat.authz.hasAllPermission 'access-permissions'
@@ -31,18 +31,14 @@ Template.permissions.onCreated ->
 		added: {}
 		removed: {}
 
-	subs = @subscribe 'roles'
-
 	Tracker.autorun =>
-		if subs.ready()
-			@roles.set Roles.getAllRoles().fetch()
+		@roles.set RocketChat.models.Roles.find().fetch()
 
 	Tracker.autorun =>
-		if subs.ready()
-			ChatPermissions.find().observeChanges
-				added: (id, fields) =>
-					@permissionByRole[id] = fields.roles
-				changed: (id, fields) =>
-					@permissionByRole[id] = fields.roles
-				removed: (id) =>
-					delete @permissionByRole[id]
+		ChatPermissions.find().observeChanges
+			added: (id, fields) =>
+				@permissionByRole[id] = fields.roles
+			changed: (id, fields) =>
+				@permissionByRole[id] = fields.roles
+			removed: (id) =>
+				delete @permissionByRole[id]
diff --git a/packages/rocketchat-authorization/client/views/permissions.html b/packages/rocketchat-authorization/client/views/permissions.html
index f95b309f24a35ed785388c21c8971469c6462fa3..c895fea4c2de67b038350d2e55c73b41b3e1c2b8 100644
--- a/packages/rocketchat-authorization/client/views/permissions.html
+++ b/packages/rocketchat-authorization/client/views/permissions.html
@@ -9,8 +9,8 @@
 						<td>&nbsp;</td>
 						{{#each role}}
 							<td title="{{description}}">
-								<a href="{{pathFor "admin-permissions-edit" name=name}}">
-									{{name}}
+								<a href="{{pathFor "admin-permissions-edit" name=_id}}">
+									{{_id}}
 									<i class="icon-edit"></i>
 								</a>
 							</td>
@@ -23,7 +23,7 @@
 							<td>{{_id}}</td>
 							{{#each role}}
 								<td>
-									<input type="checkbox" name="perm[{{_id}}][{{../_id}}]" class="role-permission" value="1" checked="{{granted ../roles ../_id}}" data-role="{{name}}" data-permission="{{../_id}}">
+									<input type="checkbox" name="perm[{{_id}}][{{../_id}}]" class="role-permission" value="1" checked="{{granted ../roles}}" data-role="{{_id}}" data-permission="{{../_id}}">
 								</td>
 							{{/each}}
 						</tr>
diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.coffee b/packages/rocketchat-authorization/client/views/permissionsRole.coffee
index bb754ced89c9a40911c5882ca11318aa6b5dbda2..739fa26afada48c8d0a1c6b219db572a6e36e3ba 100644
--- a/packages/rocketchat-authorization/client/views/permissionsRole.coffee
+++ b/packages/rocketchat-authorization/client/views/permissionsRole.coffee
@@ -1,6 +1,6 @@
 Template.permissionsRole.helpers
 	role: ->
-		return Meteor.roles.findOne({ name: FlowRouter.getParam('name') }) or {}
+		return RocketChat.models.Roles.findOne({ _id: FlowRouter.getParam('name') }) or {}
 
 	userInRole: ->
 		return Template.instance().usersInRole
@@ -108,4 +108,4 @@ Template.permissionsRole.onCreated ->
 	@subscribe 'roles', FlowRouter.getParam('name')
 	@subscribe 'usersInRole', FlowRouter.getParam('name')
 
-	@usersInRole = Roles.getUsersInRole(FlowRouter.getParam('name'), Roles.GLOBAL_GROUP, { sort: { username: 1 } })
+	@usersInRole = RocketChat.models.Roles.findUsersInRole(FlowRouter.getParam('name'), null, { sort: { username: 1 } })
diff --git a/packages/rocketchat-authorization/client/views/permissionsRole.html b/packages/rocketchat-authorization/client/views/permissionsRole.html
index a824390e886680a18e37f6fc3df8c3021b91c77f..18382fdb3c6a805a096fbfc4c7eec6e780c0b20c 100644
--- a/packages/rocketchat-authorization/client/views/permissionsRole.html
+++ b/packages/rocketchat-authorization/client/views/permissionsRole.html
@@ -7,7 +7,7 @@
 				<form id="form-role" class="inline form-role">
 					<label>{{_ "Role"}} :</label>
 						{{#if editing}}
-							<span>{{name}}</span>
+							<span>{{_id}}</span>
 						{{else}}
 							<input type="text" name="name" value="">
 						{{/if}}
diff --git a/packages/rocketchat-authorization/package.js b/packages/rocketchat-authorization/package.js
index 62fa6b7fe6460f2a5bcab13eca032473bd73801f..69682e47db333201648a31e4c0ff64e69936b27d 100644
--- a/packages/rocketchat-authorization/package.js
+++ b/packages/rocketchat-authorization/package.js
@@ -11,18 +11,22 @@ Package.onUse(function(api) {
   api.use([
     'coffeescript',
     'underscore',
-    'rocketchat:lib',
-    'alanning:roles@1.2.12'
+    'rocketchat:lib'
     ]);
 
-  api.use('mongo', 'client');
+  api.use('mongo', ['client', 'server']);
   api.use('kadira:flow-router', 'client');
   api.use('less@2.5.1', 'client');
+  api.use('tracker', 'client');
 
   api.use('templating', 'client');
 
   api.addFiles('lib/rocketchat.coffee', ['server','client']);
-  api.addFiles('client/collection.coffee', ['client']);
+  api.addFiles('client/lib/ChatPermissions.coffee', ['client']);
+  api.addFiles('client/lib/models/Roles.coffee', ['client']);
+  api.addFiles('client/lib/models/Users.js', ['client']);
+  api.addFiles('client/lib/models/Subscriptions.js', ['client']);
+
   api.addFiles('client/startup.coffee', ['client']);
   api.addFiles('client/hasPermission.coffee', ['client']);
   api.addFiles('client/hasRole.coffee', ['client']);
@@ -39,19 +43,22 @@ Package.onUse(function(api) {
   api.addFiles('client/stylesheets/permissions.less', 'client');
 
   api.addFiles('server/models/Permissions.coffee', ['server']);
+  api.addFiles('server/models/Roles.coffee', ['server']);
+  api.addFiles('server/models/Base.js', ['server']);
+  api.addFiles('server/models/Users.js', ['server']);
+  api.addFiles('server/models/Subscriptions.js', ['server']);
 
-  api.addFiles('server/functions/addUsersToRoles.coffee', ['server']);
-  api.addFiles('server/functions/getPermissionsForRole.coffee', ['server']);
+  api.addFiles('server/functions/addUserRoles.coffee', ['server']);
   api.addFiles('server/functions/getRoles.coffee', ['server']);
-  api.addFiles('server/functions/getRolesForUser.coffee', ['server']);
   api.addFiles('server/functions/getUsersInRole.coffee', ['server']);
   api.addFiles('server/functions/hasPermission.coffee', ['server']);
   api.addFiles('server/functions/hasRole.coffee', ['server']);
-  api.addFiles('server/functions/removeUsersFromRoles.coffee', ['server']);
+  api.addFiles('server/functions/removeUserFromRoles.coffee', ['server']);
 
   // publications
-  api.addFiles('server/publication.coffee', ['server']);
+  api.addFiles('server/publications/permissions.js', 'server');
   api.addFiles('server/publications/roles.coffee', 'server');
+  api.addFiles('server/publications/scopedRoles.js', 'server');
   api.addFiles('server/publications/usersInRole.coffee', 'server');
 
   // methods
diff --git a/packages/rocketchat-authorization/server/functions/addUserRoles.coffee b/packages/rocketchat-authorization/server/functions/addUserRoles.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..c715153ce326174249ddba7290f2051551558997
--- /dev/null
+++ b/packages/rocketchat-authorization/server/functions/addUserRoles.coffee
@@ -0,0 +1,19 @@
+RocketChat.authz.addUserRoles = (userId, roleNames, scope) ->
+	if not userId or not roleNames
+		return false
+
+	user = RocketChat.models.Users.findOneById(userId)
+	if not user
+		throw new Meteor.Error 'invalid-user'
+
+	roleNames = [].concat roleNames
+
+	existingRoleNames = _.pluck(RocketChat.authz.getRoles(), '_id')
+	invalidRoleNames = _.difference(roleNames, existingRoleNames)
+	unless _.isEmpty(invalidRoleNames)
+		for role in invalidRoleNames
+			RocketChat.models.Roles.createOrUpdate role
+
+	RocketChat.models.Roles.addUserRoles(userId, roleNames, scope)
+
+	return true
diff --git a/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee b/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee
deleted file mode 100644
index ac2be57a5460073b5263534400897f2e5f033fee..0000000000000000000000000000000000000000
--- a/packages/rocketchat-authorization/server/functions/addUsersToRoles.coffee
+++ /dev/null
@@ -1,27 +0,0 @@
-RocketChat.authz.addUsersToRoles = (userIds, roleNames, scope ) ->
-	if not userIds or not roleNames
-		return false
-
-	unless _.isArray(userIds)
-		userIds = [userIds]
-
-	users = Meteor.users.find({_id: {$in : userIds}}).fetch()
-	unless userIds.length is users.length
-		throw new Meteor.Error 'invalid-user'
-
-	unless _.isArray(roleNames)
-		roleNames = [roleNames]
-
-	existingRoleNames = _.pluck(RocketChat.authz.getRoles().fetch(), 'name')
-	invalidRoleNames = _.difference( roleNames, existingRoleNames)
-	unless _.isEmpty(invalidRoleNames)
-		# throw new Meteor.Error 'invalid-role'
-		for role in invalidRoleNames
-			Roles.createRole role
-
-	unless _.isString(scope)
-		scope = Roles.GLOBAL_GROUP
-
-	Roles.addUsersToRoles( userIds, roleNames, scope)
-
-	return true
diff --git a/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee b/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee
deleted file mode 100644
index 7023d120265bdf8e1e41d5062538f4ae116d90ea..0000000000000000000000000000000000000000
--- a/packages/rocketchat-authorization/server/functions/getPermissionsForRole.coffee
+++ /dev/null
@@ -1,9 +0,0 @@
-RocketChat.authz.getPermissionsForRole = (roleName) ->
-	unless roleName
-		throw new Meteor.Error 'invalid-role'
-
-	roleNames = _.pluck(RocketChat.authz.getRoles().fetch(), 'name')
-	unless roleName in roleNames
-		throw new Meteor.Error 'invalid-role', "Role #{roleName} not found"
-
-	return _.pluck(RocketChat.models.Permissions.findByRole( roleName ).fetch(), '_id')
diff --git a/packages/rocketchat-authorization/server/functions/getRoles.coffee b/packages/rocketchat-authorization/server/functions/getRoles.coffee
index 37c3d2537fdb438dcc9afc654e5eb1d941ef69af..895dcc532c1913c7fdb53e8800c8d079ecc4f8e8 100644
--- a/packages/rocketchat-authorization/server/functions/getRoles.coffee
+++ b/packages/rocketchat-authorization/server/functions/getRoles.coffee
@@ -1,2 +1,2 @@
 RocketChat.authz.getRoles = ->
-	return Roles.getAllRoles()
\ No newline at end of file
+	return RocketChat.models.Roles.find().fetch()
diff --git a/packages/rocketchat-authorization/server/functions/getRolesForUser.coffee b/packages/rocketchat-authorization/server/functions/getRolesForUser.coffee
deleted file mode 100644
index 800473a08bf3d14650a1fee5717714f62448e977..0000000000000000000000000000000000000000
--- a/packages/rocketchat-authorization/server/functions/getRolesForUser.coffee
+++ /dev/null
@@ -1,6 +0,0 @@
-RocketChat.authz.getRolesForUser = (userId, scope) ->
-	# returns roles for the given scope as well as the global scope
-	unless scope
-		scope = Roles.GLOBAL_GROUP
-
-	return Roles.getRolesForUser(userId, scope)
diff --git a/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee b/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee
index ee416c3e90255a1dddb77cb42ec78b055676126e..b8fc11a51fbae3c0462bab59d41e59392782e547 100644
--- a/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee
+++ b/packages/rocketchat-authorization/server/functions/getUsersInRole.coffee
@@ -1,6 +1,2 @@
 RocketChat.authz.getUsersInRole = (roleName, scope, options) ->
-	# alanning:roles doc says this is an expensive operation
-	unless _.isString(scope)
-		scope = Roles.GLOBAL_GROUP
-
-	return Roles.getUsersInRole(roleName, scope, options)
+	return RocketChat.models.Roles.findUsersInRole(roleName, scope, options)
diff --git a/packages/rocketchat-authorization/server/functions/hasPermission.coffee b/packages/rocketchat-authorization/server/functions/hasPermission.coffee
index b7c39299c7edaba68f68539e2b054cc7099c7a1d..7ae014453d0e994254bfa534be5054163f970e60 100644
--- a/packages/rocketchat-authorization/server/functions/hasPermission.coffee
+++ b/packages/rocketchat-authorization/server/functions/hasPermission.coffee
@@ -1,10 +1,3 @@
 RocketChat.authz.hasPermission = (userId, permissionId, scope) ->
-	# get user's roles
-	roles = RocketChat.authz.getRolesForUser(userId, scope)
-
-	# get permissions for user's roles
-	permissions = []
-	for role in roles
-		permissions = permissions.concat( RocketChat.authz.getPermissionsForRole( role ))
-	# may contain duplicate, but doesn't matter
-	return permissionId in permissions
+	permission = RocketChat.models.Permissions.findOne permissionId
+	return RocketChat.models.Roles.isUserInRoles(userId, permission.roles, scope)
diff --git a/packages/rocketchat-authorization/server/functions/hasRole.coffee b/packages/rocketchat-authorization/server/functions/hasRole.coffee
index 10ac10df4428c504fbc4f61acd15e33c0a53dca7..aff335e48b2fd0f7ae37fce3f2d00bb98796124c 100644
--- a/packages/rocketchat-authorization/server/functions/hasRole.coffee
+++ b/packages/rocketchat-authorization/server/functions/hasRole.coffee
@@ -1,3 +1,3 @@
-RocketChat.authz.hasRole = (userId, roleName, scope) ->
-	# per alanning:roles, returns true if user is in ANY roles
-	return Roles.userIsInRole(userId, [roleName], scope)
+RocketChat.authz.hasRole = (userId, roleNames, scope) ->
+	roleNames = [].concat roleNames
+	return RocketChat.models.Roles.isUserInRoles(userId, roleNames, scope) # true if user is in ANY role
diff --git a/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee b/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..64df765f67fc7711960861e2f4b8543287b8afce
--- /dev/null
+++ b/packages/rocketchat-authorization/server/functions/removeUserFromRoles.coffee
@@ -0,0 +1,18 @@
+RocketChat.authz.removeUserFromRoles = (userId, roleNames, scope) ->
+	if not userId or not roleNames
+		return false
+
+	user = RocketChat.models.Users.findOneById(userId)
+	if not user?
+		throw new Meteor.Error 'invalid-user'
+
+	roleNames = [].concat roleNames
+
+	existingRoleNames = _.pluck(RocketChat.authz.getRoles(), 'name')
+	invalidRoleNames = _.difference(roleNames, existingRoleNames)
+	unless _.isEmpty(invalidRoleNames)
+		throw new Meteor.Error 'invalid-role'
+
+	RocketChat.models.Roles.removeUserRoles(userId, roleNames, scope)
+
+	return true
diff --git a/packages/rocketchat-authorization/server/functions/removeUsersFromRoles.coffee b/packages/rocketchat-authorization/server/functions/removeUsersFromRoles.coffee
deleted file mode 100644
index 93f78b6ccad5b1af25aaf44a20de37e490bdc89f..0000000000000000000000000000000000000000
--- a/packages/rocketchat-authorization/server/functions/removeUsersFromRoles.coffee
+++ /dev/null
@@ -1,25 +0,0 @@
-RocketChat.authz.removeUsersFromRoles = (userIds, roleNames, scope ) ->
-	if not userIds or not roleNames
-		return false
-
-	unless _.isArray(userIds)
-		userIds = [userIds]
-
-	users = Meteor.users.find({_id: {$in : userIds}}).fetch()
-	unless userIds.length is users.length
-		throw new Meteor.Error 'invalid-user'
-
-	unless _.isArray(roleNames)
-		roleNames = [roleNames]
-
-	existingRoleNames = _.pluck(RocketChat.authz.getRoles().fetch(), 'name')
-	invalidRoleNames = _.difference( roleNames, existingRoleNames)
-	unless _.isEmpty(invalidRoleNames)
-		throw new Meteor.Error 'invalid-role'
-
-	unless _.isString(scope)
-		scope = Roles.GLOBAL_GROUP
-
-	Roles.removeUsersFromRoles( userIds, roleNames, scope)
-
-	return true
diff --git a/packages/rocketchat-authorization/server/methods/addUserToRole.coffee b/packages/rocketchat-authorization/server/methods/addUserToRole.coffee
index a5340768b512a68b516f303f4a1fed499bc284a2..74ba6bbea53017285a33b185a525663ef2bd96ba 100644
--- a/packages/rocketchat-authorization/server/methods/addUserToRole.coffee
+++ b/packages/rocketchat-authorization/server/methods/addUserToRole.coffee
@@ -1,15 +1,14 @@
 Meteor.methods
-	'authorization:addUserToRole': (roleName, username) ->
+	'authorization:addUserToRole': (roleName, username, scope) ->
 		if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-permissions'
 			throw new Meteor.Error "not-authorized"
 
 		if not roleName or not _.isString(roleName) or not username or not _.isString(username)
 			throw new Meteor.Error 'invalid-arguments'
 
-		user = Meteor.users.findOne { username: username }, { fields: { _id: 1 } }
+		user = RocketChat.models.Users.findOneByUsername username, { fields: { _id: 1 } }
 
 		if not user?._id?
 			throw new Meteor.Error 'user-not-found', 'User_not_found'
 
-		# return Roles.addUsersToRoles user._id, roleName
-		return Roles.addUsersToRoles user._id, roleName, Roles.GLOBAL_GROUP
+		return RocketChat.models.Roles.addUserRoles user._id, roleName, scope
diff --git a/packages/rocketchat-authorization/server/methods/deleteRole.coffee b/packages/rocketchat-authorization/server/methods/deleteRole.coffee
index 0a928cb252bd089fa2077e6c7601e8f0f50800f8..39ca53a350289761cca1c9725c2ebe8d70cf6dd4 100644
--- a/packages/rocketchat-authorization/server/methods/deleteRole.coffee
+++ b/packages/rocketchat-authorization/server/methods/deleteRole.coffee
@@ -1,16 +1,19 @@
 Meteor.methods
-	'authorization:deleteRole': (_id) ->
+	'authorization:deleteRole': (roleName) ->
 		if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-permissions'
 			throw new Meteor.Error "not-authorized"
 
-		role = Meteor.roles.findOne _id
+		role = RocketChat.models.Roles.findOne roleName
+		if not role?
+			throw new Meteor.Error 'invalid-role'
 
 		if role.protected
 			throw new Meteor.Error 'protected-role', 'Cannot_delete_a_protected_role'
 
-		someone = Meteor.users.findOne { "roles.#{Roles.GLOBAL_GROUP}": role.name }
+		roleScope = role.scope or 'Users'
+		existingUsers = RocketChat.models[roleScope]?.findUsersInRoles?(roleName)
 
-		if someone?
+		if existingUsers?.count() > 0
 			throw new Meteor.Error 'role-in-use', 'Cannot_delete_role_because_its_in_use'
 
-		return Roles.deleteRole role.name
+		return RocketChat.models.Roles.remove role.name
diff --git a/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee b/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee
index 6510c2f8b2be8683da88afda7d36a074762adc54..26da340af6f32bfd70bab9179e3aebff25a58734 100644
--- a/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee
+++ b/packages/rocketchat-authorization/server/methods/removeUserFromRole.coffee
@@ -11,4 +11,4 @@ Meteor.methods
 		if not user?._id?
 			throw new Meteor.Error 'user-not-found'
 
-		return Roles.removeUsersFromRoles user._id, roleName, Roles.GLOBAL_GROUP
+		return RocketChat.models.Roles.removeUserRoles user._id, roleName
diff --git a/packages/rocketchat-authorization/server/methods/saveRole.coffee b/packages/rocketchat-authorization/server/methods/saveRole.coffee
index 7a30d9ecec60571c4bbaea899dbfc40c6043eaeb..874fe0eaa6d0bc3de8ba8c3d1e178e857b42069a 100644
--- a/packages/rocketchat-authorization/server/methods/saveRole.coffee
+++ b/packages/rocketchat-authorization/server/methods/saveRole.coffee
@@ -3,13 +3,7 @@ Meteor.methods
 		if not Meteor.userId() or not RocketChat.authz.hasPermission Meteor.userId(), 'access-permissions'
 			throw new Meteor.Error "not-authorized"
 
-		saveData =
-			description: roleData.description
+		if not roleData.name?
+			throw new Meteor.Error 'invalid-data', 'Role name is required'
 
-		if not _id? and roleData.name?
-			saveData.name = roleData.name
-
-		if _id?
-			return Meteor.roles.update _id, { $set: saveData }
-		else
-			return Meteor.roles.insert saveData
+		return RocketChat.models.Roles.createOrUpdate roleData.name, 'Users', roleData.description
diff --git a/packages/rocketchat-authorization/server/models/Base.js b/packages/rocketchat-authorization/server/models/Base.js
new file mode 100644
index 0000000000000000000000000000000000000000..5977c6446677641d03f7e66ada585774895224d0
--- /dev/null
+++ b/packages/rocketchat-authorization/server/models/Base.js
@@ -0,0 +1,38 @@
+RocketChat.models._Base.prototype.roleBaseQuery = function(userId, scope) { return {} }
+
+RocketChat.models._Base.prototype.findRolesByUserId = function(userId, options) {
+	var query = this.roleBaseQuery(userId);
+	return this.find(query, { fields: { roles: 1 } });
+}
+
+RocketChat.models._Base.prototype.isUserInRole = function(userId, roleName, scope) {
+	var query = this.roleBaseQuery(userId, scope);
+	query.roles = roleName;
+	return !_.isUndefined(this.findOne(query));
+}
+
+RocketChat.models._Base.prototype.addRolesByUserId = function(userId, roles, scope) {
+	var roles = [].concat(roles);
+	var query = this.roleBaseQuery(userId, scope);
+	var update = {
+		$addToSet: {
+			roles: { $each: roles }
+		}
+	}
+	return this.update(query, update);
+}
+
+RocketChat.models._Base.prototype.removeRolesByUserId = function(userId, roles, scope) {
+	var roles = [].concat(roles);
+	var query = this.roleBaseQuery(userId, scope);
+	var update = {
+		$pullAll: {
+			roles: roles
+		}
+	}
+	return this.update(query, update);
+}
+
+RocketChat.models._Base.prototype.findUsersInRoles = function() {
+	throw new Meteor.Error('overwrite-function', 'You must overwrite this function in the extended classes');
+}
diff --git a/packages/rocketchat-authorization/server/models/Permissions.coffee b/packages/rocketchat-authorization/server/models/Permissions.coffee
index 3e1c6eef96a5e025b65cbbad6fe3929ea2e7a8fc..ec763d94b7122a1d14dcde4db00e4f26b850b792 100644
--- a/packages/rocketchat-authorization/server/models/Permissions.coffee
+++ b/packages/rocketchat-authorization/server/models/Permissions.coffee
@@ -2,7 +2,6 @@ RocketChat.models.Permissions = new class extends RocketChat.models._Base
 	constructor: ->
 		@_initModel 'permissions'
 
-
 	# FIND
 	findByRole: (role, options) ->
 		query =
diff --git a/packages/rocketchat-authorization/server/models/Roles.coffee b/packages/rocketchat-authorization/server/models/Roles.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..8489afa1d47ac77c94b8acc537d88bab2faa09d8
--- /dev/null
+++ b/packages/rocketchat-authorization/server/models/Roles.coffee
@@ -0,0 +1,43 @@
+RocketChat.models.Roles = new class extends RocketChat.models._Base
+	constructor: ->
+		@_initModel 'roles'
+		@tryEnsureIndex { 'name': 1 }
+		@tryEnsureIndex { 'scope': 1 }
+
+	findUsersInRole: (name, scope, options) ->
+		role = @findOne name
+		roleScope = role?.scope or 'Users'
+		RocketChat.models[roleScope]?.findUsersInRoles?(name, scope, options)
+
+	isUserInRoles: (userId, roles, scope) ->
+		roles = [].concat roles
+		_.some roles, (roleName) =>
+			role = @findOne roleName
+			roleScope = role?.scope or 'Users'
+			return RocketChat.models[roleScope]?.isUserInRole?(userId, roleName, scope)
+
+	createOrUpdate: (name, scope, description, protectedRole) ->
+		scope ?= 'Users'
+		updateData = {}
+		updateData.name = name
+		updateData.scope = scope
+		if description?
+			updateData.description = description
+		if protectedRole?
+			updateData.protected = protectedRole
+
+		@upsert { _id: name }, { $set: updateData }
+
+	addUserRoles: (userId, roles, scope) ->
+		roles = [].concat roles
+		for roleName in roles
+			role = @findOne roleName
+			roleScope = role?.scope or 'Users'
+			RocketChat.models[roleScope]?.addRolesByUserId?(userId, roleName, scope)
+
+	removeUserRoles: (userId, roles, scope) ->
+		roles = [].concat roles
+		for roleName in roles
+			role = @findOne roleName
+			roleScope = role?.scope or 'Users'
+			RocketChat.models[roleScope]?.removeRolesByUserId?(userId, roleName, scope)
diff --git a/packages/rocketchat-authorization/server/models/Subscriptions.js b/packages/rocketchat-authorization/server/models/Subscriptions.js
new file mode 100644
index 0000000000000000000000000000000000000000..9c7d4a16fc760f753d6109bc14d64932d245aa05
--- /dev/null
+++ b/packages/rocketchat-authorization/server/models/Subscriptions.js
@@ -0,0 +1,28 @@
+RocketChat.models.Subscriptions.roleBaseQuery = function(userId, scope) {
+	var query = { "u._id": userId }
+	if (!_.isUndefined(scope)) {
+		query.rid = scope;
+	}
+	return query;
+}
+
+RocketChat.models.Subscriptions.findUsersInRoles = function(roles, scope, options) {
+	roles = [].concat(roles);
+
+	var query = {
+		roles: { $in: roles }
+	}
+
+	if (scope) {
+		query.rid = scope;
+	}
+
+	subscriptions = this.find(query).fetch();
+
+	users = _.compact(_.map(subscriptions, function(subscription) {
+		if ('undefined' !== typeof subscription.u && 'undefined' !== typeof subscription.u._id)
+			return subscription.u._id
+	}));
+
+	return RocketChat.models.Users.find({ _id: { $in: users } }, options);
+}
diff --git a/packages/rocketchat-authorization/server/models/Users.js b/packages/rocketchat-authorization/server/models/Users.js
new file mode 100644
index 0000000000000000000000000000000000000000..315ab7e9acf9500536ff5c9ca491bc380d1f3970
--- /dev/null
+++ b/packages/rocketchat-authorization/server/models/Users.js
@@ -0,0 +1,13 @@
+RocketChat.models.Users.roleBaseQuery = function(userId, scope) {
+	return { _id: userId }
+}
+
+RocketChat.models.Users.findUsersInRoles = function(roles, scope, options) {
+	roles = [].concat(roles);
+
+	var query = {
+		roles: { $in: roles }
+	}
+
+	return this.find(query, options);
+}
diff --git a/packages/rocketchat-authorization/server/publication.coffee b/packages/rocketchat-authorization/server/publication.coffee
deleted file mode 100644
index 9a4fa8cbfc1e737fc08741fa78fd10c1d3966afd..0000000000000000000000000000000000000000
--- a/packages/rocketchat-authorization/server/publication.coffee
+++ /dev/null
@@ -1,2 +0,0 @@
-Meteor.publish 'permissions', ->
-	return RocketChat.models.Permissions.find {}
diff --git a/packages/rocketchat-authorization/server/publications/integrations.coffee b/packages/rocketchat-authorization/server/publications/integrations.coffee
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/packages/rocketchat-authorization/server/publications/permissions.js b/packages/rocketchat-authorization/server/publications/permissions.js
new file mode 100644
index 0000000000000000000000000000000000000000..0872d3b4db046cc84791c55c1e576b7399bd4218
--- /dev/null
+++ b/packages/rocketchat-authorization/server/publications/permissions.js
@@ -0,0 +1,3 @@
+Meteor.publish('permissions', function () {
+	return RocketChat.models.Permissions.find({});
+});
diff --git a/packages/rocketchat-authorization/server/publications/roles.coffee b/packages/rocketchat-authorization/server/publications/roles.coffee
index 6357a62510e7c6a4635d19a169531248d04a0145..b3eafb56d3e50b2a485ab95413f4a4064755d776 100644
--- a/packages/rocketchat-authorization/server/publications/roles.coffee
+++ b/packages/rocketchat-authorization/server/publications/roles.coffee
@@ -2,7 +2,5 @@ Meteor.publish 'roles', ->
 	unless @userId
 		return @ready()
 
-	if not RocketChat.authz.hasPermission @userId, 'access-permissions'
-		throw new Meteor.Error "not-authorized"
+	return RocketChat.models.Roles.find()
 
-	return RocketChat.authz.getRoles()
diff --git a/packages/rocketchat-authorization/server/publications/scopedRoles.js b/packages/rocketchat-authorization/server/publications/scopedRoles.js
new file mode 100644
index 0000000000000000000000000000000000000000..bd6247697b0abb90c100593ea93c9aa097bdaf58
--- /dev/null
+++ b/packages/rocketchat-authorization/server/publications/scopedRoles.js
@@ -0,0 +1,11 @@
+/**
+ * Publish logged-in user's roles so client-side checks can work.
+ */
+Meteor.publish('scopedRoles', function (scope) {
+	if (!this.userId || _.isUndefined(RocketChat.models[scope]) || !_.isFunction(RocketChat.models[scope].findRolesByUserId)) {
+		this.ready()
+		return
+	}
+
+	return RocketChat.models[scope].findRolesByUserId(this.userId);
+});
diff --git a/packages/rocketchat-authorization/server/startup.coffee b/packages/rocketchat-authorization/server/startup.coffee
index fbaf7bdb701c522c20c6301b9cc8b35d5e05b208..d9bd6b1a7b12cce3b3bf0958a85d7c81fce87b88 100644
--- a/packages/rocketchat-authorization/server/startup.coffee
+++ b/packages/rocketchat-authorization/server/startup.coffee
@@ -7,7 +7,7 @@ Meteor.startup ->
 	permissions = [
 
 		{ _id: 'view-statistics',
-		roles : ['admin', 'temp-role']}
+		roles : ['admin']}
 
 		{ _id: 'view-privileged-setting',
 		roles : ['admin']}
@@ -34,7 +34,7 @@ Meteor.startup ->
 		roles : ['admin']}
 
 		{ _id: 'edit-other-user-active-status',
-		roles : ['admin', 'site-moderator']}
+		roles : ['admin']}
 
 		{ _id: 'delete-user',
 		roles : ['admin']}
@@ -49,37 +49,37 @@ Meteor.startup ->
 		roles : ['admin']}
 
 		{ _id: 'create-c',
-		roles : ['admin', 'site-moderator', 'user']}
+		roles : ['admin', 'user']}
 
 		{ _id: 'delete-c',
-		roles : ['admin', 'site-moderator']}
+		roles : ['admin']}
 
 		{ _id: 'edit-room',
-		roles : ['admin', 'site-moderator', 'moderator']}
+		roles : ['admin', 'moderator']}
 
 		{ _id: 'edit-message',
-		roles : ['admin', 'site-moderator', 'moderator']}
+		roles : ['admin', 'moderator']}
 
 		{ _id: 'delete-message',
-		roles : ['admin', 'site-moderator', 'moderator']}
+		roles : ['admin', 'moderator']}
 
 		{ _id: 'remove-user',
-		roles : ['admin', 'site-moderator', 'moderator']}
+		roles : ['admin', 'moderator']}
 
 		{ _id: 'mute-user',
-		roles : ['admin', 'site-moderator', 'moderator']}
+		roles : ['admin', 'moderator']}
 
 		{ _id: 'ban-user',
-		roles : ['admin', 'site-moderator', 'moderator']}
+		roles : ['admin', 'moderator']}
 
 		{ _id: 'create-p',
-		roles : ['admin', 'site-moderator', 'user']}
+		roles : ['admin', 'user']}
 
 		{ _id: 'delete-p',
-		roles : ['admin', 'site-moderator']}
+		roles : ['admin']}
 
 		{ _id: 'delete-d',
-		roles : ['admin', 'site-moderator']}
+		roles : ['admin']}
 
 		{ _id: 'bulk-register-user',
 		roles : ['admin']}
@@ -88,13 +88,13 @@ Meteor.startup ->
 		roles : ['admin']}
 
 		{ _id: 'view-c-room',
-		roles : ['admin', 'site-moderator', 'user']}
+		roles : ['admin', 'user']}
 
 		{ _id: 'view-p-room',
-		roles : ['admin', 'site-moderator', 'user']}
+		roles : ['admin', 'user']}
 
 		{ _id: 'view-d-room',
-		roles : ['admin', 'site-moderator', 'user']}
+		roles : ['admin', 'user']}
 
 		{ _id: 'access-permissions',
 		roles : ['admin']}
@@ -109,14 +109,15 @@ Meteor.startup ->
 		roles : ['admin']}
 	]
 
-	#alanning:roles
-	roles = _.pluck(Roles.getAllRoles().fetch(), 'name');
-
 	for permission in permissions
 		RocketChat.models.Permissions.upsert( permission._id, {$set: permission })
-		for role in permission.roles
-			unless role in roles
-				Roles.createRole role
-				roles.push(role)
 
+	defaultRoles = [
+		{ name: 'admin', scope: 'Users' }
+		{ name: 'moderator', scope: 'Subscriptions' }
+		{ name: 'user', scope: 'Users' }
+		{ name: 'bot', scope: 'Users' }
+	]
 
+	for role in defaultRoles
+		RocketChat.models.Roles.createOrUpdate role.name, role.scope
diff --git a/packages/rocketchat-integrations/package.js b/packages/rocketchat-integrations/package.js
index 8c00200f332156a62c6db0b648cc78b05c4d5992..dc2b48f48e4a2a2c22c6ceb78be6965e019e5743 100644
--- a/packages/rocketchat-integrations/package.js
+++ b/packages/rocketchat-integrations/package.js
@@ -13,7 +13,7 @@ Package.onUse(function(api) {
   api.use('underscore');
   api.use('simple:highlight.js');
   api.use('rocketchat:lib');
-  api.use('alanning:roles@1.2.12');
+  api.use('rocketchat:authorization');
 
   api.use('kadira:flow-router', 'client');
   api.use('templating', 'client');
diff --git a/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee b/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee
index 67c33d156f6a745f1e393e3cb8c93c23cf1d8191..54efaf760064dd44e6fc5c07c564f2fc0bca3733 100644
--- a/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee
+++ b/packages/rocketchat-integrations/server/methods/incoming/addIncomingIntegration.coffee
@@ -61,7 +61,7 @@ Meteor.methods
 
 		RocketChat.models.Users.update {_id: user._id}, updateObj
 
-		Roles.addUsersToRoles user._id, 'bot', 'bot'
+		RocketChat.models.Roles.addUserRoles user._id, 'bot'
 
 		integration._id = RocketChat.models.Integrations.insert integration
 
diff --git a/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee b/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee
index da7aa3dd15f2f80ae1b67477bfc8e936a0b6249b..59a93bdbbafae5e788a0cee499d1aa0fd23ece1e 100644
--- a/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee
+++ b/packages/rocketchat-integrations/server/methods/incoming/updateIncomingIntegration.coffee
@@ -38,7 +38,7 @@ Meteor.methods
 			throw new Meteor.Error 'channel_does_not_exists', "[methods] updateIncomingIntegration -> The channel does not exists"
 
 		user = RocketChat.models.Users.findOne({username: currentIntegration.username})
-		Roles.addUsersToRoles user._id, 'bot', 'bot'
+		RocketChat.models.Roles.addUserRoles user._id, 'bot'
 
 		RocketChat.models.Integrations.update integrationId,
 			$set:
diff --git a/packages/rocketchat-lib/server/methods/setAdminStatus.coffee b/packages/rocketchat-lib/server/methods/setAdminStatus.coffee
index b81d6d9f04f62db1ee3817794d0afd9854d3f5c2..542c5853fd094f682c17af4225fdc2527cf22cb4 100644
--- a/packages/rocketchat-lib/server/methods/setAdminStatus.coffee
+++ b/packages/rocketchat-lib/server/methods/setAdminStatus.coffee
@@ -7,8 +7,8 @@ Meteor.methods
 			throw new Meteor.Error 'not-authorized', '[methods] setAdminStatus -> Not authorized'
 
 		if admin
-			RocketChat.authz.addUsersToRoles( userId, 'admin')
+			RocketChat.authz.addUserRoles( userId, 'admin')
 		else
-			RocketChat.authz.removeUsersFromRoles( userId, 'admin')
+			RocketChat.authz.removeUserFromRoles( userId, 'admin')
 
 		return true
diff --git a/packages/rocketchat-livechat/package.js b/packages/rocketchat-livechat/package.js
index 216d35f024349e18870575da04daf31727c017a3..a43697f53401f55a0dc46d584a5511487b86c5b8 100644
--- a/packages/rocketchat-livechat/package.js
+++ b/packages/rocketchat-livechat/package.js
@@ -20,8 +20,8 @@ Package.onUse(function(api) {
 
 	api.use(['webapp', 'autoupdate'], 'server');
 	api.use('ecmascript');
-	api.use('alanning:roles@1.2.12');
 	api.use('rocketchat:lib');
+	api.use('rocketchat:authorization');
 	api.use('rocketchat:ui');
 	api.use('kadira:flow-router', 'client');
 	api.use('templating', 'client');
diff --git a/packages/rocketchat-livechat/permissions.js b/packages/rocketchat-livechat/permissions.js
index ea678f9abe66d7b358754b1dfa7efddfbd436670..ad5a5a3c8432579935162307bdfcc041e42a4ae3 100644
--- a/packages/rocketchat-livechat/permissions.js
+++ b/packages/rocketchat-livechat/permissions.js
@@ -1,13 +1,13 @@
 Meteor.startup(() => {
-	var roles = _.pluck(Roles.getAllRoles().fetch(), 'name');
+	var roles = _.pluck(RocketChat.models.Roles.find().fetch(), 'name');
 	if (roles.indexOf('livechat-agent') === -1) {
-		Roles.createRole('livechat-agent');
+		RocketChat.models.Roles.createOrUpdate('livechat-agent');
 	}
 	if (roles.indexOf('livechat-manager') === -1) {
-		Roles.createRole('livechat-manager');
+		RocketChat.models.Roles.createOrUpdate('livechat-manager');
 	}
 	if (roles.indexOf('livechat-guest') === -1) {
-		Roles.createRole('livechat-guest');
+		RocketChat.models.Roles.createOrUpdate('livechat-guest');
 	}
 	if (RocketChat.models && RocketChat.models.Permissions) {
 		RocketChat.models.Permissions.createOrUpdate('view-l-room', ['livechat-agent', 'livechat-manager', 'admin']);
diff --git a/packages/rocketchat-livechat/server/methods/addAgent.js b/packages/rocketchat-livechat/server/methods/addAgent.js
index cd924c14ce9b7d18d5136b8ee78afd49f0cb2a81..e236bc2c41a2f70ef0436a0239434ce0822d8b48 100644
--- a/packages/rocketchat-livechat/server/methods/addAgent.js
+++ b/packages/rocketchat-livechat/server/methods/addAgent.js
@@ -14,7 +14,7 @@ Meteor.methods({
 			throw new Meteor.Error('user-not-found', 'Username_not_found');
 		}
 
-		if (RocketChat.authz.addUsersToRoles(user._id, 'livechat-agent')) {
+		if (RocketChat.authz.addUserRoles(user._id, 'livechat-agent')) {
 			return RocketChat.models.Users.setOperator(user._id, true);
 		}
 
diff --git a/packages/rocketchat-livechat/server/methods/addManager.js b/packages/rocketchat-livechat/server/methods/addManager.js
index eb0f905ec402ba01ee5b4b27ee4e9eed4339ab21..9f4af3713a4647d0d0d2feb43197c93d89f6e753 100644
--- a/packages/rocketchat-livechat/server/methods/addManager.js
+++ b/packages/rocketchat-livechat/server/methods/addManager.js
@@ -14,6 +14,6 @@ Meteor.methods({
 			throw new Meteor.Error('user-not-found', 'Username_not_found');
 		}
 
-		return RocketChat.authz.addUsersToRoles(user._id, 'livechat-manager');
+		return RocketChat.authz.addUserRoles(user._id, 'livechat-manager');
 	}
 });
diff --git a/packages/rocketchat-livechat/server/methods/removeAgent.js b/packages/rocketchat-livechat/server/methods/removeAgent.js
index 141b7d3bf94350bb164e94814f78d5576bbe25cb..adbf4ae47739efcb49602609dade49d4e62c6fc0 100644
--- a/packages/rocketchat-livechat/server/methods/removeAgent.js
+++ b/packages/rocketchat-livechat/server/methods/removeAgent.js
@@ -14,7 +14,7 @@ Meteor.methods({
 			throw new Meteor.Error('user-not-found', 'Username_not_found');
 		}
 
-		if (RocketChat.authz.removeUsersFromRoles(user._id, 'livechat-agent')) {
+		if (RocketChat.authz.removeUserFromRoles(user._id, 'livechat-agent')) {
 			return RocketChat.models.Users.setOperator(user._id, false);
 		}
 
diff --git a/packages/rocketchat-livechat/server/methods/removeManager.js b/packages/rocketchat-livechat/server/methods/removeManager.js
index 32db557fd805773d01c0fb4430c8655d845cd8bb..31ad6cd337b8f01524536b12474e7ce0440cec7f 100644
--- a/packages/rocketchat-livechat/server/methods/removeManager.js
+++ b/packages/rocketchat-livechat/server/methods/removeManager.js
@@ -12,6 +12,6 @@ Meteor.methods({
 			throw new Meteor.Error('user-not-found', 'Username_not_found');
 		}
 
-		return RocketChat.authz.removeUsersFromRoles(user._id, 'livechat-manager');
+		return RocketChat.authz.removeUserFromRoles(user._id, 'livechat-manager');
 	}
 });
diff --git a/packages/rocketchat-livechat/server/models/Users.js b/packages/rocketchat-livechat/server/models/Users.js
index 41e10fad9dbc193264869a06f3bbde3562d223ef..7a9d212867d8f84a6cd1861d63d5770642eb4f80 100644
--- a/packages/rocketchat-livechat/server/models/Users.js
+++ b/packages/rocketchat-livechat/server/models/Users.js
@@ -20,11 +20,9 @@ RocketChat.models.Users.setOperator = function(_id, operator) {
 RocketChat.models.Users.findOnlineAgents = function() {
 	var query = {
 		status: 'online',
-		roles: {}
+		roles: 'livechat-agent'
 	};
 
-	query.roles[Roles.GLOBAL_GROUP] = 'livechat-agent';
-
 	return this.find(query);
 };
 
@@ -50,11 +48,10 @@ RocketChat.models.Users.findOnlineUserFromList = function(userList) {
  */
 RocketChat.models.Users.getNextAgent = function() {
 	var query = {
-		status: 'online'
+		status: 'online',
+		roles: 'livechat-agent'
 	};
 
-	query['roles.' + Roles.GLOBAL_GROUP] = 'livechat-agent';
-
 	var collectionObj = this.model.rawCollection();
 	var findAndModify = Meteor.wrapAsync(collectionObj.findAndModify, collectionObj);
 
diff --git a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee
index d8d3b415c34eaca83b8f75c771317d1afcd54bc9..4ced37677bb6857a9cc90107dde8be905b78d1fc 100644
--- a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee
+++ b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.coffee
@@ -1,5 +1,6 @@
 Template.oauthApp.onCreated ->
-	@record = new ReactiveVar {}
+	@record = new ReactiveVar
+		active: true
 
 
 Template.oauthApp.helpers
@@ -12,6 +13,9 @@ Template.oauthApp.helpers
 		if params?.id?
 			data = ChatOAuthApps.findOne({_id: params.id})
 			if data?
+				data.authorization_url = Meteor.absoluteUrl("oauth/authorize")
+				data.access_token_url = Meteor.absoluteUrl("oauth/token")
+
 				Template.instance().record.set data
 				return data
 
@@ -45,6 +49,7 @@ Template.oauthApp.events
 
 	"click .submit > .save": ->
 		name = $('[name=name]').val().trim()
+		active = $('[name=active]:checked').val().trim() is "1"
 		redirectUri = $('[name=redirectUri]').val().trim()
 
 		if name is ''
@@ -55,6 +60,7 @@ Template.oauthApp.events
 
 		app =
 			name: name
+			active: active
 			redirectUri: redirectUri
 
 		params = Template.instance().data.params?()
diff --git a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html
index fab7358c2178d1feb3035f3af84d19540e7e6ab2..d9d722ddd4917d53feaf9ca48f42330c82c2174b 100644
--- a/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html
+++ b/packages/rocketchat-oauth2-server-config/admin/client/views/oauthApp.html
@@ -5,10 +5,17 @@
 			<div class="rocket-form">
 				<div class="section">
 					<div class="section-content">
+						<div class="input-line double-col">
+							<label>{{_ "Active"}}</label>
+							<div>
+								<label><input class="input-monitor" type="radio" name="active" value="1" checked="{{$eq data.active true}}" /> {{_ "True"}}</label>
+								<label><input class="input-monitor" type="radio" name="active" value="0" checked="{{$eq data.active false}}" /> {{_ "False"}}</label>
+							</div>
+						</div>
 						<div class="input-line double-col">
 							<label>{{_ "Application_Name"}}</label>
 							<div>
-								<input type="text" name="name" value="{{data.name}}" placeholder="{{_ 'Optional'}}" />
+								<input type="text" name="name" value="{{data.name}}" />
 								<div class="settings-description">{{_ "Give_the_application_a_name_This_will_be_seen_by_your_users"}}</div>
 							</div>
 						</div>
@@ -34,11 +41,25 @@
 									<div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=clientSecret]">{{_ "COPY_TO_CLIPBOARD"}}</a></div>
 								</div>
 							</div>
+							<div class="input-line double-col">
+								<label>{{_ "Authorization_URL"}}</label>
+								<div>
+									<input type="text" name="authorization_url" value="{{data.authorization_url}}" disabled="disabled" />
+									<div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=authorization_url]">{{_ "COPY_TO_CLIPBOARD"}}</a></div>
+								</div>
+							</div>
+							<div class="input-line double-col">
+								<label>{{_ "Access_Token_URL"}}</label>
+								<div>
+									<input type="text" name="access_token_url" value="{{data.access_token_url}}" disabled="disabled" />
+									<div class="settings-description"><a href="#" class="clipboard" data-clipboard-target="[name=access_token_url]">{{_ "COPY_TO_CLIPBOARD"}}</a></div>
+								</div>
+							</div>
 						{{/if}}
 					</div>
 				</div>
 				<div class="submit">
-					{{#if data.token}}
+					{{#if data.clientId}}
 						<button class="button red delete"><i class="icon-trash"></i><span>{{_ "Delete"}}</span></button>
 					{{/if}}
 					<button class="button save"><i class="icon-send"></i><span>{{_ "Save_changes"}}</span></button>
diff --git a/packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee b/packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee
index 9215823802ddbd008716d072723c4b48760c7413..21e189664dc64073a013c4ba2f34a0bffe6a9c72 100644
--- a/packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee
+++ b/packages/rocketchat-oauth2-server-config/admin/server/methods/addOAuthApp.coffee
@@ -15,6 +15,9 @@ Meteor.methods
 		if application.redirectUri.trim() is ''
 			throw new Meteor.Error 'invalid_redirectUri', '[methods] addOAuthApp -> redirectUri can\'t be empty'
 
+		if not _.isBoolean(application.active)
+			throw new Meteor.Error 'invalid_active', '[methods] addOAuthApp -> active must be boolean'
+
 		application.clientId = Random.id()
 		application.clientSecret = Random.secret()
 		application._createdAt = new Date
diff --git a/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee b/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee
index 6cfd200145c115d31083fb9425bb700a8b71a3b7..e50cbf1161104b80fefb23db0ed376b62c32e649 100644
--- a/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee
+++ b/packages/rocketchat-oauth2-server-config/admin/server/methods/updateOAuthApp.coffee
@@ -15,6 +15,9 @@ Meteor.methods
 		if application.redirectUri.trim() is ''
 			throw new Meteor.Error 'invalid_redirectUri', '[methods] updateOAuthApp -> redirectUri can\'t be empty'
 
+		if not _.isBoolean(application.active)
+			throw new Meteor.Error 'invalid_active', '[methods] updateOAuthApp -> active must be boolean'
+
 		currentApplication = RocketChat.models.OAuthApps.findOne(applicationId)
 		if not currentApplication?
 			throw new Meteor.Error 'invalid_application', '[methods] updateOAuthApp -> application not found'
@@ -22,6 +25,7 @@ Meteor.methods
 		RocketChat.models.OAuthApps.update applicationId,
 			$set:
 				name: application.name
+				active: application.active
 				redirectUri: application.redirectUri
 				_updatedAt: new Date
 				_updatedBy: RocketChat.models.Users.findOne @userId, {fields: {username: 1}}
diff --git a/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee b/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..41fee6a9a863d9a6a10a50f5f030d7ec8a011ecc
--- /dev/null
+++ b/packages/rocketchat-oauth2-server-config/oauth/server/default-services.coffee
@@ -0,0 +1,12 @@
+if not RocketChat.models.OAuthApps.findOne('zapier')
+	RocketChat.models.OAuthApps.insert
+		_id: 'zapier'
+		name: 'Zapier'
+		active: false
+		clientId: 'zapier'
+		clientSecret: 'RTK6TlndaCIolhQhZ7_KHIGOKj41RnlaOq_o-7JKwLr'
+		redirectUri: 'https://zapier.com/dashboard/auth/oauth/return/AppIDAPI/'
+		_createdAt: new Date
+		_createdBy:
+			_id: 'system'
+			username: 'system'
diff --git a/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee b/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee
index 96940151b582fdee3f0f130d1f0a4287b7696864..770cb583682bf87744294daf32b127aaf324bd87 100644
--- a/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee
+++ b/packages/rocketchat-oauth2-server-config/oauth/server/oauth2-server.coffee
@@ -8,12 +8,6 @@ oauth2server = new OAuth2Server
 WebApp.connectHandlers.use oauth2server.app
 # JsonRoutes.Middleware.use oauth2server.app
 
-if not oauth2server.model.Clients.findOne()
-	oauth2server.model.Clients.insert
-		clientId: 'papers3'
-		clientSecret: '123'
-		redirectUri: 'http://localhost:3000/_oauth/rc'
-
 oauth2server.routes.get '/account', oauth2server.oauth.authorise(), (req, res, next) ->
 	user = Meteor.users.findOne req.user.id
 
diff --git a/packages/rocketchat-oauth2-server-config/package.js b/packages/rocketchat-oauth2-server-config/package.js
index 479ba8b40b3d2e57e7f0be287e76d97e04fb6cff..310bebaeed5ff25ef2932258b5d7b91387c27e62 100644
--- a/packages/rocketchat-oauth2-server-config/package.js
+++ b/packages/rocketchat-oauth2-server-config/package.js
@@ -23,6 +23,7 @@ Package.onUse(function(api) {
 	//// OAuth //
 	// Server
 	api.addFiles('oauth/server/oauth2-server.coffee', 'server');
+	api.addFiles('oauth/server/default-services.coffee', 'server');
 
 	api.addAssets('oauth/client/stylesheets/oauth2.less', 'server');
 	api.addFiles('oauth/client/stylesheets/load.coffee', 'server');
diff --git a/packages/rocketchat-theme/assets/stylesheets/base.less b/packages/rocketchat-theme/assets/stylesheets/base.less
index dd46ff3ebf0f0d44325cd2b59f878c6586a696b8..1a323d7e600854832b0f67165a2578925c331c62 100644
--- a/packages/rocketchat-theme/assets/stylesheets/base.less
+++ b/packages/rocketchat-theme/assets/stylesheets/base.less
@@ -2516,6 +2516,13 @@ a.github-fork {
 	line-height: 20px;
 	min-height: 40px;
 
+	&.highlight {
+		-webkit-animation: highlight 3s;
+		-moz-animation: highlight 3s;
+		-o-animation: highlight 3s;
+		animation: highlight 3s;
+	}
+
 	.body, .user.user-card-message, .time {
 		-webkit-user-select: text;
 		-moz-user-select: text;
@@ -3073,7 +3080,12 @@ a.github-fork {
 		margin-left: 120px;
 		white-space: normal;
 		.calc(width, ~'100% - 120px');
+
 		h3 {
+			-webkit-user-select: text;
+			-moz-user-select: text;
+			-ms-user-select: text;
+			user-select: text;
 			font-size: 24px;
 			margin-bottom: 8px;
 			line-height: 27px;
@@ -3109,6 +3121,10 @@ a.github-fork {
 			}
 		}
 		p {
+			-webkit-user-select: text;
+			-moz-user-select: text;
+			-ms-user-select: text;
+			user-select: text;
 			line-height: 18px;
 			font-size: 12px;
 			font-weight: 300;
diff --git a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee
index aae87a8d192c6322c6e70d03482dc408de2fce86..cb79f341e3c8ca7eddd8db37ea21efa9c993d683 100644
--- a/packages/rocketchat-ui/lib/RoomHistoryManager.coffee
+++ b/packages/rocketchat-ui/lib/RoomHistoryManager.coffee
@@ -107,6 +107,8 @@
 		unless message?.rid
 			return
 
+		instance = Blaze.getView($('.messages-box .wrapper')[0]).templateInstance()
+
 		if ChatMessage.findOne message._id
 			wrapper = $('.messages-box .wrapper')
 			msgElement = $("##{message._id}", wrapper)
@@ -114,6 +116,15 @@
 			wrapper.animate({
 				scrollTop: pos
 			}, 500)
+			msgElement.addClass('highlight')
+
+			setTimeout ->
+				messages = wrapper[0]
+				instance.atBottom = messages.scrollTop >= messages.scrollHeight - messages.clientHeight;
+
+			setTimeout ->
+				msgElement.removeClass('highlight')
+			, 3000
 		else
 			room = getRoom message.rid
 			room.isLoading.set true
@@ -134,7 +145,6 @@
 					if item.t isnt 'command'
 						ChatMessage.upsert {_id: item._id}, item
 
-				instance = Blaze.getView($('.messages-box .wrapper')[0]).templateInstance()
 				Meteor.defer ->
 					readMessage.refreshUnreadMark(message.rid, true)
 					RoomManager.updateMentionsMarksOfRoom typeName
@@ -144,11 +154,18 @@
 					wrapper.animate({
 						scrollTop: pos
 					}, 500)
+
+					msgElement.addClass('highlight')
+
 					setTimeout ->
 						room.isLoading.set false
-						instance.atBottom = !result.moreAfter
+						messages = wrapper[0]
+						instance.atBottom = !result.moreAfter && messages.scrollTop >= messages.scrollHeight - messages.clientHeight;
 					, 500
 
+					setTimeout ->
+						msgElement.removeClass('highlight')
+					, 3000
 				room.loaded += result.messages.length
 				room.hasMore.set result.moreBefore
 				room.hasMoreNext.set result.moreAfter
diff --git a/packages/rocketchat-ui/lib/collections.coffee b/packages/rocketchat-ui/lib/collections.coffee
index 4c77cee3d1a9b58dff58e25c4a97866c291d0773..a1f8bd138791632e94983beebc0f5d9b6b73fa00 100644
--- a/packages/rocketchat-ui/lib/collections.coffee
+++ b/packages/rocketchat-ui/lib/collections.coffee
@@ -3,3 +3,8 @@
 @ChatSubscription = new Meteor.Collection 'rocketchat_subscription'
 @UserAndRoom = new Meteor.Collection null
 @CachedChannelList = new Meteor.Collection null
+
+RocketChat.models.Users = _.extend {}, RocketChat.models.Users, Meteor.users
+RocketChat.models.Subscriptions = _.extend {}, RocketChat.models.Subscriptions, @ChatSubscription
+RocketChat.models.Rooms = _.extend {}, RocketChat.models.Rooms, @ChatRoom
+RocketChat.models.Messages = _.extend {}, RocketChat.models.Messages, @ChatMessage
diff --git a/server/lib/accounts.coffee b/server/lib/accounts.coffee
index e68658e7dec5e959b11c7372e8120aa7d3c9ddcb..cc51761cb35ec15a4e087db075d9d2d1892d5aae 100644
--- a/server/lib/accounts.coffee
+++ b/server/lib/accounts.coffee
@@ -86,7 +86,7 @@ Accounts.insertUserDoc = _.wrap Accounts.insertUserDoc, (insertUserDoc, options,
 		else
 			roles.push 'user'
 
-	RocketChat.authz.addUsersToRoles(_id, roles)
+	RocketChat.authz.addUserRoles(_id, roles)
 
 	RocketChat.callbacks.run 'afterCreateUser', options, user
 	return _id
diff --git a/server/methods/createChannel.coffee b/server/methods/createChannel.coffee
index c2e8db8ce1da0be0424ea718f7bef65eaed48468..570d85bfa22ad85748d07b0b74a93c721a1b349e 100644
--- a/server/methods/createChannel.coffee
+++ b/server/methods/createChannel.coffee
@@ -41,9 +41,6 @@ Meteor.methods
 		room = RocketChat.models.Rooms.createWithTypeNameUserAndUsernames 'c', name, user, members,
 			ts: now
 
-		# set creator as channel moderator.  permission limited to channel by scoping to rid
-		RocketChat.authz.addUsersToRoles(Meteor.userId(), 'moderator', room._id)
-
 		for username in members
 			member = RocketChat.models.Users.findOneByUsername username
 			if not member?
@@ -57,6 +54,9 @@ Meteor.methods
 
 			RocketChat.models.Subscriptions.createWithRoomAndUser room, member, extra
 
+		# set creator as channel moderator.  permission limited to channel by scoping to rid
+		RocketChat.authz.addUserRoles(Meteor.userId(), 'moderator', room._id)
+
 		Meteor.defer ->
 			RocketChat.callbacks.run 'afterCreateChannel', user, room
 
diff --git a/server/methods/createPrivateGroup.coffee b/server/methods/createPrivateGroup.coffee
index 8bfa8304d98b5ba14b8c2d45a376e478f3cf6147..3a0dd23fa4c43d5b92095cd006470c0c5bd835ff 100644
--- a/server/methods/createPrivateGroup.coffee
+++ b/server/methods/createPrivateGroup.coffee
@@ -34,7 +34,7 @@ Meteor.methods
 			ts: now
 
 		# set creator as group moderator.  permission limited to group by scoping to rid
-		RocketChat.authz.addUsersToRoles(Meteor.userId(), 'moderator', room._id)
+		RocketChat.authz.addUserRoles(Meteor.userId(), 'moderator', room._id)
 
 		for username in members
 			member = RocketChat.models.Users.findOneByUsername(username, { fields: { username: 1 }})
diff --git a/server/methods/removeUserFromRoom.coffee b/server/methods/removeUserFromRoom.coffee
index 78a5137fe2a7536ae0bf03b72016241fa3ba1dcb..f45e43a5bab2b11b364cc42a5aaa600184f4bbf0 100644
--- a/server/methods/removeUserFromRoom.coffee
+++ b/server/methods/removeUserFromRoom.coffee
@@ -18,7 +18,7 @@ Meteor.methods
 		RocketChat.models.Subscriptions.removeByRoomIdAndUserId data.rid, removedUser._id
 
 		if room.t in [ 'c', 'p' ]
-			RocketChat.authz.removeUsersFromRoles(removedUser._id; 'moderator', data.rid)
+			RocketChat.authz.removeUserFromRoles(removedUser._id; 'moderator', data.rid)
 
 		fromUser = RocketChat.models.Users.findOneById fromId
 		RocketChat.models.Messages.createUserRemovedWithRoomIdAndUser data.rid, removedUser,
diff --git a/server/startup/initialData.coffee b/server/startup/initialData.coffee
index 47ba296a93f53a23843ae99c2b7a8f3aa9ee0b25..045b6d0673a8f0ed61df01526010d774b2f8470d 100644
--- a/server/startup/initialData.coffee
+++ b/server/startup/initialData.coffee
@@ -41,7 +41,7 @@ Meteor.startup ->
 							name: 'Admin'
 
 						Accounts.setPassword id, process.env.ADMIN_PASS
-						RocketChat.authz.addUsersToRoles( id, 'admin')
+						RocketChat.authz.addUserRoles( id, 'admin')
 
 					else
 						console.log 'E-mail exists; ignoring environment variables ADMIN_EMAIL and ADMIN_PASS'.red
@@ -55,5 +55,5 @@ Meteor.startup ->
 			# get oldest user
 			oldestUser = RocketChat.models.Users.findOne({ _id: { $ne: 'rocket.cat' }}, { fields: { username: 1 }, sort: {createdAt: 1}})
 			if oldestUser
-				RocketChat.authz.addUsersToRoles( oldestUser._id, 'admin')
+				RocketChat.authz.addUserRoles( oldestUser._id, 'admin')
 				console.log "No admins are found. Set #{oldestUser.username} as admin for being the oldest user"
diff --git a/server/startup/migrations/v27.coffee b/server/startup/migrations/v27.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..b3f6f7d7716b880f49b67110bb1557bd8ddf8021
--- /dev/null
+++ b/server/startup/migrations/v27.coffee
@@ -0,0 +1,11 @@
+Meteor.startup ->
+	Migrations.add
+		version: 27
+		up: ->
+			RocketChat.models.Users.update({}, { $rename: { roles: '_roles' } }, { multi: true })
+
+			RocketChat.models.Users.find({ _roles: { $exists: 1 } }).forEach (user) ->
+				for scope, roles of user._roles
+					RocketChat.models.Roles.addUserRoles(user._id, roles, scope)
+
+			RocketChat.models.Users.update({}, { $unset: { _roles: 1 } }, { multi: true })