Skip to main content

Module native

Module native 

Source
Expand description

Native-app OAuth composition root — the non-OIDC sibling of RelyingParty.

NativeAuthFlow<S> runs the authorization-code + PKCE flow for a native client (RFC 8252): a desktop or CLI program that opens the system browser and receives the redirect on a loopback socket it owns. It requests resource scopeschat.read, contact.read, … — and no openid, so the authorization server mints no id_token.

§Why RelyingParty cannot serve this

The OIDC RP is welded to OIDC in three independent places, and a native resource client breaks all three:

RelyingParty requiresA native client
S: RequestedScope, whose every impl is an openid … markerrequests resource atoms, never openid
a nonce on every authorize requesthas no id_token for a nonce to bind
a verified id_token in the token responsereceives none — PAS mints one only for openid

Loosening any of them would weaken the contract CWC / RCW / CTW depend on. So this is a sibling composition root, not a relaxation — and the two share their machinery (PKCE, discovery, the OAuth client) rather than their contract.

§Shape

Three calls, and the SDK holds every invariant that is easy to get wrong:

let flow = NativeAuthFlow::<S>::new(
    NativeConfig::new("https://accounts.ppoppo.com".parse()?, "my_app_id")
        .with_resource("https://api.ppoppo.com/grpc"),
)
.await?;

// 1. Bind your loopback listener, then hand its address to `start`.
let url = flow.start("http://127.0.0.1:54321/callback");
//    …open `url` in the browser, wait for the redirect…

// 2. Hand back the raw query string. State verification, the code
//    exchange, and the grant check all happen inside.
let source = flow.complete(raw_query, MemoryTokenStore::new()).await?;

source is a ScopedTokenSource<S> — feed it straight to a resource client built at the same S, and the credential’s tier and the client’s tier cannot disagree.

On a later run there is no code to exchange: the refresh token is already in the keystore. token_source is that path, and complete is defined in terms of it.

§What the consumer still owns

The loopback listener — a socket in the consumer’s process, which no library can hold for it. Everything else (state generation, single-use state verification, PKCE, callback parsing, the grant check) is here, on purpose: each is a security invariant that would otherwise be re-implemented, slightly differently, by every native consumer.

Structs§

NativeAuthFlow
Native-app OAuth composition root. See the module docs.
NativeConfig
Boot configuration for a NativeAuthFlow.

Enums§

CallbackError
NativeAuthFlow::complete failure surface.
NativeAuthInitError
NativeAuthFlow::new failure surface.