atproto/oauth/flow

The authorization flow for a sync Client: start resolves the account natively, discovers and verifies its authorization server, and pushes the request (PAR) with PKCE and DPoP; callback checks the redirect (state, iss, error), exchanges the code, and yields a session whose sub was verified against the issuer.

A thin sync wrapper over atproto_core/oauth/flow: this module generates the platform one-shots (PKCE, DPoP key, state) and pairs the kernel’s pending flow with the DPoP key the kernel never sees.

Keep the Flow server-side (or in-process for a CLI), keyed by state(flow), and remove it from the store when the callback arrives: a flow is single-use, and only the store can make a lookup a take. To keep a flow outside the process, store to_json(flow) and the DPoP key (dpop_key(flow), e.g. as a private JWK) and rebuild with resume.

Types

A completed login: the verified session and the DPoP key its tokens are bound to. Persist both; every later call needs the same key.

pub type Authenticated {
  Authenticated(
    session: session.VerifiedSession,
    dpop_key: gose.Key(String),
  )
}

Constructors

pub type CallbackError =
  flow.CallbackError
pub type ClientAuth =
  transport.ClientAuth

Flow

opaque
pub opaque type Flow
pub type FlowError =
  flow.StartError
pub type ResumeError =
  flow.ResumeError

Values

pub fn callback(
  client: xrpc.Client,
  flow flow: Flow,
  query query: List(#(String, String)),
  client_auth client_auth: transport.ClientAuth,
) -> Result(Authenticated, flow.CallbackError)

Complete the flow from the redirect’s query parameters, all of them as received (e.g. uri.parse_query of the callback URL’s query).

pub fn callback_error_to_string(
  error: flow.CallbackError,
) -> String
pub fn did(flow: Flow) -> did.Did

The account the flow was started for.

pub fn dpop_key(flow: Flow) -> gose.Key(String)

The DPoP key the flow’s tokens will be bound to.

pub fn flow_error_to_string(error: flow.StartError) -> String
pub fn issuer(flow: Flow) -> remote.Origin
pub fn pds(flow: Flow) -> remote.Origin
pub fn resume(
  client: xrpc.Client,
  stored stored: String,
  dpop_key dpop_key: gose.Key(String),
) -> Result(Flow, flow.ResumeError)

Rebuild a flow from to_json output and its DPoP key, re-verifying the issuer’s metadata.

pub fn resume_error_to_string(error: flow.ResumeError) -> String
pub fn start(
  client: xrpc.Client,
  resolver resolver: String,
  identifier identifier: String,
  client_id client_id: String,
  redirect_uri redirect_uri: String,
  scope scope: String,
  client_auth client_auth: transport.ClientAuth,
) -> Result(#(String, Flow), flow.StartError)

Returns the authorization-server URL to send the user to, and the pending flow to keep until the callback.

pub fn state(flow: Flow) -> String

The state this flow was started with: the key to store it under.

pub fn to_json(flow: Flow) -> String

The flow’s plain half as JSON. It holds the PKCE verifier; keep it no longer than the login takes.

✨ Search Document