You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
An authorization_code request mints two tokens but forms only one gate tuple #670
An authorization_code request can return both an access token and a refresh token. Those are two separate privileges, so they should form two gate tuples: issue:access_token:authorization_code and issue:refresh_token:authorization_code.
The text is ambiguous about this. §5.3.1 says the token types are "separately gateable", but §5.5.1 says this document produces one gate tuple per target, and the worked example in §9.2 shows a single gate naming only the access token. Read that way, the refresh token, which is the longest lived credential in the response, is issued with no decision.
Two changes:
Extend the §9.2 example to carry both gate tuples, so the multi token case is shown rather than implied.
Scope the aggregation rules in §6.6 to a token type. They currently aggregate across the whole batch, on the premise that shaping is a property of "the token being minted", singular. Shaping returned on a gate tuple should apply to the token that gate names, and scope tuple shaping should aggregate with the access token's gate, since scopes are about the access token. Aggregation then runs within a token type: a token_lifetime minimum is per token, and a claims conflict is only a conflict within one token.
Without this, a PDP cannot give a refresh token a different lifetime than the access token. It returns both values, the minimum rule takes the lower, and the refresh token is silently clamped to the access token's ceiling.
One thing to settle: a denied refresh token gate should presumably omit the refresh token and issue the access token, the narrowing behavior of §5.5.4, rather than fail the request. A denied access token gate stays fatal.
I went through the OAuth-AS profile and I’d be interested in taking a focused pass at this.
The cleanest split to me is to handle the two parts that don’t require settling the denial behavior first:
extend the authorization_code example so access-token and refresh-token issuance form separate gate tuples; and
make the shaping/aggregation rules token-type-local, so (for example) the refresh-token lifetime is not accidentally aggregated with the access-token lifetime.
I’d leave the “refresh gate denied / access gate permitted” response semantics explicitly unresolved in that change unless the WG wants to settle it at the same time.
That would keep the contribution narrowly about the invariant that each credential being minted has its own authorization gate and shaping context.
If that split sounds useful, I’m happy to prepare the spec diff and worked example.
Activity
arjun2075 commentedon Sep 25, 2026
I went through the OAuth-AS profile and I’d be interested in taking a focused pass at this.
The cleanest split to me is to handle the two parts that don’t require settling the denial behavior first:
authorization_codeexample so access-token and refresh-token issuance form separate gate tuples; andI’d leave the “refresh gate denied / access gate permitted” response semantics explicitly unresolved in that change unless the WG wants to settle it at the same time.
That would keep the contribution narrowly about the invariant that each credential being minted has its own authorization gate and shaping context.
If that split sounds useful, I’m happy to prepare the spec diff and worked example.
Merge pull request #671 from openid/oauth-issuance-670-multi-token-gates
Form one gate tuple per token type, aggregate shaping per token type