3

I have a Rails App (that is mainly a JSON API) I'm Using Devise for authentication using JSON request from whatever source (web , mobile) and I'm using Simple Token Authentication to authenticate users using HTTP headers.

I'm not sure how the implementation should look like, but I have drafted an implementation that almost works.

There is only one problem. and that is when user tries to sign out... typically it should invalidate the authentication token for the user... but it doesn't, I'm not sure where is the problem really... whether it's with the Devise or the Simple Token Auth... so any help is greatly appreciated.

but here is the code

  # router
  devise_for :users, controllers: { sessions: 'sessions',
                                    registrations: 'registrations' }
  api vendor_string: 'app', default_version: 1, path: '', format: 'json' do
    version 1 do
      cache as: 'v1' do
        resource :some_resource
      end
    end

the session controller is like this

class SessionsController < Devise::SessionsController  
  respond_to :json
  skip_filter :verify_signed_out_user, only: :destroy

  def create
    self.resource = warden.authenticate!(scope: resource_name)
    render :create, status: :created
  end

  def destroy
    current_user.authentication_token = nil
    # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ take note of this line
    current_user.save!
    super
  end
end  

the previous noted line seems to have a problem... when a user provide a wrong token header, it's still working and the current user refers to the user who shouldn't be authenticated in the first place.. for example here are 2 calls fro, the specs

describe 'DELETE sessions#destroy' do
    let(:user) { Fabricate(:confirmed_user) }
    let(:auth_token) { user.authentication_token }
    describe 'with request headers' do
      context 'valid credentials' do
        it 'Returns 204' do
          delete '/users/sign_out', {}, {
            HTTP_CONTENT_TYPE: 'application/json',
            HTTP_ACCEPT: "application/vnd.app+json; version=1",
            "X-User-Email" => user.email,
            "X-User-Token" => user.authentication_token
          }

          user.reload
          expect(response.status).to eq 204
          expect(user.authentication_token).not_to eq auth_token
          #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this is ok cause it's the valid user
        end
      end

      context 'invalid credentials' do
        it 'Returns 204' do
          delete '/users/sign_out', {}, {
            HTTP_CONTENT_TYPE: 'application/json',
            HTTP_ACCEPT: "application/vnd.app+json; version=1",
            "X-User-Email" => user.email,
            "X-User-Token" => 'Invalid'
          }

          user.reload
          expect(response.status).to eq 204
          expect(user.authentication_token).to eq auth_token
          #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this FAILS
          # why did the user get new auth token when didn't sign out ????
        end
      end
    end

this is also reported on Github

and for completeness here is the application controller

class ApplicationController < ActionController::Base
  # The API responds only to JSON
  respond_to :json

  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  # default to protect_from_forgery with: :exception
  protect_from_forgery with: :null_session

  # Token Authenticatable for API
  acts_as_token_authentication_handler_for User
end
a14m
  • 7,808
  • 8
  • 50
  • 67

2 Answers2

1

From simple_authentication_token page on github, the current_user.authentication_token will automatically generated if it was blank (nil) on each time current_user will be saved.

Assuming user is an instance of User, which is token authenticatable: each time user will be saved, and user.authentication_token.blank? it receives a new and unique authentication token (via Devise.friendly_token).

Update

Add acts_as_token_authentication_handler_for User in your sessions_controller.rb

henggana
  • 157
  • 1
  • 8
  • Yeah i know, but the test shows that it doesn't work... This is also not my first project with simple auth token... And i can assure you that this issue exists on all of them – a14m Jan 07 '15 at 03:00
0

Please read on https://github.com/gonzalo-bulnes/simple_token_authentication/issues/224 . I think that is normal behaviour. You need delete the token on the client side(device)

Mada Aryakusumah
  • 611
  • 11
  • 16