v0.25.0¶
Release Date: 2026-10-27
Relying parties can call SystemAuth's APIs, such as the managed-principal
API, with their signed-in people's DPoP-bound session tokens. SystemAuth
accepts a bound token only with a proof by the key it is bound to, and until
now an application had no public way to add one, so mpclient and proxies
that sent the token as Bearer were refused. The new
relyingparty.Client.Transport adds the proofs. It adds no breaking changes
and no migrations.
Highlights¶
- Session tokens to SystemAuth's APIs.
relyingparty.Client.Transportis anhttp.RoundTripperfor requests that carry a token the relying party obtained. The caller sets it inAuthorization, asBearerorDPoP. The transport presents a token bound to the client's key with theDPoPscheme and a new proof for the request's method and URL, and an unbound token (from a client registered withallow_bearer_tokens) unchanged asBearer. mpclientworks with bound tokens. Give it anhttp.Clientwith the transport. Its calls are unchanged: managers create, list and sign in managed principals with their session token.- Server nonces. When SystemAuth asks for a nonce (
dpop.require_nonce), the transport retries once with it if the request body can be sent again, and otherwise keeps the nonce for the next request, as a reverse proxy's streamed body needs. - Another key's token stays unusable. A JWT bound to a key the relying party does not hold, such as a caller's own token, is refused with
ErrForeignDPoPTokenbefore anything is sent. An opaque token's binding cannot be read locally, so it is sent with the relying party's proof, and SystemAuth refuses it if it is bound to another key. - Proofs only for SystemAuth's tokens. The transport reads a JWT's binding only once its signature verifies against SystemAuth's keys, so it never makes a proof for a token someone made up; such a token is refused with
ErrInvalidToken. Its expiry is left to SystemAuth, which answers an expired token as before.
Added¶
relyingparty.Client.Transport(base http.RoundTripper) http.RoundTripper.
Changed¶
- The relying party's own calls to SystemAuth's userinfo, memberships and access-changes endpoints go through
Transport, so they share its nonce handling. A JWT access token is now sent only once its signature verifies against SystemAuth's keys, which the client already fetched to verify ID tokens; the client's own session tokens always do.
Documentation¶
- Calling APIs with DPoP: calling SystemAuth's other APIs with a session's token
- Managed Principals:
mpclientwith the relying party's transport, and proxies - Relying Party: the
mpclientexample uses the transport
Using it¶
-
Build the managed-principal client with the relying party's transport:
-
A reverse proxy that forwards a person's calls to SystemAuth's APIs sets
Authorization: Bearer <session token>as before and usesrp.Transport(base)as its transport. - Send these requests to the URL SystemAuth checks proofs against: its issuer origin, or
dpop.resource_base_urlwhen it sets one. A proof'shtuis the request's URL, so a request to another origin, such as an internal address, does not verify.
Nothing changes for existing deployments.
For release history, see the changelog.