Reputation: 6057
I'm using Ember
front-end with Grape
API and to authenticate a page I have something like:
def current_user
return nil if headers['Authorization'].nil?
@current_user ||= User.find_by_authentication_token(
headers['Authorization']
)
end
At the moment I'm using ember-simple-auth
which sends something like as a header:
Token token="n2Rs5tokenLH", email="[email protected]"
Check out the Grape logger:
User Load (38.1ms) SELECT "users".* FROM "users" WHERE "users"."authentication_token" = 'Token token="n2Rs5tokenLH", email="[email protected]"' LIMIT 1
Now in rails I usually use authenticate_or_request_with_http_token
to handle this. and I don't want to handle this manually using stuff like gsub
or regular expressions. What is the best way to handle this in Grape?
Please note that the Grape API is mounted inside a rails project and inside app/api/backend/v1/default.rb
:
module Backend
module V1
module Defaults
extend ActiveSupport::Concern
included do
version 'v1', using: :path
format :json
prefix :api
rescue_from :all do |e|
Backend::Base.logger.error e
end
helpers do
def current_user
return nil if headers['Authorization'].nil?
@current_user ||= User.find_by_authentication_token(
headers['Authorization']
)
end
def authenticate!
error!('401 Unauthorized', 401) unless current_user
end
end
end
end
end
end
Edit:
I just found out that I can use ActionController::HttpAuthentication::Token.token_and_options
to do the job, however I'm not sure how should I include this in Grape
project.
The structure of the app looks like:
⇒ tree app/api
app/api
└── backend
├── base.rb
└── v1
├── defaults.rb
└── ....
I tried to include ActionController::HttpAuthentication::Token
in defaults.rb
something like:
helpers do
include ActionController::HttpAuthentication::Token
def current_user
return nil if headers['Authorization'].nil?
@current_user ||= User.find_by_authentication_token(
token_and_options(headers['Authorization'])
)
end
def authenticate!
error!('401 Unauthorized', 401) unless current_user
end
end
But now I'm getting:
undefined method `authorization' for #<String:0x007ff51cdb85f8>
Upvotes: 0
Views: 3429
Reputation: 131
You're on the right path: use token_params_from and pass in the Authorization header directly.
helpers do
include ActionController::HttpAuthentication::Token
def current_user
return nil if headers['Authorization'].nil?
@current_user ||= User.find_by_authentication_token(token)
end
def token
token_params_from(headers['Authorization']).shift[1]
end
def authenticate!
error!('401 Unauthorized', 401) unless current_user
end
end
The undefined method
exception is due to token_and_options expecting a ActionDispatch::Request object where you're providing a String.
Upvotes: 4
Reputation: 6057
I had to add a customized token_and_options
function which looks like:
def token_and_options(auth_string)
if header = auth_string.to_s[/^Token (.*)/]
values = $1.split(',').
inject({}) do |memo, value|
value.strip!
key, value = value.split(/\=\"?/)
value.chomp!('"')
value.gsub!(/\\\"/, '"')
memo.update(key => value)
end
values.delete("token")
end
end
And then parse token with something like: token_and_options(headers['Authorization'])
Upvotes: 0