api authentication redefined
What we were doing for years?
What's wrong with that?
- bulletproof cross-domain cookies are hard to implement
- you have to deal with CSRF
- awkward to use outside the web, eg. in native apps
- you have to keep state on API
alternative:
token authentication

advantages of token authentication
- CORS is a breeze
- decoupling – you can generate token anywhere
- CSRF attack does not exist
- you store session on client side
- stateless API – no login, logout or sessions
Implementation? rails side:
class AuthToken < ActiveRecord::Base
belongs_to :user
def self.authenticate(token)
find_by(token: token).try(:user)
end
def self.fetch(user)
return user.auth_token if user.auth_token.present?
user.create_auth_token(token: generate_token)
end
def self.generate_token
SecureRandom.hex
end
end
module TokenAuth
def current_user
authenticate_with_http_token { |token| AuthToken.authenticate(token) }
end
end
IMPLEMENTATION? RAILS SIDE:
class SessionsController
def create
user = User.authenticate_with_credentials(params[:login], params[:password])
if user
render json: { token: AuthToken.fetch(user) }
else
head :forbidden
end
end
end
...and javascript side
getAuthorizationHeader: ->
token = $.cookie('auth-token')
"Token #{token}" if token
setCookie: (data) ->
$.cookie('auth-token', data.token, { expire: 365 })
$.ajaxPrefilter (options, originalOptions, xhr) =>
xhr.setRequestHeader('Authorization', getAuthorizationHeader())
$.post('/sessions.json', { login: 'user', password: 'secret' }).done(setCookie)
No need to:
- send request to server to sign out
- worry about remembering session, it can be done client-side
few things we should know
- we have to store tokens on client somehow
- tokens can expire like cookies
- streaming is a bit tricky – we have to send signed request
- we have to deal with XSS instead of CSRF
- we can use JSON Web Tokens
json web tokens
- draft specification for token exchanging
- encode any information like hash with user
- allows to specify expiration time of token
- have a lib for most of languages
- probably better way to issue tokens than SecureRandom
JSON WEB TOKENS
user_id = 123
claim = {
iss: user_id,
exp: 1.week.from_now,
nbf: Time.now
}
jwt = JSON::JWT.new(claim).to_s
jws = JSON::JWT.new(claim).sign(key)
jws.to_s
# With signature & encryption
jwe = jws.encrypt(key, algorithm, encryption_method)
jws.to_s
questions?
sources
- http://www.sitepoint.com/using-json-web-tokens-node-js/
- http://auth0.com/blog/2014/01/07/angularjs-authentication-with-cookies-vs-token/
- http://auth0.com/blog/2014/01/27/ten-things-you-should-know-about-tokens-and-cookies/
- http://tools.ietf.org/html/draft-ietf-oauth-json-web-token
deck
By Lucjan Suski
deck
- 363