5

I made Devise authentication to log out via GET, but couldn't make it log out using this Angular.js code:

$scope.logout = ->
  $http.get('/users/sign_out').success ->
    #If it does not redirect from 'editor' to 'login' then you haven't actually logged out
    $location.path('editor')

Devise's logout behaviour seems to be random - sometimes it logs out, sometimes not. And if I enter /users/sign_out into browser's address bar, it logs out always.

Ok, I switched the Devise authentication's log out to POST request to get rid of caching problems and used following Angular.js code:

$scope.logout = ->
  $http.post('/users/sign_out').success ->
    $location.path('editor')

The first time it logged out fine, as always, but then I couldn't make it to log out.

I decided to make my own method to see what happens:

match '/logout' => 'api#logout', :via => :post

class ApiController < ApplicationController
  before_filter :authenticate_user!

  def logout
    sign_out
    if current_user
      puts 'Has not signed out!'
    else
      puts 'Has signed out!'
    end
    head :ok
  end
end

and detected that after sign_out the current_user is always nil, but then the Angular application by some miracle manages to access other methods of ApiController, and current_user isn't nil there!

I do not understand that. Ok, let us suppose that there may follow some other HTTP request, right after (or at the same time as) logout request, passing the authentication cookie and Devise re-logins, but shouldn't the session ID passed in cookie be expired immediately after call of sign_out method?!

Paul
  • 25,812
  • 38
  • 124
  • 247

1 Answers1

2

sorry I never responded earlier, hope this helps

My Sesisons Controller

$scope.signOutUser = function () {
  $http.delete('/api/users/sign_out', {
    auth_token: Session.currentUser // just a cookie storing my token from devise token authentication.
  }).success( function(result) {
    $cookieStore.remove('_pf_session');
    $cookieStore.remove('_pf_name');
    $cookieStore.remove('_pf_email');
    location.reload(true); // I need to refresh the page to update cookies
  }).error( function(result) {
    console.log(result);
  });
} 

My Devise Sessions Controller I overrode

class SessionsController < Devise::SessionsController
  before_filter :authenticate_user!, only: :destroy

  def destroy
    token = params[:auth_token]
    @user = User.find_by_authentication_token(token)
    @user.reset_authentication_token!
    sign_out(@user)
    render status: :ok, json: {message: "You have successfully logged out"}
  end
end

As you can see, I'm not using Rails cookies and thus my answer may not pertain. If I did I would probably add a line like session[:user] = nil in my destroy action.

shicholas
  • 6,123
  • 3
  • 27
  • 38
  • Now remove the `$cookieStore.remove` calls and see if it really logs out at the server side. Btw: Devise has no cookies with names `_pf_session`, `_pf_name`, `_pf_email` – Paul Jun 13 '13 at 11:46
  • the two systems run in parallel and only talk to each other via JSON. On sign-in, Angular creates the `pf_session`, `pf_name` and `pf_email` cookies in the browser. The server just makes sure that no requests w/o a devise generated token are authorized. If an unauthorized request gets sent, I used [Witold's HTTP Interceptor](http://witoldsz.github.io/angular-http-auth/) to get my client side app to flip out upon an unauthorized request. However, after talking to my ruby group last night there might be some CSRF issues and that I should use rails cookies. I'll post when I figure that out. – shicholas Jun 13 '13 at 17:29