I've implemented Matteo Melanis great blog article A Simple Token Authentication Service for Mobile Devices. It works beautifully with the Chrome extension Postman. However, when I try to fetch a user authentication token with cUrl, I'm running into a bizzare problem.
First the development.log entry for the (successful) authentication fetch using Postman:
Started POST "/api/v1/tokens.json?email=my@mail.com&password=[FILTERED]" for 127.0.0.1 at 2013-11-25 11:28:21 +0100
Processing by Api::V1::TokensController#create as JSON
Parameters: {"email"=>"my@mail.com", "password"=>"[FILTERED]"}
[1m[36mUser Load (1.4ms)[0m [1mSELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1[0m
Entered create method
[1m[35mUser Load (3.9ms)[0m SELECT "users".* FROM "users" WHERE "users"."email" = 'my@mail.com' LIMIT 1
Completed 200 OK in 99ms (Views: 0.3ms | ActiveRecord: 5.3ms)
Then, when I run $ curl -X POST "https://localhost:3000/api/v1/tokens.json?email=my@mail.com&password=somepassword" -d "email=my@mail.com&password=somepassword" -v -k -i
, I get
Started POST "/api/v1/tokens.json?email=my@mail.com&password=[FILTERED]" for 127.0.0.1 at 2013-11-25 11:29:01 +0100
Processing by Api::V1::TokensController#create as JSON
Parameters: {"email"=>"my@mail.com", "password"=>"[FILTERED]"}
Completed 401 Unauthorized in 12ms
You might ask why I provided the parameters both as HTTP Post data, and as a query string. Well, my initial research with the curl lib sample http-post.c suggest the former, while Postmans successful query suggests the latter. I've tried all combinations of these, but nothing works, so I'm pretty lost.
In the Api::V1::TokensController
, I've added logging whenever the create method is being called, that is
class Api::V1::TokensController < ApplicationController
skip_before_filter :verify_authenticity_token
respond_to :json
def create
Rails.logger.debug("Entered create method")
email = params[:email]
password = params[:password]
if request.format != :json
render :status=>406, :json=>{:message=>"The request must be json"}
return
end
if email.nil? or password.nil?
render :status=>400,
:json=>{:message=>"The request must contain the user email and password."}
return
end
@user=User.find_by_email(email.downcase)
if @user.nil?
logger.info("User #{email} failed signin, user cannot be found.")
render :status=>401, :json=>{:message=>"Invalid email or password."}
return
end
# http://rdoc.info/github/plataformatec/devise/master/Devise/Models/TokenAuthenticatable
@user.ensure_authentication_token!
if not @user.valid_password?(password)
logger.info("User #{email} failed signin, password \"#{password}\" is invalid")
render :status=>401, :json=>{:message=>"Invalid email or password."}
else
render :status=>200, :json=>{:token=>@user.authentication_token}
end
end
def destroy
@user=User.find_by_authentication_token(params[:id])
if @user.nil?
logger.info("Token not found.")
render :status=>404, :json=>{:message=>"Invalid token."}
else
@user.reset_authentication_token!
render :status=>200, :json=>{:token=>params[:id]}
end
end
end
As can be seen from the logs, create method is being called in the first place, but not in the second. It is as if Api::V1::TokensController
's skip_before_filter :verify_authenticity_token
is ignored altogether. But how can that be?
Any suggestion is greatly appreciated!