WEB / WEB-15.01
OAuth actors, code flow and scopes
Mina lets Atlas Exporter read selected notes. Separate OAuth roles, code exchange and the API’s own decision through this one delegation.
1. Core · Mechanism
Read every scenario without motion
Read allowed
- After callback
The scene starts after an accepted callback; browser redirects and owner authentication are not drawn in this segment.
- Client
- Code alias held; callback bound
- Authorization server
- Code valid; no token
- Resource server
- No request yet
- Exchange ready
The client prepares the code, redirect and selected verifier context; preparation is a local operation.
- Client
- Token request ready; code not sent to API
- Authorization server
- Code valid; no token
- Resource server
- No request yet
- AS received request
The token request arrived at the AS; client, code, redirect and PKCE checks are not yet complete.
- Client
- Token request ready; code not sent to API
- Authorization server
- Token request received; gate pending
- Resource server
- No request yet
- AS gate passed
The selected code and binding gates passed; code-consumed and token-response-ready state are created locally at the AS.
- Client
- Token request ready; code not sent to API
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- No request yet
- Token response arrived
The client received access and optional refresh aliases; this receipt is not yet Notes API permission.
- Client
- AT alias held; no API gate yet
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- No request yet
- Action selected
The client prepares a read request to notes-api using access-A. The token audience remains notes-api and its granted scope remains notes:read; the recipient makes its own acceptance decision.
- Client
- notes-api read request ready
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- No request yet
- API received request
The request arrived at notes-api. The recipient now holds the access-A context, but audience, time, scope and object conditions have not yet been evaluated.
- Client
- notes-api read request ready
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- notes-api received request; policy pending
- API decision
The audience matches notes-api and now=1050 is before expiresAt=2000. The notes:read scope and selected tenant/owner relationship allow the read. This is an allow decision; the scene neither reads note bytes nor sends a body to the client.
- Client
- notes-api read request ready
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- Read policy allow; bytes not read
Scope too narrow
- After callback
The scene starts after an accepted callback; browser redirects and owner authentication are not drawn in this segment.
- Client
- Code alias held; callback bound
- Authorization server
- Code valid; no token
- Resource server
- No request yet
- Exchange ready
The client prepares the code, redirect and selected verifier context; preparation is a local operation.
- Client
- Token request ready; code not sent to API
- Authorization server
- Code valid; no token
- Resource server
- No request yet
- AS received request
The token request arrived at the AS; client, code, redirect and PKCE checks are not yet complete.
- Client
- Token request ready; code not sent to API
- Authorization server
- Token request received; gate pending
- Resource server
- No request yet
- AS gate passed
The selected code and binding gates passed; code-consumed and token-response-ready state are created locally at the AS.
- Client
- Token request ready; code not sent to API
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- No request yet
- Token response arrived
The client received access and optional refresh aliases; this receipt is not yet Notes API permission.
- Client
- AT alias held; no API gate yet
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- No request yet
- Action selected
The client prepares a write request to notes-api using access-A. The token audience remains notes-api and its granted scope remains notes:read; the recipient makes its own acceptance decision.
- Client
- notes-api write request ready
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- No request yet
- API received request
The request arrived at notes-api. The recipient now holds the access-A context, but audience, time, scope and object conditions have not yet been evaluated.
- Client
- notes-api write request ready
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- notes-api received request; policy pending
- API decision
Audience and time are valid for notes-api, but the write request requires notes:write while the grant contains only notes:read. The result is scope-denied. No write occurs and no resource body is sent to the client in this branch.
- Client
- notes-api write request ready
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- Write policy deny; read scope only
Wrong API
- After callback
The scene starts after an accepted callback; browser redirects and owner authentication are not drawn in this segment.
- Client
- Code alias held; callback bound
- Authorization server
- Code valid; no token
- Resource server
- No request yet
- Exchange ready
The client prepares the code, redirect and selected verifier context; preparation is a local operation.
- Client
- Token request ready; code not sent to API
- Authorization server
- Code valid; no token
- Resource server
- No request yet
- AS received request
The token request arrived at the AS; client, code, redirect and PKCE checks are not yet complete.
- Client
- Token request ready; code not sent to API
- Authorization server
- Token request received; gate pending
- Resource server
- No request yet
- AS gate passed
The selected code and binding gates passed; code-consumed and token-response-ready state are created locally at the AS.
- Client
- Token request ready; code not sent to API
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- No request yet
- Token response arrived
The client received access and optional refresh aliases; this receipt is not yet Notes API permission.
- Client
- AT alias held; no API gate yet
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- No request yet
- Action selected
The client prepares a read request to archive-api using access-A. The token audience remains notes-api and its granted scope remains notes:read; the recipient makes its own acceptance decision.
- Client
- archive-api read request ready
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- No request yet
- API received request
The request arrived at archive-api. The recipient now holds the access-A context, but audience, time, scope and object conditions have not yet been evaluated.
- Client
- archive-api read request ready
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- archive-api received request; policy pending
- API decision
The request recipient is archive-api while the access-A audience is notes-api. The recipient rejects this mismatch as audience-denied; positive scope or tenant/owner facts do not grant a different recipient permission. No body is produced and the client has not yet received this decision.
- Client
- archive-api read request ready
- Authorization server
- Code consumed; AT+optional RT ready
- Resource server
- archive-api: audience-denied; no body
Code expired
- Time boundary
The accepted callback context holds the code; the selected clock has reached its exact expiration instant.
- Client
- Code alias held; now=1100
- Authorization server
- Code expiresAt=1100; unused
- Resource server
- No request
- Exchange ready
The client prepares the same normal token request; code validity still belongs to the AS local gate.
- Client
- Normal token request ready
- Authorization server
- Code expiresAt=1100; unused
- Resource server
- No request
- AS receipt
The token request arrived at the AS; receipt completes neither the expiry check nor token issuance.
- Client
- Normal token request ready
- Authorization server
- Request received; expiry pending
- Resource server
- No request
- Expiry denial
The zero-leeway fixture rejects the code because now equals expiresAt; no access or refresh token is created.
- Client
- Normal token request ready
- Authorization server
- Code expired; error ready; no tokens
- Resource server
- No request
- Error receipt
The client received the selected exchange error outcome; it does not continue to Notes API with a new credential.
- Client
- Exchange failed; no AT; no API call
- Authorization server
- Code expired; error ready; no tokens
- Resource server
- No request
ACTORS · STATE · DATA FLOW
Limited authority without sharing a password
Mina’s notes live at Notes API; Atlas Exporter is a separate application that wants to export them. Giving it Mina’s password would create authority and credential storage duties beyond that job. Delegated authorization organizes the transfer of selected access to a client. OAuth addresses API access; by itself it does not define a standard user identity or a shared login result across applications. Federation means accepting authentication information from another identity authority under a trust agreement; OIDC makes that distinction concrete in the next lesson.
The four roles are resource owner Mina, client Atlas Exporter, authorization server id.example.org and resource server Notes API. AS and RS can share an operator or process, but token issuance and resource enforcement remain distinct decisions. Client here means a server-side application, not the browser. The browser carries front-channel redirects; a confidential client’s credential is not embedded in browser code. A consent screen is not a mandatory visual step on every visit: AS policy can use an earlier approval.
A code is an intermediate credential
The client first creates a transaction for the selected AS, storing the redirect URI, requested scopes and browser-bound correlation. The browser visits the AS, which authenticates the owner and decides the grant. The callback carries a short-lived, single-use code. After tying that return to its own transaction, the client exchanges the code at the token endpoint. The code is not presented to the API. The AS checks its client, redirect URI, validity and use bindings; our selected S256 PKCE profile also requires the verifier to match the challenge bound to that code.
The animation shows the segment after callback acceptance: client-to-AS token request, the AS’s local gate, token response to the client and a normal resource request to the RS. Mina’s authentication, browser redirects and TLS handshakes are described in the artifact timeline but omitted from the scene. A token response arriving at the client does not mean the RS has read a note. Failure branches are declared policy outcomes of this normal flow, not measured provider errors.
The token’s recipient and the limit of scope
An access token is the credential used for access at the selected RS; OAuth does not require every access token to be a JWT. An opaque token’s audience and scope can come from the RS’s trusted validation context. The artifact shows these as readable policy fields rather than token bytes. If requested notes:read notes:write becomes a notes:read grant, the client accepts that reduction. Scope names are case-sensitive values defined by the AS; “read” is not the same permission in every application. The RS combines audience, time and scope checks with its own resource policy on every request.
A refresh token is for the token endpoint, not Notes API. It requests a new access token; it is neither an automatically endless session nor expanding authority. Issuance is optional, client binding remains, and refresh cannot request scopes outside the original grant. Current BCP requires sender constraint or rotation for public clients; a confidential client’s refresh token remains bound to its client. The fixture represents refresh through an alias and a narrowing matrix, without running rotation or issuing credentials.
2. Red · Trust & Impact
Read every scenario without motion
Foreign tenant
- The resource-action scope was selected
Mina’s atlas-exporter client uses access-A. This access context carries a notes:read grant; an authorization code or refresh token is not treated as an RS credential.
- Access grant context
- case=foreign-tenant
- Resource-server policy
- RS policy not applied
- Resource boundary
- No resource grant
- Requested and granted scopes were separated
The client requested notes:read and notes:write, but grantedScopes contains only notes:read. Requested scope is not permission granted by the consent/grant outcome.
- Access grant context
- Granted: notes:read
- Resource-server policy
- RS policy not applied
- Resource boundary
- No resource grant
- The recipient gate was evaluated
Audience notes-api matches and requiredScope notes:read is granted. These positive conditions do not remove the object-relationship check for a foreign tenant.
- Access grant context
- Granted: notes:read
- Resource-server policy
- Audience match; scope present
- Resource boundary
- No resource grant
- The object condition remained separate from scope
sameTenant=false while ownerMatches=true. Matching ownership cannot override tenant scope; a read-class grant does not grant access to every note.
- Access grant context
- Read grant scope
- Resource-server policy
- Tenant mismatch
- Resource boundary
- No resource grant
- The RS action decision remained negative
The expected result is object-denied. A successful code exchange at another stage does not turn this resource decision into allow.
- Access grant context
- Grant exists; this action denied
- Resource-server policy
- Reason: object-denied
- Resource boundary
- No resource allowance
- Each actor’s authority boundary was preserved
Client callback correlation, AS code binding and RS token/resource policy have different owners. This scene explains the RS reason without adding actual IdP, token-signature or body-delivery outcomes.
- Access grant context
- Known: declared read grant
- Resource-server policy
- Known: RS object-denied
- Resource boundary
- No broadened resource authority
Wrong audience
- The resource-action scope was selected
Mina’s atlas-exporter client uses access-A. This access context carries a notes:read grant; an authorization code or refresh token is not treated as an RS credential.
- Access grant context
- case=wrong-audience
- Resource-server policy
- RS policy not applied
- Resource boundary
- No resource grant
- Requested and granted scopes were separated
The client requested notes:read and notes:write, but grantedScopes contains only notes:read. Requested scope is not permission granted by the consent/grant outcome.
- Access grant context
- Granted: notes:read
- Resource-server policy
- RS policy not applied
- Resource boundary
- No resource grant
- The recipient gate was evaluated
The resource case selects recipient archive-api while the access audience is notes-api. The RS separates this mismatch as audience-denied; it does not label the token generally forged.
- Access grant context
- Granted: notes:read
- Resource-server policy
- Audience mismatch
- Resource boundary
- No resource grant
- The object condition remained separate from scope
True sameTenant and ownerMatches cannot compensate for the failed recipient gate. An object relationship does not establish token authority for another API.
- Access grant context
- Read grant scope
- Resource-server policy
- Audience mismatch retained
- Resource boundary
- No resource grant
- The RS action decision remained negative
The expected result is audience-denied. A successful code exchange at another stage does not turn this resource decision into allow.
- Access grant context
- Grant exists; this action denied
- Resource-server policy
- Reason: audience-denied
- Resource boundary
- No resource allowance
- Each actor’s authority boundary was preserved
Client callback correlation, AS code binding and RS token/resource policy have different owners. This scene explains the RS reason without adding actual IdP, token-signature or body-delivery outcomes.
- Access grant context
- Known: declared read grant
- Resource-server policy
- Known: RS audience-denied
- Resource boundary
- No broadened resource authority
ASSUMPTION · BOUNDARY · CONTROL
Which mistaken assumption expands authority?
A save button being visible after Exporter received notes:read is not proof of permission. The artifact allows own-note/read and denies own-note/write for scope. The latter is not a login failure: even a genuine grant can omit that action. In foreign-tenant/read, scope suffices but object policy denies access. A design that substitutes scope for object ownership extends an allowed action class to every object; impact depends on which data could be read or changed.
In the wrong-audience branch, the client selected the wrong API; the token is valid for another RS. Notes API rejecting it does not make the token globally fake: the recipient is wrong. In code-expired, the AS stops code exchange; the client cannot act as if an access token exists. Separate necessary conditions by actor: callback correlation at the client, code binding at the AS, token audience and resource policy at the RS. A positive decision by one actor does not replace another’s gate.
What bearer possession changes
For bearer use, possession matters for access, so treating a token as ordinary log or frontend display data is a mistaken storage assumption. Sender-constrained mechanisms are mentioned as design choices only; the bearer alias does not claim cryptographic client binding. PKCE also does not sender-constrain the access token at the API or replace a client secret in every context. These limits explain which boundary a credential protects, without providing a payload or intervention method.
3. Blue · Secure development & defense
Read every scenario without motion
Code deadline
- The code-exchange evidence was selected
Code-A carries expiresAt=1100, issuedAt=1000 and client/redirect/PKCE binding metadata. This alias is not an access token granting API resource permission.
- Grant/code observation
- code-A declaration
- AS contract review
- AS gate not examined
- Acceptance scope
- Token issuance not examined
- The confidential-client condition was read
The profile is a confidential server-side client. Normal and time-boundary cases separately supply clientAuthenticated=true; a PKCE match does not replace client authentication in every context.
- Grant/code observation
- Client: confidential server-side
- AS contract review
- Client/redirect/PKCE binding true
- Acceptance scope
- Token issuance not examined
- Last-valid and equality were compared
At now=1099 expected=true, while now=1100 gives expected=false. This fixture’s deadline stops code acceptance; access-token expiry is not assumed to share that deadline.
- Grant/code observation
- Last valid=1099; deadline=1100
- AS contract review
- Equality code exchange denied
- Acceptance scope
- Access issuance unsupported for this case
- Code and access outcomes were separated
The equality branch has a negative code predicate. Possessing the code alias cannot be interpreted as issuance of access-A; the AS outcome is separate evidence.
- Grant/code observation
- Code acceptance=false
- AS contract review
- Known: expiry boundary denial
- Acceptance scope
- No inferred access token
- Correlation evidence was scoped
The profile selects one-use state and a browser-bound transaction. The code matrix does not measure runtime client callback correlation or actual AS interoperability.
- Grant/code observation
- Selected: state + browser binding
- AS contract review
- Declared AS predicates
- Acceptance scope
- No runtime callback evidence
- The AS conclusion was not promoted to an RS conclusion
The code-deadline denial is known; no new access context is inferred from the AS. This record says nothing about RS acceptance of another grant or an earlier access alias.
- Grant/code observation
- Known: code expiry equality
- AS contract review
- No inferred token issuance
- Acceptance scope
- UNKNOWN: other access acceptance
Scope ledger
- The grant-scope record was selected
requestedScopes contains read and write; grantedScopes contains only read. Review preserves the consent request and AS grant outcome as distinct observations.
- Grant/code observation
- Requested: read+write
- AS contract review
- Grant not examined
- Acceptance scope
- Refresh scope not examined
- The AS grant outcome was compared
access-A is supplied with grantedScopes=[notes:read]. A write option in the client UI does not mean the omitted grant was issued.
- Grant/code observation
- Requested: read+write
- AS contract review
- Granted: read only
- Acceptance scope
- Refresh scope not examined
- Refresh recipient and scope were separated
refresh-A is for the AS token endpoint only and carries originalScopes=[notes:read]. It is not the access context presented as an RS credential.
- Grant/code observation
- Refresh original: notes:read
- AS contract review
- Recipient: AS token endpoint
- Acceptance scope
- No rotation runtime
- Scope omission and escalation were separated
A refresh request omitting the scope parameter has expected=true for the original scope. Requesting notes:write gives expected=false; omission creates no new grant.
- Grant/code observation
- Original scope retained
- AS contract review
- Omitted/read accepted; write denied
- Acceptance scope
- No inferred scope expansion
- The resource-action outcome was correlated
The RS allows own-note read and gives scope-denied for write. These match the grant scope; tenant/object conditions remain required even for read.
- Grant/code observation
- Grant: notes:read
- AS contract review
- Read allow; write scope-denied
- Acceptance scope
- Object policy remains required
- Grant-scope evidence was bounded
This ledger shows declared scopes and finite decision outcomes. Refresh rotationExecuted=false; no current revocation, actual token bytes or network-capture result is added.
- Grant/code observation
- Known: declared grant scope
- AS contract review
- Known: no scope expansion
- Acceptance scope
- UNKNOWN: runtime lifecycle
IMPLEMENTATION · SECURITY CONTROL · VERIFICATION
Keep the normal flow narrow and auditable
Atlas selects a confidential server-side client, code flow and S256 PKCE. Transaction correlation binds the browser and selected AS; credentials and verifier are not sent to browser code. Registered redirect URIs are compared exactly; the native localhost port exception is outside this web profile. Current BCP mandates PKCE for public clients and recommends it for confidential clients; CSRF prevention is mandatory but every profile need not use the same state mechanism. We additionally select one-use state. A multi-AS client explicitly designs issuer or distinct-redirect mix-up defenses.
Apply the BCP’s grant choices with their actual force: password grant is MUST NOT; implicit use is SHOULD NOT, with an exception only when the stated risks are mitigated. This lesson selects code flow. Minimum scopes, target RS audience and bounded credential use are explicit design choices. The RS allows access only when token validation, requested action and tenant/object conditions all hold. Neither a UI decision nor the client saying “scope present” is trusted; resource and job access preserve the same policy context.
Evidence from resource regression
The regression matrix includes positive own-note/read and three distinct negative boundaries: no write scope, wrong audience and foreign tenant. It tests the code time boundary as expired at 1100 and valid at 1099, under this fixture’s zero-leeway rule. Result records contain aliases, decision names and safe correlation rather than code or token bytes. This model check does not prove real AS interoperability, token signature verification or a learner lab; those need separate implementation and evidence.
NOW APPLY IT TO THE CASE
Which RS resource decision does an AS grant not complete?
Atlas exporter code, access and refresh aliases have different recipients and purposes. Requested scope, granted scope and object permission remain separate.
Which issuer/recipient relationship supplies identity in the case? Separate login or delegation success from evidence for current tenant/object permission.
Open the related case file ↗READ THE EXAMPLE TOGETHER
Atlas delegation decision table
Select a field and examine what it supports and where the evidence ends.
Read the raw artifact and field explanations
{
"profile": {
"clientType": "confidential server-side",
"flow": "authorization_code",
"pkce": "S256",
"oneUseStateSelected": true,
"browserBoundTransaction": true,
"actualProtocolRun": false,
"actualTokensIncluded": false,
"actualSignatureVerification": false
},
"actors": {
"resourceOwner": "Mina",
"client": "atlas-exporter",
"authorizationServer": "https://id.example.org",
"resourceServer": "notes-api"
},
"timeline": [
"client creates AS/browser-bound transaction",
"browser visits AS authorization endpoint",
"AS authenticates owner and decides grant",
"browser follows code callback",
"client validates transaction correlation",
"client exchanges code at token endpoint",
"client receives access token plus optional refresh token",
"RS validates token context and requested resource"
],
"code": {
"alias": "code-A",
"clientId": "atlas-exporter",
"redirectUri": "https://atlas.example.org/callback",
"issuedAt": 1000,
"expiresAt": 1100,
"used": false,
"pkceBindingDeclared": true
},
"codeCases": [
{
"name": "normal",
"now": 1050,
"clientMatches": true,
"redirectMatches": true,
"pkceMatches": true,
"used": false,
"expected": true,
"clientAuthenticated": true
},
{
"name": "last-valid",
"now": 1099,
"clientMatches": true,
"redirectMatches": true,
"pkceMatches": true,
"used": false,
"expected": true,
"clientAuthenticated": true
},
{
"name": "expiry-equality",
"now": 1100,
"clientMatches": true,
"redirectMatches": true,
"pkceMatches": true,
"used": false,
"expected": false,
"clientAuthenticated": true
},
{
"name": "already-consumed",
"now": 1050,
"clientMatches": true,
"redirectMatches": true,
"pkceMatches": true,
"used": true,
"expected": false,
"clientAuthenticated": true
},
{
"name": "binding-unmet",
"now": 1050,
"clientMatches": true,
"redirectMatches": true,
"pkceMatches": false,
"used": false,
"expected": false,
"clientAuthenticated": true
},
{
"name": "client-auth-unmet",
"now": 1050,
"clientMatches": true,
"redirectMatches": true,
"pkceMatches": true,
"clientAuthenticated": false,
"used": false,
"expected": false
}
],
"access": {
"alias": "access-A",
"representation": "opaque alias, metadata is declarative validated context",
"audience": "notes-api",
"requestedScopes": [
"notes:read",
"notes:write"
],
"grantedScopes": [
"notes:read"
],
"expiresAt": 2000
},
"refresh": {
"alias": "refresh-A",
"recipient": "AS token endpoint only",
"optional": true,
"clientBound": true,
"originalScopes": [
"notes:read"
],
"rotationExecuted": false
},
"refreshCases": [
{
"requestedScopes": [
"notes:read"
],
"expected": true
},
{
"requestedScopes": [],
"expected": true,
"scopeParameterOmitted": true
},
{
"requestedScopes": [
"notes:write"
],
"expected": false
}
],
"resourceCases": [
{
"case": "normal",
"audience": "notes-api",
"action": "read",
"requiredScope": "notes:read",
"now": 1050,
"sameTenant": true,
"ownerMatches": true,
"expected": "allow"
},
{
"case": "scope-denied",
"audience": "notes-api",
"action": "write",
"requiredScope": "notes:write",
"now": 1050,
"sameTenant": true,
"ownerMatches": true,
"expected": "scope-denied"
},
{
"case": "wrong-audience",
"audience": "archive-api",
"action": "read",
"requiredScope": "notes:read",
"now": 1050,
"sameTenant": true,
"ownerMatches": true,
"expected": "audience-denied"
},
{
"case": "foreign-tenant",
"audience": "notes-api",
"action": "read",
"requiredScope": "notes:read",
"now": 1050,
"sameTenant": false,
"ownerMatches": true,
"expected": "object-denied"
}
]
}- actors
- Role ownership; the four roles make separate decisions.
- code
- Client, redirect, time, use and PKCE bindings; not code bytes.
- access
- Granted scope and RS audience context; not an asserted JWT claim.
- refreshCases
- Scope sets that do not exceed the first grant; no credential renewal runs.
- resourceCases
- Selected decisions that keep scope and object policy separate.
All code/token values are aliases. The scene starts after callback; it runs no browser, real AS, TLS, PKCE hash production, signature/introspection or refresh.
Two reality checks
An access token is a user login statement.
An OAuth access token is for RS access; OIDC adds a standard authentication statement through the ID token.
Read scope opens all of a user’s notes.
The RS checks audience, scope and tenant/object policy together on each request.
YOUR TURN
Work through this story.
Predict the outcome, find the evidence boundary, and explain it in your own words.
The client requested notes:read and notes:write; the access context grants only notes:read. Is writing allowed?
- No; the selected branch is scope-denied.
- Yes; requesting write during authorization is sufficient for a grant.
Read the explained answer
No; the selected branch is scope-denied. — The AS grant is limited to read; requested scope creates no permission. The RS checks the required write scope.
Are code, refresh and access aliases sent to the same endpoint?
Selected lesson artifact fields; teaching example
- code.clientId
- atlas-exporter
- refresh.recipient
- AS token endpoint only
- access.audience
- notes-api
- The RS accepts a refresh alias instead of access in an ordinary API request.
- Code exchange/refresh belong to the AS token endpoint; access belongs to notes-api.
Read the explained answer
Code exchange/refresh belong to the AS token endpoint; access belongs to notes-api. — Each alias has a different stage/purpose; refresh recipient is explicitly AS only.
Audience and read scope are valid, but the resource belongs to a foreign tenant. Why is an object gate still required?
Read the explained answer
The RS evaluates token context for audience/time/granted scopes, then applies requested-object tenant/owner policy. Read scope does not release every note from another tenant. The authorization code is carried through the browser callback, not an API access token; this fixture executes no actual protocol run.
□ I did not count scope as an object grant.
□ I separated the code from the API-access credential.
Open the application console · request / response / browser
Also open request, URL, cookie and DOM examples
Sources and scope
- RFC 6749 — The OAuth 2.0 Authorization Framework§1.1 Roles; §1.2 Protocol Flow; §1.3.1 Authorization Code · §1.4 Access Token; §1.5 Refresh Token · §3.2.1 Client Authentication; §3.3 Access Token Scope · §4.1.1–4.1.4 Authorization Code Grant · §5.1 Successful Response; §6 Refreshing an Access Token; §7 Accessing Protected Resources
- RFC 9700 — Best Current Practice for OAuth 2.0 Security§2.1 Protecting Redirect-Based Flows; §2.1.1 Authorization Code Grant · §2.1.2 Implicit Grant; §2.2.1 Access Tokens; §2.2.2 Refresh Tokens · §2.3 Access Token Privilege Restriction; §2.4 Resource Owner Password Credentials Grant; §2.5 Client Authentication
- RFC 7636 — Proof Key for Code Exchange by OAuth Public Clients§4.3 Client Sends the Code Challenge; §4.4 Server Returns the Code · §4.5 Client Sends Code and Verifier; §4.6 Server Verifies code_verifier
- RFC 6750 — The OAuth 2.0 Authorization Framework: Bearer Token Usage§1.2 Terminology: Bearer Token · §2.1 Authorization Request Header Field · §2.3 URI Query Parameter security qualifications
- OWASP OAuth2 Cheat SheetTerminology; OAuth 2.0 Essential Basics · PKCE — Proof Key for Code Exchange Mechanism · Access Token Privilege Restriction
- OWASP Authorization Cheat SheetRecommendations / Enforce Least Privileges · Recommendations / Deny by Default; Validate the Permissions on Every Request
- OpenID Connect Core 1.0 — Final incorporating errata set 2§1 Introduction; §1.2 Terminology: OP and RP