Repository navigation
v0.37.0 — delegation grants
A worker can mint delegation grants
vgi_rpc.Identity.v1 has always had two methods. Only one was reachable:
_build_identity passed resolve_token= and nothing else, and mint_grant
existed nowhere in this package, so offered_methods() could never include
issue_grant however a worker was written. The protocol was designed; the
wiring was missing.
Worker.mint_grant is the hook, detected by override exactly as resolve_token
is — identity comparison against the base, not a "supports grants" flag, because
the method must be absent unless a worker actually wrote the minting and a flag
can be set without one. A worker may now resolve credentials, mint grants, or
both, and the protocol it hosts describes what it does rather than what the
version supports.
class MyWorker(Worker):
@classmethod
def mint_grant(cls, principal, purpose, scopes, ttl_seconds) -> IssuedGrant:
...What a grant is for. OAuth cannot express durable delegation: it fuses the
grant, the credential and the session into one refresh token, so an IdP
shortening session lifetime shortens the grant. This mints the durable record —
created while the user is present, presented later by unattended automation as
an ordinary bearer.
Two guards, both load-bearing
-
No subject on the wire.
issue_granthas no subject field; the framework
passes the caller's own authenticated principal. Cross-subject minting is
closed by construction rather than by a check, which is why this needs no
allowlist whileintrospect_tokenhas one. The introspector allowlist is now
passed only when a resolver is supplied — requiring one from a worker that
mints but resolves nothing would be a startup error for a worker that is not
an oracle, the opposite of the guard's purpose. -
No
auth_time, no minting. A credential that cannot prove a recent human
login is refused. That single rule stops a grant minting another grant — a
grant is not IdP-issued, so it carries noauth_time— and makes a static
bearer token, which proves a machine holds a secret rather than that anyone
authenticated, fail closed.
On revocation
IssuedGrant.token is opaque to the framework: a sealed envelope, a database
row, or an IdP-brokered credential are equally valid and equally invisible. Be
clear-eyed about what a self-contained sealed token costs — with no server-side
record there is nothing to delete, so individual grants cannot be revoked and
rotating the sealing key invalidates all of them at once. A deployment that
needs per-grant revocation has to put something lookupable in the token.
Also
vgi.auth re-exports IssuedGrant and a GrantMinter alias, so a worker
author never names a private vgi_rpc module.
Rowfence forwards vgi_rpc.Identity.v1/issue_grant from this release onward
(its sibling introspect_token stays unforwarded — the proxy holds an
introspector credential, so relaying a client's call would make it an oracle).