So you have an Angular application running on a domain (http://myfabulousapp.com) and the Rails API running on another domain (http://api.myfabulousapp.com). It’s all working well, but now you want to implement authentication using Devise. How do you do this?


Before start:

Our “test” project folder structure:

Let’s create our “test” project with these commands:

Open another terminal window:

The app/index.html:

The app/app.js:

The main page:


1. Install rack-cors gem


2. Allow Angular to access Rails

PS: don’t put an “:options”. If you do that, you won’t be able to destroy sessions, because Angular will replace “delete” by “options” when communicating with another domain (and Devise won’t recognize the “option” verb as a “delete”)

PS 2: don’t forget to restart the server!!!


2.5. If Rails “–api”, enable Sessions


3. Install angular_devise library on your Angular app


4. Configure Angular:

A) Add Devise module to the app:

B) Add $http to always provide credentials:

C) Set Rails API urls (change api_url to your actual API location):

Or a more extensive example:


5. Remove the CSRF protection from Rails (I know, I know…)

PS: notice that I’m also including a “:json” to force Devise to respond to json calls.

PS: after do some tests and it’s all working, you can use a better solution to deal with CSRF, like use this angular_rails_csrf gem (which doesn’t worked for me, but maybe you have more luck – see my tries here).

PS II: “I don’t recommend to disable CSRF protection, blah, blah, blah…” Yeah, me neither, it’s just a test in order to troubleshooting why sessions are being lost after a refresh.


6. After a refresh, get the session back

  • Matthias Orgler

    As for the CSRF step: Rails seems to recommend that you simply skip the protection for JSON requests (http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html):

    class ApplicationController < ActionController::Base
    protect_from_forgery
    skip_before_action :verify_authenticity_token, if: :json_request?

    protected

    def json_request?
    request.format.json?
    end
    end

  • Matthias Orgler

    btw: very nice article! Thanks a lot!

  • Ankit

    Hi, I have a problem. I am able to login but when i refresh i logout. Auth.currentUser() gives 401 error. How can i fix it?

  • Nerio Navea

    Hi, I had a trouble testing your example when connect the index.html with the angular-ui-router.js script the src attribute must have this value “/bower_components/angular-ui-router/release/angular-ui-router.js” but all the rest are very helpfull thanks!

  • Nerio Navea

    Hi, I’m trying to make a remote client for a rails-api but when I try to config the AuthProvider with a diferent baseUrl then returs me a error here is my code:

    https://gist.github.com/nerionavea/a9ef593201bb32bb5902

    • Daniel Loureiro

      There’s a typo in your code:
      “‘http://localhost:3000”

      Should it be (look the orphan single quote at second character):
      “http://localhost:3000”

      • Nerio Navea

        i fix the error but still returns me this:

        Error: [$injector:modulerr] Failed to instantiate module clientApp due to:
        AuthProvider.baseUrl is not a function
        @http://localhost:4567/index.html:13:5

        I was searching on the ‘/lib/devise.js’ file and in AuthProvider there is not a baseUrl method defined. do i have to require another file on this?, because there is another file in ‘/src’ folder with have a file called ‘Auth.js’ and this file have a definition of ‘baseUrl’ method in AuthProvider. sorry but i’m confussed with this

        • Daniel Loureiro

          I just realized that my tutorial is incomplete. It lacks the code that binds Angular with Rails API :P

          Instead of baseUrl, why don’t you do something like this:

          var api_url = 'http://localhost:3000/';

          AuthProvider.loginPath(api_url + 'users/sign_in.json');
          AuthProvider.loginMethod('POST');
          AuthProvider.resourceName('user');

          AuthProvider.registerPath(api_url + 'users.json');
          AuthProvider.registerMethod('POST');
          AuthProvider.resourceName('user');

          AuthProvider.logoutPath(api_url + 'users/sign_out.json');
          AuthProvider.logoutMethod('DELETE');

          • Nerio Navea

            It works, thanks!

  • Left me in the middle of nowhere. Sheesh, wasn’t that helpful.