A small AngularJS Service to interact with Devise Authentication.
This service requires Devise to respond to JSON. To do that, simply add
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
respond_to :html, :json
# ...
endAditionally, if you have CSRF Forgery
Protection
enabled for your controller actions, you will also need to include the
X-CSRF-TOKEN header with the token provided by rails. The easiest way
to include this is to use the
ng-rails-csrf gem. You may also
setup
rails
to include a XSRF-TOKEN cookie, which Angular uses automatically.
AngularDevise is registered as angular-devise in
bower.
bower install --save angular-deviseYou can then use the main file at angular-devise/lib/devise-min.js.
Just register Devise as a dependency for your module. Then, the Auth
service will be available for use.
angular.module('myModule', ['Devise']).
config(function(AuthProvider) {
// Configure Auth service with AuthProvider
}).
controller('myCtrl', function(Auth) {
// Use your configured Auth service.
});Auth.currentUser() returns a promise that will be resolved into the
currentUser. There are three possible outcomes:
- Auth has authenticated a user, and will resolve with that user.
- Auth has not authenticated a user but the server has a previously authenticated session, Auth will attempt to retrieve that session and resolve with its user.
- Neither Auth nor the server has an authenticated session, and an unresolved promise will be returned. (see Interceptor for rationale.)
angular.module('myModule', ['Devise']).
controller('myCtrl', function(Auth) {
Auth.currentUser().then(function(user) {
// User was logged in, or Devise returned
// previously authenticated session.
console.log(user); // => {id: 1, ect: '...'}
}, function(error) {
// unauthenticated error
});
});Auth._currentUser will be either null or the currentUser's object
representation. It is not recommended to directly access
Auth._currentUser, but instead use
Auth.currentUser().
angular.module('myModule', ['Devise']).
controller('myCtrl', function(Auth) {
console.log(Auth._currentUser); // => null
// Log in user...
console.log(Auth._currentUser); // => {id: 1, ect: '...'}
});Auth.isAuthenticated() is a helper method to determine if a
currentUser is logged in with Auth.
angular.module('myModule', ['Devise']).
controller('myCtrl', function(Auth) {
console.log(Auth.isAuthenticated()); // => false
// Log in user...
console.log(Auth.isAuthenticated()); // => true
});Use Auth.login() to authenticate with the server. Keep in mind,
credentials are sent in plaintext; use a SSL connection to secure them.
creds is an object which should contain any credentials needed to
authenticate with the server. Auth.login() will return a promise that
will resolve to the logged-in user. See
AuthProvider.parse() for parsing the user into a usable
object.
angular.module('myModule', ['Devise']).
controller('myCtrl', function(Auth) {
var credentials = {
email: '[email protected]',
password: 'password1'
};
Auth.login(credentials).then(function(user) {
console.log(user); // => {id: 1, ect: '...'}
}, function(error) {
// Authentication failed...
});
});By default, login will POST to '/users/sign_in.json'. The path and
HTTP method used to login are configurable using:
angular.module('myModule', ['Devise']).
config(function(AuthProvider) {
AuthProvider.loginPath('path/on/server.json');
AuthProvider.loginMethod('GET');
});Use Auth.logout() to de-authenticate from the server. Auth.logout()
returns a promise that will be resolved to the old currentUser.
angular.module('myModule', ['Devise']).
controller('myCtrl', function(Auth) {
// Log in user...
// ...
Auth.logout().then(function(oldUser) {
// alert(oldUser.name + "you're signed out now.");
}, function(error) {
// An error occurred logging out.
});
});By default, logout will DELETE to '/users/sign_out.json'. The path and
HTTP method used to logout are configurable using:
angular.module('myModule', ['Devise']).
config(function(AuthProvider) {
AuthProvider.logoutPath('path/on/server.json');
AuthProvider.logoutMethod('GET');
});Use Auth.register() to register and authenticate with the server. Keep
in mind, credentials are sent in plaintext; use a SSL connection to
secure them. creds is an object that should contain any credentials
needed to register with the server. Auth.register() will return a
promise that will resolve to the registered user. See
AuthProvider.parse() for parsing the user into a
usable object.
angular.module('myModule', ['Devise']).
controller('myCtrl', function(Auth) {
var credentials = {
email: '[email protected]',
password: 'password1',
password_confirmation: 'password1'
};
Auth.register(credentials).then(function(registeredUser) {
console.log(registeredUser); // => {id: 1, ect: '...'}
}, function(error) {
// Registration failed...
});
});By default, register will POST to '/users.json'. The path and HTTP
method used to register are configurable using:
angular.module('myModule', ['Devise']).
config(function(AuthProvider) {
AuthProvider.registerPath('path/on/server.json');
AuthProvider.registerMethod('GET');
});AngularDevise creates an $http
Interceptor
that listens for 401 Unauthorized response codes. Its purpose is to
catch unauthorized requests on-the-fly and seamlessly recover. When it
catches a 401, it will:
- create a deferred
- broadcast a
devise:unauthorizedevent passing:- the ajax response
- the deferred
- return the deferred's promise
Since the deferred is passed to the devise:unauthorized event, you are
free to resolve it (and the request) inside of the event listener. For
instance:
angular.module('myModule', []).
controller('myCtrl', function($scope, Auth, $http) {
// Guest user
// Catch unauthorized requests and recover.
$scope.$on('devise:unauthorized', function(event, xhr, deferred) {
// Ask user for login credentials
Auth.login(credentials).then(function() {
// Successfully logged in.
// Redo the original request.
return $http(xhr.config);
}).then(function(response) {
// Successfully recovered from unauthorized error.
// Resolve the original request's promise.
deferred.resolve(response);
}, function(error) {
// There was an error.
// Reject the original request's promise.
deferred.reject(error);
});
});
// Request requires authorization
// Will cause a `401 Unauthorized` response,
// that will be recovered by our listener above.
$http.delete('/users/1').then(function(response) {
// Deleted user 1
}, function(error) {
// Something went wrong.
});
});The Interceptor can be disabled globally or on a per-request basis using the
ignoreAuth setting.
angular.module('myModule', ['Devise']).
config(function(AuthProvider) {
// Ignore 401 Unauthorized everywhere
AuthProvider.ignoreAuth(true);
}).
controller('myCtrl', function($http) {
// Enable per-request
$http({
url: '/',
ignoreAuth: false,
// ...
});
});By default, AngularDevise uses the following HTTP methods/paths:
- login: POST /users/sign_in.json
- logout: DELETE /users/sign_out.json
- register: POST /users.json
And the following parse function:
function parse(response) {
var user = response.data;
return user;
}All of these can be configured using a .config block in your module.
angular.module('myModule', ['Devise']).
config(function(AuthProvider) {
// Customise login
AuthProvider.loginMethod('GET');
AuthProvider.loginPath('/admins/login.json');
// Customise logout
AuthProvider.logoutMethod('POST');
AuthProvider.logoutPath('/user/logout.json');
// Customise register
AuthProvider.registerMethod('PATCH');
AuthProvider.registerPath('/user/sign_up.json');
// Ignore 401 Unauthorized everywhere
// Disables `devise:unauthorized` interceptor
AuthProvider.ignoreAuth(true);
// Customize user parsing
// NOTE: **MUST** return a truth-y expression
AuthProvider.parse(function(response) {
return new User(response.data);
});
});AngularDevise is maintained by Cloudspace, and is distributed under the MIT License.

