Exosphere.ATProto.OAuth.Session (Exosphere v0.4.0)

Copy Markdown View Source

A DPoP-bound ATProto OAuth session: the tokens, the session DPoP key, and everything needed to refresh and to make authorized XRPC requests.

Produced by Flow.callback/3. The struct is plain data — refresh it with refresh/2, persist it with to_map/1, and hand it to Exosphere.OAuth.Session (the GenServer wrapper) or use it directly with Exosphere.ATProto.Repo (which accepts a session with access_token and dpop_private_key).

Refresh tokens are single-use (rotating): after every successful refresh, store the new session — the old refresh token is dead. A {:error, :invalid_grant} from refresh means the refresh token was reused or revoked and the session must be discarded.

Summary

Functions

Whether the access token has expired (with a small clock-skew allowance).

Rebuild a session serialized with to_map/1.

Build a session from a token response.

Like new/1, but raises on invalid input.

Refresh the session: exchange the (single-use) refresh token for a new token pair.

The session as a plain, Jason-encodable map for persistence.

Types

t()

@type t() :: %Exosphere.ATProto.OAuth.Session{
  access_token: String.t(),
  auth_server: Exosphere.ATProto.OAuth.ServerMetadata.t(),
  client: Exosphere.ATProto.OAuth.Client.t(),
  dpop_key: map(),
  expires_at: pos_integer() | nil,
  pds: String.t() | nil,
  refresh_token: String.t() | nil,
  scope: [String.t()],
  sub: String.t()
}

Functions

expired?(session, opts \\ [])

@spec expired?(
  t(),
  keyword()
) :: boolean()

Whether the access token has expired (with a small clock-skew allowance).

:now overrides the current time (tests).

from_map(map)

@spec from_map(map()) :: {:ok, t()} | {:error, :invalid_session}

Rebuild a session serialized with to_map/1.

new(opts)

@spec new(keyword() | map()) :: {:ok, t()} | {:error, term()}

Build a session from a token response.

Options

  • :sub, :access_token, :refresh_token, :scope (list or space-separated string), :expires_in (seconds) or :expires_at (unix seconds), :dpop_key, :client, :auth_server, :pds
  • :expected_did - when set, sub must match it
  • :http - HTTP module for the server-flow subject verification

new!(opts)

@spec new!(keyword()) :: t()

Like new/1, but raises on invalid input.

refresh(session, opts \\ [])

@spec refresh(
  t(),
  keyword()
) :: {:ok, t()} | {:error, term()}

Refresh the session: exchange the (single-use) refresh token for a new token pair.

On success returns the rotated session — replace your stored copy. On {:error, {:refresh_failed, 400, _}} (invalid/reused refresh token), the session is unrecoverable: discard it and re-authorize.

to_map(session)

@spec to_map(t()) :: map()

The session as a plain, Jason-encodable map for persistence.