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)


Thats it!

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

  • 348