atproto_core/oauth/flow
The authorization flow as Effects, from identifier to verified session.
start resolves the account to a DID, resolves that DID natively to its
PDS (the resolver’s answer is only a hint), discovers and verifies the
PDS’s authorization server, and pushes the request (PAR) with PKCE and
DPoP. It yields the authorization URL and a Pending flow that carries
the DID, the verified authorization server, state, and the PKCE
verifier.
callback is the only way to exchange a code: it takes the pending flow
and the full callback query, requires state to match and iss to be
the verified issuer (RFC 9207), surfaces error responses, exchanges the
code, and returns a VerifiedSession only when the token sub is the
flow’s DID and that DID resolves back to the same issuer.
To survive a redirect (a browser app navigating away), to_json stores
the pending flow’s plain parts and resume rebuilds it, re-fetching and
re-verifying the authorization server metadata rather than trusting
stored endpoints. The DPoP key is not part of it; keep that separately.
A Pending must be used at most once. The kernel cannot enforce that for
a value the caller stores, so the caller’s store must remove the flow when
it looks it up by state (a take, not a read).
Types
pub type CallbackError {
MissingParameter(name: String)
DuplicateParameter(name: String)
StateMismatch
IssuerMismatch(expected: String, actual: String)
AuthorizationFailed(
error: String,
description: option.Option(String),
)
ExchangeFailed(error: session.TokenError)
}
Constructors
-
MissingParameter(name: String) -
DuplicateParameter(name: String) -
StateMismatch -
IssuerMismatch(expected: String, actual: String) -
AuthorizationFailed( error: String, description: option.Option(String), )The authorization server reported an error (e.g.
access_denied). -
ExchangeFailed(error: session.TokenError)
Pending
opaqueAn authorization request waiting for its callback.
pub opaque type Pending
pub type ResumeError {
StoredFlowInvalid(reason: String)
ResumeDiscoveryFailed(error: metadata.MetadataError)
}
Constructors
-
StoredFlowInvalid(reason: String) -
ResumeDiscoveryFailed(error: metadata.MetadataError)
pub type StartError {
IdentifierResolveFailed(
identifier: String,
error: xrpc.XrpcError,
)
InvalidIdentity(error: did.DidError)
HandleNotClaimed(handle: String, did: String)
DiscoverFailed(error: metadata.MetadataError)
ParFailed(error: transport.PostError)
ParRejected(status: Int, error: option.Option(String))
ParResponseInvalid(reason: String)
}
Constructors
-
IdentifierResolveFailed( identifier: String, error: xrpc.XrpcError, )The resolver could not map a handle to a DID.
-
InvalidIdentity(error: did.DidError) -
HandleNotClaimed(handle: String, did: String)The handle’s DID document does not list the handle in
alsoKnownAs. -
DiscoverFailed(error: metadata.MetadataError) -
ParFailed(error: transport.PostError) -
ParRejected(status: Int, error: option.Option(String)) -
ParResponseInvalid(reason: String)
Values
pub fn callback(
pending: Pending,
query: List(#(String, String)),
client_auth: transport.ClientAuth,
) -> effect.Effect(Result(session.VerifiedSession, CallbackError))
Complete a flow from the redirect’s query parameters (all of them, as
received). Consumes pending; see the module docs on single use.
pub fn callback_error_to_string(error: CallbackError) -> String
pub fn issuer(pending: Pending) -> remote.Origin
pub fn pds(pending: Pending) -> remote.Origin
pub fn resume(
stored: String,
) -> effect.Effect(Result(Pending, ResumeError))
Rebuild a pending flow from to_json output, re-verifying the issuer’s
metadata.
pub fn resume_error_to_string(error: ResumeError) -> String
pub fn start(
resolver resolver: String,
identifier identifier: String,
client_id client_id: String,
redirect_uri redirect_uri: String,
scope scope: String,
pkce_verifier pkce_verifier: String,
pkce_challenge pkce_challenge: String,
state state: String,
client_auth client_auth: transport.ClientAuth,
) -> effect.Effect(Result(#(String, Pending), StartError))
Start a flow for identifier (a handle or a DID). resolver is the
Slingshot-compatible service used to map a handle to a DID; it is not
consulted for a DID, and its PDS answer is never used. Returns the URL to
send the user to and the pending flow to keep until the callback.
pub fn start_error_to_string(error: StartError) -> String