Class: HaveAPI::Authentication::Token::Provider
- Defined in:
- lib/haveapi/authentication/token/provider.rb
Overview
Provider for token authentication.
This provider has to be configured using 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 Config#http_header or 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)
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
Attributes inherited from Base
Class Method Summary collapse
-
.with_config(cfg) ⇒ Object
Configure the token provider.
Instance Method Summary collapse
-
#authenticate(request) ⇒ Object
Authenticate request.
- #describe ⇒ Object
-
#initialize(server, v, cfg) ⇒ Provider
constructor
A new instance of Provider.
- #resource_module ⇒ Object
- #setup ⇒ Object
-
#token(request) ⇒ String
Extract token from HTTP request.
Methods inherited from Base
Constructor Details
#initialize(server, v, cfg) ⇒ Provider
Returns a new instance of Provider.
132 133 134 135 |
# File 'lib/haveapi/authentication/token/provider.rb', line 132 def initialize(server, v, cfg) @config = cfg.new(server, v) super(server, v) end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
130 131 132 |
# File 'lib/haveapi/authentication/token/provider.rb', line 130 def config @config end |
Class Method Details
Instance Method Details
#authenticate(request) ⇒ Object
Authenticate request
152 153 154 155 156 |
# File 'lib/haveapi/authentication/token/provider.rb', line 152 def authenticate(request) t = token(request) t && config.find_user_by_token(request, t) end |
#describe ⇒ Object
165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/haveapi/authentication/token/provider.rb', line 165 def describe { http_header: config.class.http_header, query_parameter: config.class.query_parameter, description: "The client authenticates with credentials, usually "+ "username and password, and gets a token. "+ "From this point, the credentials can be forgotten and "+ "the token is used instead. Tokens can have different lifetimes, "+ "can be renewed and revoked. The token is passed either via HTTP "+ "header or query parameter." } end |
#resource_module ⇒ Object
141 142 143 144 145 146 147 148 |
# File 'lib/haveapi/authentication/token/provider.rb', line 141 def resource_module return @module if @module provider = self @module = Module.new do const_set(:Token, provider.send(:token_resource)) end end |
#setup ⇒ Object
137 138 139 |
# File 'lib/haveapi/authentication/token/provider.rb', line 137 def setup @server.allow_header(config.class.http_header) end |
#token(request) ⇒ String
Extract token from HTTP request
161 162 163 |
# File 'lib/haveapi/authentication/token/provider.rb', line 161 def token(request) request[config.class.query_parameter] || request.env[header_to_env] end |