Class: AccessToken

Inherits:
Object
  • Object
show all
Defined in:
lib/access_token.rb,
lib/access_token/version.rb,
lib/access_token/null_store.rb,
lib/access_token/redis_store.rb,
lib/access_token/memcached_store.rb

Defined Under Namespace

Classes: MemcachedStore, NullStore, RedisStore

Constant Summary collapse

BEARER_HEADER =
'Bearer'.freeze
EXPIRES_HEADER =
'Expires'.freeze
AUTHORIZATION_HEADER =
'HTTP_AUTHORIZATION'.freeze
TIME_KEY =
'time'.freeze
ID_KEY =
'id'.freeze
SIGNATURE_KEY =
'signature'.freeze
BEARER_REGEX =
/\ABearer (.*?)\z/
VERSION =
'0.1.0'

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(request:, response:, secret:, ttl: 3600, store: NullStore.new, encryptor: Parsel::JSON) ⇒ AccessToken

Returns a new instance of AccessToken.



40
41
42
43
44
45
46
47
# File 'lib/access_token.rb', line 40

def initialize(request:, response:, secret:, ttl: 3600, store: NullStore.new, encryptor: Parsel::JSON)
  @request = request
  @response = response
  @store = store
  @secret = secret
  @ttl = ttl
  @encryptor = encryptor
end

Instance Attribute Details

#encryptorObject (readonly)

Set the token encryptor strategy. By default it uses the Parsel::JSON encryptor.



31
32
33
# File 'lib/access_token.rb', line 31

def encryptor
  @encryptor
end

#requestObject (readonly)

Set the HTTP request object. It must implement the ‘ip` and `user_agent` methods.



19
20
21
# File 'lib/access_token.rb', line 19

def request
  @request
end

#responseObject (readonly)

Set the HTTP response object. It must implement the ‘headers` method.



23
24
25
# File 'lib/access_token.rb', line 23

def response
  @response
end

#secretObject (readonly)

Set the encryption secret.



38
39
40
# File 'lib/access_token.rb', line 38

def secret
  @secret
end

#storeObject (readonly)

Set the token store strategy. By default it uses in-memory store.



27
28
29
# File 'lib/access_token.rb', line 27

def store
  @store
end

#ttlObject (readonly)

Set the token TTL. Defaults to 86400 (24 hours).



35
36
37
# File 'lib/access_token.rb', line 35

def ttl
  @ttl
end

Instance Method Details

#bearerObject



77
78
79
# File 'lib/access_token.rb', line 77

def bearer
  request.env[AUTHORIZATION_HEADER].to_s[BEARER_REGEX, 1]
end

#fresh?(timestamp) ⇒ Boolean

Returns:

  • (Boolean)


81
82
83
# File 'lib/access_token.rb', line 81

def fresh?(timestamp)
  timestamp > Time.now.to_i - ttl
end

#request_signatureObject



49
50
51
# File 'lib/access_token.rb', line 49

def request_signature
  @request_signature ||= Digest::SHA1.hexdigest("#{request.ip}#{request.user_agent}")
end

#resolve(token = bearer) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/access_token.rb', line 64

def resolve(token = bearer)
  return unless store.key?(token)

  data = encryptor.decrypt(secret, token)
  store.del(token)

  return unless data
  return unless fresh?(data[TIME_KEY])
  return unless request_signature == data[SIGNATURE_KEY]

  data[ID_KEY]
end

#update(record) ⇒ Object



53
54
55
56
57
58
59
60
61
62
# File 'lib/access_token.rb', line 53

def update(record)
  now = Time.now
  timestamp = now.to_i
  data = {TIME_KEY => timestamp, SIGNATURE_KEY => request_signature, ID_KEY => record.id}
  token = encryptor.encrypt(secret, data)
  store.set(token, timestamp, ttl)
  response[BEARER_HEADER] = token
  response[EXPIRES_HEADER] = (Time.now + ttl).httpdate
  token
end