Give an access token the resource it was asked for #56

Merged
PerishFire merged 1 commit from land/identity-face into main 2026-07-31 04:51:54 +00:00
Owner

oidc: give an access token the resource it was asked for

Every access token said aud = <this issuer>, which means a resource
server could only ever check that ensign signed it — not that it was meant
for them. Any token from any client opened every resource.

An App with mode = "resource" registers one. /authorize takes a
resource and mints the access token against it; without one the audience
stays the issuer, which is what /userinfo answers to. An unregistered
resource is refused rather than quietly falling back, because a fallback
would let anyone name their own audience and the separation would be
decoration. A client's slug will not do either: mixing the two kinds of
App would blur which of them is a resource.

Renew carries the audience now. A refresh that forgot it would hand back
a token for a different resource than the one the grant was made against.

Teams ride the access token, gated on the same profile scope that
already gates login and name. A resource that needs group membership for
its own authorisation no longer has to ask, and cannot learn it merely by
being registered — the person still grants it once.

Code and Ward now contain the four facts an issuance rests on rather
than each carrying their own copy. The copy came first and Ectropy named
it: two shapes drifting apart is the cost, and there was nothing to gain.

oidc: give an access token the resource it was asked for Every access token said `aud = <this issuer>`, which means a resource server could only ever check that ensign signed it — not that it was meant for them. Any token from any client opened every resource. An `App` with `mode = "resource"` registers one. `/authorize` takes a `resource` and mints the access token against it; without one the audience stays the issuer, which is what `/userinfo` answers to. An unregistered resource is refused rather than quietly falling back, because a fallback would let anyone name their own audience and the separation would be decoration. A client's slug will not do either: mixing the two kinds of App would blur which of them is a resource. `Renew` carries the audience now. A refresh that forgot it would hand back a token for a different resource than the one the grant was made against. Teams ride the access token, gated on the same `profile` scope that already gates login and name. A resource that needs group membership for its own authorisation no longer has to ask, and cannot learn it merely by being registered — the person still grants it once. `Code` and `Ward` now contain the four facts an issuance rests on rather than each carrying their own copy. The copy came first and Ectropy named it: two shapes drifting apart is the cost, and there was nothing to gain.
Give an access token the resource it was asked for
All checks were successful
guard / guard (pull_request) Successful in 3m43s
guard / guard (push) Successful in 3m25s
384aca31ed
oidc: give an access token the resource it was asked for

Every access token said `aud = <this issuer>`, which means a resource
server could only ever check that ensign signed it — not that it was meant
for them. Any token from any client opened every resource.

An `App` with `mode = "resource"` registers one. `/authorize` takes a
`resource` and mints the access token against it; without one the audience
stays the issuer, which is what `/userinfo` answers to. An unregistered
resource is refused rather than quietly falling back, because a fallback
would let anyone name their own audience and the separation would be
decoration. A client's slug will not do either: mixing the two kinds of
App would blur which of them is a resource.

`Renew` carries the audience now. A refresh that forgot it would hand back
a token for a different resource than the one the grant was made against.

Teams ride the access token, gated on the same `profile` scope that
already gates login and name. A resource that needs group membership for
its own authorisation no longer has to ask, and cannot learn it merely by
being registered — the person still grants it once.

`Code` and `Ward` now contain the four facts an issuance rests on rather
than each carrying their own copy. The copy came first and Ectropy named
it: two shapes drifting apart is the cost, and there was nothing to gain.

Land-Source: identity-face@a16439a1fa3ccf7802b7cf28ca13ac771774a330
PerishFire deleted branch land/identity-face 2026-07-31 04:51:54 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
PerishLab/ensign!56
No description provided.