class HaveAPI::Authentication::Token::Provider

Provider for token authentication.

This provider has to be configured using {HaveAPI::Authentication::Token::Config}.

Token auth contains API resource ‘token`. User can request a token by calling action `Request`. The returned token is then used for authenticating the user. Client sends the token with each request in configured {HaveAPI::Authentication::Token::Config#http_header} or {HaveAPI::Authentication::Token::Config#query_parameter}.

Token can be revoked by calling action ‘Revoke` and renewed with `Renew`.

Example usage:

Token model:

class ApiToken < ActiveRecord::Base
  belongs_to :user

  validates :user_id, :token, presence: true
  validates :token, length: {is: 100}

  enum lifetime: %i(fixed renewable_manual renewable_auto permanent)

  def renew
    self.valid_to = Time.now + interval
  end
end

Authentication provider configuration:

class MyTokenAuthConfig < HaveAPI::Authentication::Token::Config
  request do
    handle do |req, res|
      user = ::User.find_by(login: input[:user], password: input[:password])

      if user.nil?
        res.error = 'invalid user or password'
        next res
      end

      token = SecureRandom.hex(50)
      valid_to =
        if req.input[:lifetime] == 'permanent'
          nil
        else
          Time.now + req.input[:interval]

      user.tokens << ::Token.new(
        token: token,
        lifetime: req.input[:lifetime],
        valid_to: valid_to,
        interval: req.input[:interval],
        label: req.request.user_agent,
      )

      res.token = token
      res.valid_to = valid_to
      res.complete = true
      res.ok
    end
  end

  renew do
    handle do |req, res|
      t = ::Token.find_by(user: req.user, token: req.token)

      if t && t.lifetime.start_with('renewable')
        t.renew
        t.save
        res.valid_to = t.valid_to
        res.ok
      else
        res.error = 'unable to renew token'
        res
      end
    end
  end

  revoke do
    handle do |req, res|
      req.user.tokens.delete(token: req.token)
      res.ok
    end
  end

  def find_user_by_token(request, token)
    t = ::Token.find_by(token: token)

    if t
      # Renew the token if needed
      if t.lifetime == 'renewable_auto'
        t.renew
        t.save
      end

      t.user # return the user
    end
  end
end

Finally put the provider in the authentication chain:

api = HaveAPI.new(...)
...
api.auth_chain << HaveAPI::Authentication::Token.with_config(MyTokenAuthConfig)