Behaviour for persisting the OAuth2 token pair.
Because Exact Online rotates the refresh token on every refresh, the token
has to be stored somewhere that outlives the request. Exact.TokenStore.ETS
is the built-in in-memory implementation; implement this behaviour to keep
tokens in a database or a secrets manager instead.
lock/2 exists so that concurrent requests cannot refresh the same grant
twice. Exact Online rejects a refresh that uses an already rotated refresh
token, so a second concurrent refresh would break the grant. Implementations
must run fun with the lock for key held, and may serialize more coarsely
than per key. It is optional and defaults to running fun unsynchronized.
defmodule MyApp.ExactTokens do
@behaviour Exact.TokenStore
@impl true
def fetch(user_id) do
case MyApp.Repo.get(MyApp.ExactToken, user_id) do
nil -> :error
record -> {:ok, MyApp.ExactToken.to_token(record)}
end
end
@impl true
def put(user_id, token) do
MyApp.ExactToken.upsert!(user_id, token)
:ok
end
end
Summary
Callbacks
Returns the stored token for key, or :error when there is none.
Runs fun while holding a lock for key.
Persists token under key.
Types
@type key() :: term()
Callbacks
@callback fetch(key()) :: {:ok, Exact.Token.t()} | :error
Returns the stored token for key, or :error when there is none.
Runs fun while holding a lock for key.
@callback put(key(), Exact.Token.t()) :: :ok | {:error, term()}
Persists token under key.