atproto_core/oauth/transport

The shared OAuth transport as an Effect: a form-encoded POST carrying a DPoP proof and, for confidential clients, a fresh client assertion, with the mandatory nonce retry (first attempt no nonce, retry with the server’s DPoP-Nonce on use_dpop_nonce). dpop_nonce_challenge is the single, target-agnostic copy of the nonce-detection logic.

Types

How the client authenticates at the PAR, token, and revocation endpoints.

pub type ClientAuth {
  PublicClient
  PrivateKeyJwt(
    sign: fn(remote.Origin) -> Result(String, String),
  )
}

Constructors

  • PublicClient

    A public client (browser app, native app, loopback dev client).

  • PrivateKeyJwt(sign: fn(remote.Origin) -> Result(String, String))

    A confidential client using private_key_jwt. sign is called once per HTTP attempt, nonce retry included, with the verified issuer to use as the assertion aud; it must return a freshly signed JWT (new jti, current iat) every time.

pub type PostError {
  ProofFailed(reason: String)
  AssertionFailed(reason: String)
  PostFailed(url: String, error: xrpc.TransportError)
}

Constructors

  • ProofFailed(reason: String)
  • AssertionFailed(reason: String)
  • PostFailed(url: String, error: xrpc.TransportError)

Values

pub const client_assertion_type: String
pub fn dpop_nonce_challenge(
  resp: response.Response(String),
) -> option.Option(String)

The DPoP nonce a server is asking us to use, if it rejected the request with use_dpop_nonce. The authorization server (PAR/token) signals this in the JSON body; the PDS resource server signals it in the WWW-Authenticate header. Either way the nonce itself comes in the DPoP-Nonce header.

pub fn post_error_to_string(error: PostError) -> String
pub fn post_form(
  url: remote.Url,
  form: List(#(String, String)),
  client_auth: ClientAuth,
  issuer: remote.Origin,
) -> effect.Effect(Result(response.Response(String), PostError))

POST form to url on the authorization server issuer, retrying once with the server nonce if it asks for one. The response is returned as-is; status handling belongs to the caller.

✨ Search Document