Ramp.TokenManager (ramp v1.0.0)

Copy Markdown View Source

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

start_opt()

@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

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

exchange_auth_code(server, code, redirect_uri, timeout \\ 30000)

@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.

refresh(server, timeout \\ 30000)

@spec refresh(GenServer.server(), timeout()) ::
  {:ok, String.t()} | {:error, Ramp.Error.t()}

Forces an immediate token refresh, discarding any cached token.

set_token(server, token, expires_in_seconds)

@spec set_token(GenServer.server(), String.t(), pos_integer()) :: :ok

Manually seeds a pre-obtained access token (e.g. from external storage).

start_link(opts)

@spec start_link([start_opt()]) :: GenServer.on_start()

Starts a TokenManager.

Options

  • :client_id (required unless :access_token given)
  • :client_secret (required unless :access_token given)
  • :scopes - list of OAuth2 scope strings, default []
  • :base_url - defaults to "https://api.ramp.com"
  • :http_timeout_ms - default 30_000
  • :name - an optional GenServer name for supervision
  • :access_token / :expires_in - seed a pre-obtained token instead of performing the client-credentials exchange on first use

token(server, timeout \\ 30000)

@spec token(GenServer.server(), timeout()) ::
  {:ok, String.t()} | {:error, Ramp.Error.t()}

Returns a currently-valid access token, fetching/refreshing one if needed.