skip to content

What would make you move an estate's delegated rights from scope strings onto RFC 9396 authorization_details?

level: principalimportance: should knowfreq 28%

answer

  1. watch for structure inside the strings
  2. grammar for a language already invented
  3. consent rendering is the hidden cost
  4. two readings must match, issuer and enforcer
  5. additive, so migrate one type at a time

basics

~20 s

Move when the rights you delegate carry parameters — a specific resource, a limit, a date range — and teams are encoding those parameters inside scope strings by private convention. That convention is an unwritten contract with no protocol support and no error when parties disagree.

solid answer

~50 s

The trigger is not the number of scopes; it is what teams are doing inside them. When a scope value has started carrying structure — an identifier, an amount, a period packed into the string — the estate has already built a rights language without a grammar, and RFC 9396 is the grammar. Weigh that against a real cost: every `type` must be rendered as consent a person can agree to, and understood identically by the authorization server that issues and the resource server that enforces. Someone has to own the type definitions as a versioned contract. Adopt where the limit is safety- or money-bearing and the parameters are what a resource owner is actually agreeing to; leave categorical permissions as scopes. Because `scope` and `authorization_details` may travel together and `authorization_details_types_supported` advertises what is understood, the move can be made one type at a time rather than as a cutover.

go deeper

for a junior

Recall the distinction behind the decision: a permission label says what kind of access is wanted, while a structured right can also say which resource, which operation and within which limits.

for a middle

Be able to state the trigger and the mechanics: parameters being smuggled into permission strings, and a JSON array of typed entries that the token response echoes as what was actually granted.

for a senior

Show the sequencing — enforcement before promise, one type at a time, both mechanisms coexisting — and name the failure of a precise right that no resource server upholds.

for a principal

Own the trade in full: governance of the type vocabulary, matched interpretation across issuers and enforcers, consent rendering in every locale, and the honest case for leaving categorical permissions exactly as they are.

## The signal that the string has run out The decision is rarely about volume. A large flat permission vocabulary is unwieldy but honest. The signal to watch for is **structure appearing inside the values**: identifiers, amounts, periods or resource names packed into a permission string and parsed by convention at the other end. At that point the estate has invented a rights language with no grammar, no validation and no error path — two teams can read the same string differently and nothing in the protocol notices. A second signal is a consent screen nobody can write honestly, because the label shown to the resource owner does not name the limit the request actually carries. ## What RFC 9396 moves into the protocol `authorization_details` gives the request an array of typed objects. `type` is required and fixes how the rest of the entry is read; common members — `locations`, `actions`, `datatypes`, `identifier`, `privileges` — give types a shared vocabulary instead of a private one. The granted array returns in the token response, so what the resource server enforces is the structure the authorization server actually approved, not a string both sides hope they agree about. An unknown type is rejected with `invalid_authorization_details` rather than dropped, which turns a silent divergence into a visible failure at the earliest moment. ## What it costs | Cost | Who pays it | Why it is unavoidable | |---|---|---| | Rendering consent per type | The authorization server team | A structured object has to become a sentence a person can agree to, in every language served | | Matched interpretation | Authorization server and resource server | Both must read a type identically, or a right is granted in one sense and enforced in another | | Type governance | Whoever owns the estate's rights model | Types are a contract that needs definition, versioning and deprecation like any API | | Token and request size | Everyone | A structured right is larger than a word, in the request and in whatever the token carries | | Client complexity | Every integrator | Composing an array and reading the granted one is more work than adding a string | ## How to decide 1. **Is the limit the point?** If what the resource owner is agreeing to is *bounded* — this supply point, this period, up to this amount — the bound belongs in the protocol. If the agreement is categorical, a label is the honest representation and structure adds nothing. 2. **Is the resource server able to enforce structure?** A right expressed precisely and enforced approximately is worse than a coarse right enforced exactly, because the consent screen now promises something no component upholds. 3. **Is there an owner for the types?** Without one, a type vocabulary sprawls faster than a scope vocabulary did, and with harder failures. 4. **Does the consent surface have room?** Structured rights need a place to be shown. If the screen cannot express them, the precision never reaches the person granting it. 5. **What is the blast radius of getting it wrong?** Money-bearing and safety-bearing rights repay the work; a read-only convenience feature does not. ## Sequencing the move The mechanism is additive, which is the whole reason a migration is possible. - Start with the **one right that most needs a parameter**, not with a translation of the existing vocabulary. Define its type, its members and its consent rendering as a single deliverable. - Keep `scope` in the same requests for everything else. The two coexist, so no client has to change on a schedule set by someone else. - Advertise `authorization_details_types_supported` and let clients discover what they can ask for, instead of documenting it in a wiki page that drifts. - Make the resource server read the **granted** array from the token response before any client depends on it, so enforcement exists before precision is promised. - Retire a scope value only when nothing requests it, and accept that some categorical permissions never leave. ## When not to move If the rights are genuinely categorical, if the same team owns every party and can change both ends at will, or if the resource servers cannot enforce structure yet, the move buys precision nobody consumes and adds a governance obligation nobody asked for. A structured rights model that outruns its enforcement is a more expensive version of the problem it replaced.

  • Why is a large flat permission vocabulary not, on its own, a reason to move?
    Because size is a naming problem, not a structural one. A hundred categorical permissions are tedious but honest, and RFC 9396 does not make them fewer. The move pays when the values have started carrying parameters that no party can validate — that is a different defect from simply having many of them.
  • What is the first thing to build, the request side or the enforcement side?
    Enforcement. A resource server that reads the granted `authorization_details` must exist before a consent screen promises a bounded right, or the estate has published a precision it does not uphold — which is worse than the coarse permission it replaced, because now the resource owner believes the limit.
  • How do you stop a type vocabulary sprawling the way the scope vocabulary did?
    By treating types as a versioned contract with a named owner and a review, and by reusing the common members rather than inventing per-type synonyms for the same idea. The failure mode is worse than scope sprawl, because an unrecognised type is a hard rejection rather than a missing label.
  • What does keeping both mechanisms in one request cost?
    Ambiguity, if nobody decides which one governs a given right. The rule has to be written down: a right is expressed in exactly one place, and no resource server consults both for the same decision. Without that, an audit cannot answer what a token actually permitted.

saying these in an interview costs you the question

  • Says a long scope list is itself the reason to migrate
  • Promises bounded rights before any resource server enforces structure
  • Treats the move as a cutover rather than type by type
  • Ignores who owns and versions the type definitions
  • Assumes the consent screen renders a structured right for free
  • Expresses one right in both scope and authorization_details at once