39

So, I'm trying to use tokens with Devise (version 1.0.3 with Rails 2.3.8) to let a user log in, but I'm not entirely sure where to begin.

http://zyphdesignco.com/blog/simple-auth-token-example-with-devise

The above tutorial helped me turn on the token functionality, and showed how to generate (or delete) tokens...but the whole POINT of tokens is to use them to authorize a user, correct?

When I look at a user in the console, I can say user.authentication_token, and get something back like: "Qm1ne93n_XkgmQTvxDmm", which is all well and good...but where do I go from there?

I tried hitting the sign_in root using the following command line command:

curl -d "authentication_token=Qm1ne93n_XkgmQTvxDmm" localhost:3000/users/sign_in

And definitely didn't get a successful log in.

In the sessions controller, I see that they call:

authenticate(resource_name)

Which I'm ASSUMING is somewhere in the module:

include Devise::Controllers::InternalHelpers

which gets included, but I don't know where to look for that (it's definitely not in the source's controller folder). If I could look at how authenticate works, I could see if it even LOOKS at tokens...

DOES Devise let you actually log in with tokens, or does it just have a framework for generating them? If it does let you log in with them...HOW do you do this? Can you not use curl (i.e. does it have to be in a browser? If so, I'd hafta roll my own solution, I NEED non-browser support.). If it doesn't, how do I roll my own?

anshumans
  • 4,045
  • 2
  • 18
  • 25
J.R.
  • 5,789
  • 11
  • 55
  • 78

3 Answers3

36

My understanding is that you can use the tokens to log in or to hit arbitrary pages that need authentication, even with cURL. If you look in config/initializers/devise.rb, there should be a line that says something like:

config.token_authentication_key = :auth_token

Whatever the name of the token_authentication_key is should match what you put as the query or form parameter in your request. You used authentication_token in your example, not sure if you changed devise.rb to match that or not.

If you want to figure out how things are working internally, I would try git clone git://github.com/plataformatec/devise.git and search for the methods you need clarification of.

Here are some sample cURL requests (I made a custom Users::SessionsController that extends Devise::SessionsController and overrides the create method to handle JSON.)

class Users::SessionsController < Devise::SessionsController
  def create
    resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
    set_flash_message(:notice, :signed_in) if is_navigational_format?
    sign_in(resource_name, resource)

    respond_to do |format|
      format.html do
        respond_with resource, :location => redirect_location(resource_name, resource)
      end
      format.json do
        render :json => { :response => 'ok', :auth_token => current_user.authentication_token }.to_json, :status => :ok
      end
    end
  end
end 

And then the cURL requests I gave:

curl -X POST 'http://localhost:3000/users/sign_in.json' -d 'user[email]=example@example.com&user[password]=password'
-> {"response":"ok","auth_token":"ABCDE0123456789"}

curl -L 'http://localhost:3000/profile?auth_token=ABCDE0123456789'
-> got page that I wanted that needs authentication
Anthony Panozzo
  • 3,274
  • 1
  • 24
  • 22
  • 1
    Thanks a lot! This really helped *nodnod* I wasn't aware that I was supposed to pass "auth token" (authentication_token is how it's stored in the db). I also thought it was supposed to be passed as a log in, not with every command. Works like a charm, now! – J.R. Jan 13 '11 at 14:03
  • Anthony, could you advice what could be wrong if auth_token is not generated during user sign_up/sign_in? I'm using mongo_mapper. In the model I've got ensure_authentication_token! method, which resets token if it's blank. – Mike Bevz May 04 '11 at 15:13
  • Seems like a different question. Maybe you could open another question for it. – Anthony Panozzo May 04 '11 at 19:25
  • 1
    Off topic, I know, but Mike Bevz: Did you also put in an authentication token field in the database? I remember back when I was starting I had accidentally only added it to the model, and not the database migration. – J.R. Oct 07 '11 at 19:43
5

see this article: http://www.hyperionreactor.net/blog/token-based-authentication-rails-3-and-rails-2

Basically all you need is to append the token to your requests and you're automatically authenticated, i.e. localhost:3000/posts.xml?auth_token=the_token

zero_padded
  • 123
  • 1
  • 5
  • 5
    To read the article - http://web.archive.org/web/20101003082438/http://www.hyperionreactor.net/blog/token-based-authentication-rails-3-and-rails-2 – Cameron Martin Aug 09 '12 at 14:51
2

This was a good starting point for me:

Migration to add authentication_token:

class AddTokenBasedAuthentication < ActiveRecord::Migration
  def change
    add_column :users, :authentication_token, :string
    add_index :users, :authentication_token, unique: true
  end
end

And then in the application controller:

class ApplicationController < ActionController::Base
  before_filter :authenticate_user_from_token!
  before_action :authenticate_user!, except: <your login GET action>

  private 

  def authenticate_user_from_token!
    email = params[:email].presence
    user  = email && User.find_by(email: email)

    sign_in user if user && Devise.secure_compare(user.authentication_token, params[:auth_token])
  end
end

And then the link construction is just

www.yoursite.com/?email=the@email.address&auth_token=whatever_auth_token_is_stored_for_that_user

sources: this gist linked to from devise's wiki, & this tutorial (mentioned above)

stevenspiel
  • 5,775
  • 13
  • 60
  • 89