Zepto.TokenCallback behaviour (Zepto v0.3.0)

View Source

Behaviour for persisting OAuth tokens across application restarts.

Implement this behaviour in your application to persist tokens to a database, file, or other storage. This allows the TokenManager to restore tokens on startup, avoiding the need for users to re-authorize after every restart.

Example Implementation

defmodule MyApp.ZeptoTokenStore do
  @behaviour Zepto.TokenCallback

  alias MyApp.Repo
  alias MyApp.ZeptoToken

  @impl true
  def save_tokens(environment, tokens) do
    attrs = %{
      environment: to_string(environment),
      refresh_token: tokens.refresh_token,
      access_token: tokens[:access_token],
      expires_at: tokens[:expires_at]
    }

    %ZeptoToken{}
    |> ZeptoToken.changeset(attrs)
    |> Repo.insert(on_conflict: :replace_all, conflict_target: :environment)
    |> case do
      {:ok, _} -> :ok
      {:error, changeset} -> {:error, changeset}
    end
  end

  @impl true
  def load_tokens(environment) do
    case Repo.get_by(ZeptoToken, environment: to_string(environment)) do
      nil ->
        {:ok, nil}

      token ->
        {:ok, %{
          refresh_token: token.refresh_token,
          access_token: token.access_token,
          expires_at: token.expires_at
        }}
    end
  end
end

Configuration

config :zepto,
  environments: [
    sandbox: [
      # ... other config ...
      token_callback: MyApp.ZeptoTokenStore
    ]
  ]

Summary

Callbacks

Loads tokens from persistent storage.

Saves tokens to persistent storage.

Types

tokens()

@type tokens() :: %{
  refresh_token: String.t(),
  access_token: String.t() | nil,
  expires_at: DateTime.t() | nil
}

Callbacks

load_tokens(environment)

@callback load_tokens(environment :: atom()) :: {:ok, tokens() | nil} | {:error, term()}

Loads tokens from persistent storage.

Called lazily on the first API call (not on startup). This avoids startup ordering issues with database connections. If tokens are found, they are used to populate the TokenManager state, allowing API calls to proceed without requiring re-authorization.

Should return:

  • {:ok, tokens} - Map with :refresh_token, :access_token, :expires_at
  • {:ok, nil} - No tokens found (user needs to authorize)
  • {:error, reason} - Failed to load (logged, treated as no tokens)

save_tokens(environment, tokens)

@callback save_tokens(environment :: atom(), tokens()) :: :ok | {:error, term()}

Saves tokens to persistent storage.

Called after:

  • A successful token refresh (with new access_token and refresh_token)
  • TokenManager.set_refresh_token/2 is called (e.g., after OAuth callback)

The tokens map contains:

  • :refresh_token - The current refresh token (always present)
  • :access_token - The current access token (may be nil)
  • :expires_at - DateTime when the access token expires (may be nil)

Should return :ok on success or {:error, reason} on failure. Failures are logged but do not interrupt token management.