Class: FlatApi::TokenManager

Inherits:
Object
  • Object
show all
Defined in:
lib/flat_api/oauth.rb

Overview

Holds the current tokens and refreshes them at most once at a time.

Single-flight matters: two concurrent requests hitting an expired token must not both refresh, because the second refresh would invalidate the token the first just obtained.

Instance Method Summary collapse

Constructor Details

#initialize(tokens, helper: nil, on_token_refresh: nil) ⇒ TokenManager

Returns a new instance of TokenManager.



86
87
88
89
90
91
# File 'lib/flat_api/oauth.rb', line 86

def initialize(tokens, helper: nil, on_token_refresh: nil)
  @tokens = tokens
  @helper = helper
  @on_token_refresh = on_token_refresh
  @mutex = Mutex.new
end

Instance Method Details

#access_tokenObject

Refreshes when the token has expired, which is the whole point of a TokenManager: a caller installs this as Configuration#access_token_getter and never thinks about expiry again. Returning @tokens.access_token unconditionally made Tokens#expired? dead code, and every request after the expiry failed with a 401 that a refresh would have avoided.



97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/flat_api/oauth.rb', line 97

def access_token
  return @tokens.access_token unless @tokens.expired?

  @mutex.synchronize do
    # Checked again inside the lock: a thread that waited here may find the token already
    # refreshed, and refreshing twice would spend a second round trip and, with a provider
    # that rotates refresh tokens, invalidate the one the first thread just stored.
    next @tokens.access_token unless @tokens.expired?

    refresh_locked
  end
end

#refreshObject

Refreshes unconditionally. Use it to force a refresh; access_token already handles expiry.



111
112
113
# File 'lib/flat_api/oauth.rb', line 111

def refresh
  @mutex.synchronize { refresh_locked }
end