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
-
PublicClientA public client (browser app, native app, loopback dev client).
-
PrivateKeyJwt(sign: fn(remote.Origin) -> Result(String, String))A confidential client using
private_key_jwt.signis called once per HTTP attempt, nonce retry included, with the verified issuer to use as the assertionaud; it must return a freshly signed JWT (newjti, currentiat) 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.