Latch.Flow (latch v0.4.0)

Copy Markdown

Drives the atproto OAuth flow against an authorization server: pushed authorization requests, the authorization redirect, token exchange, and refresh.

Requests to the authorization server are DPoP-bound. The server requires a fresh DPoP nonce, so each request is attempted once without a nonce and retried once with the none the server returns. The client assertion and DPoP proof are regenreated on the retry, so neither jti is reused.

Summary

Functions

Builds the authorization redirect URL from a PAR request_uri.

Exchanges an authorization code for a session.

Performs a pushed authorization request, returning the request_uri.

Refreshes a session, returning a new session with rotated tokens.

Functions

authorization_url(server, client_id, request_uri)

@spec authorization_url(Latch.ServerMetadata.t(), String.t(), String.t()) ::
  String.t()

Builds the authorization redirect URL from a PAR request_uri.

The browser is sent here, per atproto only client_id and request_uri travel in the URL, since the real parameters were pushed durig PAR.

exchange_code(config, opts)

Exchanges an authorization code for a session.

Verifies the token response sub matches expected_did (the DID resolved before login) before building the session. The callback's state and iss are validated upstream, before this is called.

Required options

  • :client_id, :client_jwk - the confidential client's id and signing key
  • :redirect_uri - must match the value sent during PAR
  • :code, :core_verifier - the authorization code and PKCE verifier
  • :dpop_key - the per-session DPoP key
  • :expected_did - the DID the sub must match
  • :pds_endpoint - the resource server, stored on the session

Optional

  • :now - base time for expires_at (defaults to the current time)

par(config, server, opts)

Performs a pushed authorization request, returning the request_uri.

Required options

  • :client_id, the client's id
  • :redirect_uri, :scope, :state, :code_challenge - auth params
  • :dpop_key - the per-session DPoP key

Optional

  • :login_hint - the user's handle or DID

refresh(config, server, session, opts)

Refreshes a session, returning a new session with rotated tokens.

The refresh is DPoP-bound to the session's existing key (the tokens are bound to it), and the new sub must still match the session's DID. Refresh tokens are single-use, so the returned session carries the rotated tokens and must replace the old one.

Required options

  • :client_id, :client_jwk - the confidential client's id and signing key

Optional

  • :now - base time for expires_at (defaults to the current time)