A GenServer that manages OAuth2 client_credentials tokens for a Ramp
client: it fetches, caches, and transparently refreshes the access token
before it expires.
Because GenServer calls are processed one at a time, concurrent callers
automatically get "single-flight" behavior: only one token fetch is ever
in flight at a time, and every waiting caller receives the same fresh
token once it lands.
You normally don't start this directly -- Ramp.Client.new/1 starts
one for you (unsupervised, suitable for scripts and iex). For a
supervised, production deployment, start it explicitly in your
application's supervision tree and pass token_manager: pid (or a
registered name) to Ramp.Client.new/1:
children = [
{Ramp.TokenManager,
name: MyApp.RampTokenManager,
client_id: System.fetch_env!("RAMP_CLIENT_ID"),
client_secret: System.fetch_env!("RAMP_CLIENT_SECRET"),
scopes: ~w(transactions:read cards:read users:read)}
]
Supervisor.start_link(children, strategy: :one_for_one)
client = Ramp.Client.new(token_manager: MyApp.RampTokenManager)
Summary
Functions
Returns a specification to start this module under a supervisor.
Exchanges an OAuth2 authorization_code for an access token -- for the
partner / multi-tenant authorization_code flow, as opposed to the
default client_credentials flow.
Forces an immediate token refresh, discarding any cached token.
Manually seeds a pre-obtained access token (e.g. from external storage).
Starts a TokenManager.
Returns a currently-valid access token, fetching/refreshing one if needed.
Types
@type start_opt() :: {:client_id, String.t()} | {:client_secret, String.t()} | {:scopes, [String.t()]} | {:base_url, String.t()} | {:http_timeout_ms, pos_integer()} | {:name, GenServer.name()} | {:access_token, String.t()} | {:expires_in, pos_integer()}
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec exchange_auth_code(GenServer.server(), String.t(), String.t(), timeout()) :: {:ok, String.t()} | {:error, Ramp.Error.t()}
Exchanges an OAuth2 authorization_code for an access token -- for the
partner / multi-tenant authorization_code flow, as opposed to the
default client_credentials flow.
@spec refresh(GenServer.server(), timeout()) :: {:ok, String.t()} | {:error, Ramp.Error.t()}
Forces an immediate token refresh, discarding any cached token.
@spec set_token(GenServer.server(), String.t(), pos_integer()) :: :ok
Manually seeds a pre-obtained access token (e.g. from external storage).
@spec start_link([start_opt()]) :: GenServer.on_start()
Starts a TokenManager.
Options
:client_id(required unless:access_tokengiven):client_secret(required unless:access_tokengiven):scopes- list of OAuth2 scope strings, default[]:base_url- defaults to"https://api.ramp.com":http_timeout_ms- default30_000:name- an optionalGenServername for supervision:access_token/:expires_in- seed a pre-obtained token instead of performing the client-credentials exchange on first use
@spec token(GenServer.server(), timeout()) :: {:ok, String.t()} | {:error, Ramp.Error.t()}
Returns a currently-valid access token, fetching/refreshing one if needed.