WEB / WEB-14.S03
Token verification, purpose and key lifecycle
Separate token integrity evidence from API purpose and key-lifecycle acceptance.
1. Core · Mechanism
Read every scenario without motion
Valid profile
- Read intent
The client follows an owned API acceptance context for one known public note title.
- Atlas client
- No title; read intent
- Token verifier
- No acceptance; configured keys
- Public note store
- Public title stored; no delivery
- Request prepared
The inert token alias and known read operation are prepared without actual token bytes or keys.
- Atlas client
- Read request ready; alias=normal
- Token verifier
- No acceptance; configured keys
- Public note store
- Public title stored; no delivery
- Verifier received
The selected read request has reached the verifier. Its header and claims are not yet accepted identity or resource permission.
- Atlas client
- Read request ready; alias=normal
- Token verifier
- Request arrived; acceptance pending
- Public note store
- Public title stored; no delivery
- Local acceptance
Trusted key/crypto declarations and issuer/audience/purpose/time profile pass before preparing resource read.
- Atlas client
- Read request ready; alias=normal
- Token verifier
- All gates accepted; resource read ready
- Public note store
- Public title stored; no delivery
- Read at store
The known public-note read has arrived at the store; arrival does not yet create a response body.
- Atlas client
- Read request ready; alias=normal
- Token verifier
- All gates accepted; resource read ready
- Public note store
- Read arrived; title body pending
- Local public read
The owned store locally selects the permitted public title projection without mutating the note.
- Atlas client
- Read request ready; alias=normal
- Token verifier
- All gates accepted; resource read ready
- Public note store
- Title response ready; Tea & Bread
- Title at verifier
The public title response has arrived at the verifier; the fixed relay adds no further permission.
- Atlas client
- Read request ready; alias=normal
- Token verifier
- Public body arrived; client response ready
- Public note store
- Title response ready; Tea & Bread
- Client received
The response has arrived and ordinary title data is available; this stage runs no DOM parsing or display.
- Atlas client
- Response arrived; title=Tea & Bread
- Token verifier
- Public body arrived; client response ready
- Public note store
- Title response ready; Tea & Bread
Wrong purpose
- Read intent
The client follows an owned API acceptance context for one known public note title.
- Atlas client
- No title; read intent
- Token verifier
- No acceptance; configured keys
- Public note store
- Public title stored; no delivery
- Request prepared
The inert token alias and known read operation are prepared without actual token bytes or keys.
- Atlas client
- Read request ready; alias=wrong-purpose
- Token verifier
- No acceptance; configured keys
- Public note store
- Public title stored; no delivery
- Verifier received
The selected read request has reached the verifier. Its header and claims are not yet accepted identity or resource permission.
- Atlas client
- Read request ready; alias=wrong-purpose
- Token verifier
- Request arrived; acceptance pending
- Public note store
- Public title stored; no delivery
- Local key evidence
The key is key-v2 from the configured issuer, with state=active and supplied signatureVerifiedDeclared=true. These positive conditions alone do not establish use for notes-read; the purpose decision remains pending.
- Atlas client
- Read request ready; alias=wrong-purpose
- Token verifier
- Configured key/crypto declared valid; profile pending
- Public note store
- Public title stored; no delivery
- Local profile gate
The claims carry purpose=preview-render while the profile requires notes-read. The mismatch gives expectedAccepted=false. The verifier prepares no resource read; body=null and delivery=false remain.
- Atlas client
- Read request ready; alias=wrong-purpose
- Token verifier
- Acceptance denied: purpose; no body
- Public note store
- Public title stored; no delivery
- Denial prepared
A harmless denial result is prepared without sending a read or mutation message to the resource store.
- Atlas client
- Read request ready; alias=wrong-purpose
- Token verifier
- Denial response ready; no resource body
- Public note store
- Public title stored; no delivery
- Denial at client
The denial result has arrived with no protected note body and no preceding resource delivery.
- Atlas client
- Denial arrived; title absent
- Token verifier
- Denial response ready; no resource body
- Public note store
- Public title stored; no delivery
Retired key
- Read intent
The client follows an owned API acceptance context for one known public note title.
- Atlas client
- No title; read intent
- Token verifier
- No acceptance; configured keys
- Public note store
- Public title stored; no delivery
- Request prepared
The inert token alias and known read operation are prepared without actual token bytes or keys.
- Atlas client
- Read request ready; alias=retired-key
- Token verifier
- No acceptance; configured keys
- Public note store
- Public title stored; no delivery
- Verifier received
The selected read request has reached the verifier. Its header and claims are not yet accepted identity or resource permission.
- Atlas client
- Read request ready; alias=retired-key
- Token verifier
- Request arrived; acceptance pending
- Public note store
- Public title stored; no delivery
- Local key evidence
Although key-v1 belongs to the trusted issuer, state=retired and verifyUntil=1700000090. The key is not permitted for acceptance at profile now=1700000100. This differs from reaching the token’s exp boundary.
- Atlas client
- Read request ready; alias=retired-key
- Token verifier
- key-v1 retired; acceptance denied
- Public note store
- Public title stored; no delivery
- Local profile gate
The token satisfies its nbf/exp interval, but the prior key-policy rejection remains: reason=key-retired. The verifier prepares no resource read; body=null, delivery=false and mutation=false remain.
- Atlas client
- Read request ready; alias=retired-key
- Token verifier
- Acceptance denied: key-retired; no body
- Public note store
- Public title stored; no delivery
- Denial prepared
A harmless denial result is prepared without sending a read or mutation message to the resource store.
- Atlas client
- Read request ready; alias=retired-key
- Token verifier
- Denial response ready; no resource body
- Public note store
- Public title stored; no delivery
- Denial at client
The denial result has arrived with no protected note body and no preceding resource delivery.
- Atlas client
- Denial arrived; title absent
- Token verifier
- Denial response ready; no resource body
- Public note store
- Public title stored; no delivery
Key unavailable
- Read intent
The client follows an owned API acceptance context for one known public note title.
- Atlas client
- No title; read intent
- Token verifier
- No acceptance; configured keys
- Public note store
- Public title stored; no delivery
- Request prepared
The inert token alias and known read operation are prepared without actual token bytes or keys.
- Atlas client
- Read request ready; alias=unknown-key
- Token verifier
- No acceptance; configured keys
- Public note store
- Public title stored; no delivery
- Verifier received
The selected read request has reached the verifier. Its header and claims are not yet accepted identity or resource permission.
- Atlas client
- Read request ready; alias=unknown-key
- Token verifier
- Request arrived; acceptance pending
- Public note store
- Public title stored; no delivery
- Local key evidence
kid=key-unlisted was not found in the configured issuer key set. With signatureVerifiedDeclared=null, the signature is neither known valid nor invalid. No trusted-source refresh outcome is available, and an untrusted header URL is not a key source.
- Atlas client
- Read request ready; alias=unknown-key
- Token verifier
- Key unavailable; crypto evidence unknown
- Public note store
- Public title stored; no delivery
- Local profile gate
Missing key-verification evidence stops acceptance with reason=key-unavailable. This known fail-closed decision does not prove forgery. No resource read is prepared; body=null, delivery=false and mutation=false remain.
- Atlas client
- Read request ready; alias=unknown-key
- Token verifier
- Acceptance denied: key-unavailable; no body
- Public note store
- Public title stored; no delivery
- Denial prepared
A harmless denial result is prepared without sending a read or mutation message to the resource store.
- Atlas client
- Read request ready; alias=unknown-key
- Token verifier
- Denial response ready; no resource body
- Public note store
- Public title stored; no delivery
- Denial at client
The denial result has arrived with no protected note body and no preceding resource delivery.
- Atlas client
- Denial arrived; title absent
- Token verifier
- Denial response ready; no resource body
- Public note store
- Public title stored; no delivery
ACTORS · STATE · DATA FLOW
Which protection does the token format carry?
Atlas gives Duru a notes-read access context for the public title Tea & Bread. JWT is the claims-bearing format; JWS provides integrity through a signature or MAC, while JWE uses authenticated encryption for confidentiality and integrity. JWS Compact has three parts and JWE Compact five; counting them is not validation. A signed payload is ordinarily readable: base64url is not encryption. Decrypting JWE does not by itself prove the expected issuer; key provenance and the profile still matter. Nested tokens require validation of every required outer and inner cryptographic operation. The artifact separates inert header and claims fields; signatureVerifiedDeclared is an assumed result, not a JWT string or parser output.
The verifier owns the acceptance profile
The verifier does not let alg freely choose its cryptography: the application binds allowed algorithms and key usage to the operation. kid selects within a trusted issuer key set and is not a trust anchor. Atlas requires issuer, an issuer-subject pair, audience, typ and notes-read purpose. aud can be one string or an array of strings, matched against the intended recipient. Here purpose is an application-specific claim and atlas-notes+jwt an illustrative profile type, not universal JWT requirements. Registered claims are not all mandatory in every application; this profile explicitly lists requiredClaims. An API access context, ID token and differently purposed signed object need distinct acceptance rules. Object/action authorization still follows accepted identity.
Time and key lifecycle are separate decisions
NumericDate counts UTC epoch seconds, unlike JavaScript milliseconds. With zero skew, this fixture requires now >= nbf and now < exp; equality at exp rejects acceptance. iat describes issuance and is not itself not-before or logout enforcement; small skew and maximum age belong to the deployment profile. An active signing key and an older verification key may overlap under explicit policy. Atlas key-v1 is beyond verifyUntil while key-v2 remains active. An unavailable trusted-source refresh for an unknown kid gives no acceptance evidence and does not automatically prove forgery. Rotation, emergency revocation, cache propagation and session logout are separate lifecycle events. Preserve a configured issuer-key binding rather than downloading keys from arbitrary header URLs.
2. Red · Trust & Impact
Read every scenario without motion
Key retired
- The token-profile scope was selected
This case is evaluated under notes-read purpose, atlas-notes+jwt type and atlas-notes-api recipient policy. Decoded claims alone are not trusted context.
- Token profile
- case=retired-key
- Key/purpose gate
- Key/profile not examined
- Resource boundary
- No resource body
- The signature predicate was read separately
signatureVerifiedDeclared=true is supplied. This positive predicate does not automatically complete trusted-key lifecycle or operation-purpose gates.
- Token profile
- case=retired-key
- Key/purpose gate
- Declared signature=true
- Resource boundary
- No resource body
- The key-state or purpose boundary was applied
kid=key-v1 is bound to the configured issuer, but has state=retired and verifyUntil=1700000090. Verification use is not permitted at profile now=1700000100.
- Token profile
- case=retired-key
- Key/purpose gate
- Key retired at current profile time
- Resource boundary
- No resource body
- Time and other gates were kept distinct
exp=1700000300 and nbf=1700000000 satisfy this profile time. Valid token time does not restore permission to use a retired key.
- Token profile
- case=retired-key
- Key/purpose gate
- Time condition valid
- Resource boundary
- No resource body
- Delivery and mutation were withheld
expectedAccepted=false, expectedBody=null, expectedResourceDelivery=false and expectedMutation=false remain. Crypto success does not establish trusted action context for this note.
- Token profile
- case=retired-key
- Key/purpose gate
- Reason: key-retired
- Resource boundary
- Body=null; delivery=false; mutation=false
- Key provenance remained distinct from hints
kid is a selection hint, not a trust anchor. Retirement policies can differ, but this configured denial is not relabelled as issuer compromise or an expired JWT.
- Token profile
- case=retired-key
- Key/purpose gate
- Configured denial known
- Resource boundary
- No trusted resource dispatch
Wrong purpose
- The token-profile scope was selected
This case is evaluated under notes-read purpose, atlas-notes+jwt type and atlas-notes-api recipient policy. Decoded claims alone are not trusted context.
- Token profile
- case=wrong-purpose
- Key/purpose gate
- Key/profile not examined
- Resource boundary
- No resource body
- The signature predicate was read separately
signatureVerifiedDeclared=true is supplied. This positive predicate does not automatically complete trusted-key lifecycle or operation-purpose gates.
- Token profile
- case=wrong-purpose
- Key/purpose gate
- Declared signature=true
- Resource boundary
- No resource body
- The key-state or purpose boundary was applied
The claims carry purpose=preview-render while policy requires notes-read. Matching issuer and audience do not satisfy this different-use purpose gate.
- Token profile
- case=wrong-purpose
- Key/purpose gate
- Purpose preview-render ≠ notes-read
- Resource boundary
- No resource body
- Time and other gates were kept distinct
exp=1700000300 and nbf=1700000000 satisfy this profile time. Valid token time does not turn the wrong purpose into the right one.
- Token profile
- case=wrong-purpose
- Key/purpose gate
- Time condition valid
- Resource boundary
- No resource body
- Delivery and mutation were withheld
expectedAccepted=false, expectedBody=null, expectedResourceDelivery=false and expectedMutation=false remain. Crypto success does not establish trusted action context for this note.
- Token profile
- case=wrong-purpose
- Key/purpose gate
- Reason: purpose
- Resource boundary
- Body=null; delivery=false; mutation=false
- Key provenance remained distinct from hints
Signed claims are unsuitable for this purpose. JWE encryption also does not remove recipient/purpose acceptance rules; protection format is not an action grant.
- Token profile
- case=wrong-purpose
- Key/purpose gate
- Configured denial known
- Resource boundary
- No trusted resource dispatch
ASSUMPTION · BOUNDARY · CONTROL
Overinterpreting cryptographic success
Normal signature success says the supplied bytes verified under a configured key; it does not establish suitability for this recipient and operation. The broken assumption is that every signed claim set from a trusted issuer means the same thing in every consumer. Confusion requires distinct token purposes/profiles and a consumer failing to separate audience, type or required values. Impact is misinterpreted identity or access scope, not automatically universal account compromise. The wrong-purpose row retains signatureVerifiedDeclared=true yet rejects API acceptance, with no resource delivery or title body. Mutually exclusive profiles and separate object authorization preserve the boundary; encryption alone does not correct purpose confusion.
Mistaking key selection for trust provenance
Normal rollout may retain an older verification key for a defined interval; key-v1 does not necessarily mean an expired JWT. The broken assumption is that finding kid proves issuer ownership and continued permitted use. Stale caches, rollover delay or trusted-key-service outage can be benign; the unknown row therefore records key-unavailable separately. The retired row has valid time claims but fails application key policy. Controls bind trusted provenance, algorithm/use and retirement or revocation propagation. Impact is limited to the context accepted by that consumer; there is no key material or bearer token in the artifact.
3. Blue · Secure development & defense
Read every scenario without motion
Key unavailable
- The unknown-key observation was selected
The header carries kid=key-unlisted, absent from the configured key list. Missing key metadata and an invalid-signature outcome are different evidence.
- Verification observation
- case=unknown-key
- Key/lifecycle review
- Key lookup not examined
- Evidence conclusion
- No acceptance conclusion
- The trusted-provenance boundary was read
The approved source is the configured issuer-bound key-alias set. An untrusted header URL is not fetched; kid text does not independently establish issuer/key trust.
- Verification observation
- kid=key-unlisted
- Key/lifecycle review
- Configured key not found
- Evidence conclusion
- No acceptance conclusion
- The crypto outcome remained unknown
signatureVerifiedDeclared=null supports neither a valid nor invalid signature conclusion. A stale cache, rollout or trusted-service outage is not established as the cause of this gap.
- Verification observation
- case=unknown-key
- Key/lifecycle review
- Signature outcome=null
- Evidence conclusion
- UNKNOWN: crypto verification
- Acceptance stayed closed on missing evidence
The reason is key-unavailable with expectedAccepted=false. This fail-closed decision produces no body, mutation or resource delivery; an unavailable key is not forgery evidence.
- Verification observation
- case=unknown-key
- Key/lifecycle review
- Reason: key-unavailable
- Evidence conclusion
- No body/mutation/delivery
- Refresh evidence was requested separately
The lifecycle selects bounded trusted-source refresh, but this scene performs no networking. Acceptance is not assumed before key-source and freshness outcomes are available.
- Verification observation
- case=unknown-key
- Key/lifecycle review
- Trusted freshness required
- Evidence conclusion
- UNKNOWN: refreshed key outcome
- The unknown/invalid distinction was preserved
The known outcome is no acceptance; signature validity remains unknown. Key rotation, revocation and trusted provenance are explained using their own evidence.
- Verification observation
- Known: key unavailable
- Key/lifecycle review
- UNKNOWN: signature validity
- Evidence conclusion
- Known: delivery withheld
Logout scope
- The lifecycle-policy record was selected
logoutMeansAutomaticJWTRevocation=false describes a format limitation. Even with browser cleanup or session-logout observations, all JWT acceptance states do not have one owner.
- Verification observation
- Lifecycle policy
- Key/lifecycle review
- Revocation path not examined
- Evidence conclusion
- Current acceptance unknown
- The key-overlap policy was read
oldKeyOverlapIsConfiguredNotUniversal=true. How long an old key remains usable for verification during rotation is configuration, not a property inferred from token formatting.
- Verification observation
- Lifecycle policy
- Key/lifecycle review
- Overlap configured
- Evidence conclusion
- Current acceptance unknown
- Emergency revocation was kept separate
compromiseRequiresExplicitRevocationPolicy=true marks the need for separate emergency-revocation design. Routine overlap is not automatic incident response.
- Verification observation
- Lifecycle policy
- Key/lifecycle review
- Explicit revoke policy required
- Evidence conclusion
- Current acceptance unknown
- JWS and confidentiality were separated
The JWS Compact ledger has confidentiality=false. A signature can contribute to an integrity/authenticity profile, but guarantees neither unreadable payloads nor logout revocation.
- Verification observation
- JWS confidentiality=false
- Key/lifecycle review
- Protection and lifecycle separate
- Evidence conclusion
- Current acceptance unknown
- JWE was not broadened into issuer proof
JWE carries authenticated encryption, while issuer identity remains profile-bound. Encryption does not complete key-source, purpose or current-revocation observations.
- Verification observation
- JWE protection class known
- Key/lifecycle review
- Issuer profile remains required
- Evidence conclusion
- UNKNOWN: current revocation
- The lifecycle conclusion preserved unknown state
This artifact shows policy boundaries with actualRevocationService=false. Neither an active key nor a logout statement establishes that every consumer currently accepts or rejects the token.
- Verification observation
- Known: lifecycle policy boundaries
- Key/lifecycle review
- No runtime revocation observation
- Evidence conclusion
- UNKNOWN: consumer acceptance
IMPLEMENTATION · SECURITY CONTROL · VERIFICATION
Separate the verifier decision into fields
Observe profile ID, configured issuer, audience and purpose/type matches, subject mapping, key alias/state, cryptographic result and time-gate reason alongside accepted or denied. Keep raw tokens, personal payloads and private keys out of logs. A decoded observation is not positive verification; an upstream 401 or cache miss alone is not key-compromise evidence. Baseline uses an active key, intended recipient/purpose and bounded time. Separate unknown key, invalid signature and retired key, correlating trusted-source freshness and refresh outcome. Here denial visibly lacks a resource message and title body; no service audit schema or JWT library result is invented.
Exercise rotation and acceptance regression together
Manage acceptance-policy versions with issuer-key provenance. Routine rotation defines old-key verification overlap, maximum token lifetime and bounded cache refresh; emergency revocation needs a separate decision. Signature-valid wrong audience/purpose, now=exp, now=nbf and retired key require distinct regression cases. Fail-closed handling of unavailable evidence differs from attack attribution. The library must support the profile’s unknown-header, critical-extension and nested-crypto rules. A signature primitive working on public note bytes does not verify JWT/JWS acceptance rules or a JWKS lifecycle. Session logout requires separate server state or revocation control; JWT format alone supplies no distributed revocation.
NOW APPLY IT TO THE CASE
How do signatures, key lifecycle and purpose bind together?
The note-read profile requires approved issuer, key state and purpose together. An unknown-key outcome establishes neither forgery nor current revocation.
Separate decisions for verified actor, tenant relation and requested action in the case. Do not substitute authentication or proof success for object permission.
Open the related case file ↗READ THE EXAMPLE TOGETHER
Token acceptance ledger
Select a field and examine what it supports and where the evidence ends.
Read the raw artifact and field explanations
{
"profile": {
"issuer": "https://identity.example.org",
"audience": "atlas-notes-api",
"purpose": "notes-read",
"typ": "atlas-notes+jwt",
"allowedAlgorithms": [
"RS256"
],
"subject": "Duru",
"now": 1700000100,
"clockSkewSeconds": 0,
"requiredClaims": [
"iss",
"sub",
"aud",
"exp",
"nbf",
"iat",
"purpose"
],
"actualJWT": false,
"actualJWKS": false,
"actualNetwork": false,
"actualRevocationService": false,
"publicNoteReadPermissionDeclared": true,
"noteId": "note-A"
},
"formatLedger": [
{
"format": "JWT",
"content": "claims set",
"protection": "selected JWS or JWE profile; not implied by decode"
},
{
"format": "JWS Compact",
"parts": [
"protected-header",
"payload",
"signature-or-MAC"
],
"confidentiality": false
},
{
"format": "JWE Compact",
"parts": [
"protected-header",
"encrypted-key",
"iv",
"ciphertext",
"authentication-tag"
],
"protection": "authenticated encryption; issuer identity still profile-bound"
}
],
"keys": [
{
"kid": "key-v2",
"issuer": "https://identity.example.org",
"algorithm": "RS256",
"use": "sig",
"state": "active",
"verifyUntil": 1700000600
},
{
"kid": "key-v1",
"issuer": "https://identity.example.org",
"algorithm": "RS256",
"use": "sig",
"state": "retired",
"verifyUntil": 1700000090
}
],
"rows": [
{
"case": "normal",
"header": {
"typ": "atlas-notes+jwt",
"alg": "RS256",
"kid": "key-v2"
},
"claims": {
"iss": "https://identity.example.org",
"sub": "Duru",
"aud": [
"atlas-notes-api"
],
"exp": 1700000300,
"nbf": 1700000000,
"iat": 1700000000,
"purpose": "notes-read"
},
"signatureVerifiedDeclared": true,
"expectedAccepted": true,
"reason": "accepted",
"expectedBody": {
"title": "Tea & Bread"
},
"expectedResourceDelivery": true,
"expectedMutation": false
},
{
"case": "wrong-purpose",
"header": {
"typ": "atlas-notes+jwt",
"alg": "RS256",
"kid": "key-v2"
},
"claims": {
"iss": "https://identity.example.org",
"sub": "Duru",
"aud": [
"atlas-notes-api"
],
"exp": 1700000300,
"nbf": 1700000000,
"iat": 1700000000,
"purpose": "preview-render"
},
"signatureVerifiedDeclared": true,
"expectedAccepted": false,
"reason": "purpose",
"expectedBody": null,
"expectedResourceDelivery": false,
"expectedMutation": false
},
{
"case": "retired-key",
"header": {
"typ": "atlas-notes+jwt",
"alg": "RS256",
"kid": "key-v1"
},
"claims": {
"iss": "https://identity.example.org",
"sub": "Duru",
"aud": [
"atlas-notes-api"
],
"exp": 1700000300,
"nbf": 1700000000,
"iat": 1700000000,
"purpose": "notes-read"
},
"signatureVerifiedDeclared": true,
"expectedAccepted": false,
"reason": "key-retired",
"expectedBody": null,
"expectedResourceDelivery": false,
"expectedMutation": false
},
{
"case": "unknown-key",
"header": {
"typ": "atlas-notes+jwt",
"alg": "RS256",
"kid": "key-unlisted"
},
"claims": {
"iss": "https://identity.example.org",
"sub": "Duru",
"aud": [
"atlas-notes-api"
],
"exp": 1700000300,
"nbf": 1700000000,
"iat": 1700000000,
"purpose": "notes-read"
},
"signatureVerifiedDeclared": null,
"expectedAccepted": false,
"reason": "key-unavailable",
"expectedBody": null,
"expectedResourceDelivery": false,
"expectedMutation": false
}
],
"timeRows": [
{
"now": 1700000000,
"nbf": 1700000000,
"exp": 1700000300,
"expected": true
},
{
"now": 1699999999,
"nbf": 1700000000,
"exp": 1700000300,
"expected": false
},
{
"now": 1700000300,
"nbf": 1700000000,
"exp": 1700000300,
"expected": false
}
],
"lifecycle": {
"signingKey": "key-v2",
"oldKeyOverlapIsConfiguredNotUniversal": true,
"unknownKeyRefresh": "bounded trusted-source refresh; unavailable is no acceptance evidence",
"logoutMeansAutomaticJWTRevocation": false,
"compromiseRequiresExplicitRevocationPolicy": true,
"untrustedHeaderURLFetched": false
},
"boundaries": {
"decodedClaimsTrusted": false,
"signatureGrantsAllActions": false,
"jweProvesIssuerByItself": false,
"kidIsTrustAnchor": false,
"unavailableKeyProvesForgery": false
},
"audienceRows": [
{
"aud": [
"atlas-notes-api"
],
"expected": true
},
{
"aud": "atlas-notes-api",
"expected": true
},
{
"aud": [
"book-preview"
],
"expected": false
},
{
"aud": [],
"expected": false
}
]
}- formatLedger
- Claims versus cryptographic container.
- profile
- Consumer-owned acceptance requirements.
- keys
- Trusted aliases, use and lifecycle without secrets.
- rows
- Declared crypto outcome and independent acceptance decisions.
- timeRows
- Zero-skew NumericDate equality boundaries.
Fixed header/claim/key aliases and acceptance truth table; not a JWT parser, signature-verification or JWKS-fetch result. Time uses zero skew and an explicitly selected application key policy.
Two reality checks
A valid signature makes the token valid at every API.
Audience, purpose/profile, time and key policy still require acceptance.
An unknown kid proves token forgery.
Unavailable provenance prevents acceptance while root cause remains separate.
YOUR TURN
Work through this story.
Predict the outcome, find the evidence boundary, and explain it in your own words.
Signature verification is supplied as true, but purpose=preview-render while notes-read is required. Is the note body released?
- No. The reason is purpose and expectedBody=null.
- Yes. A signature approves every purpose and action.
Read the explained answer
No. The reason is purpose and expectedBody=null. — This profile requires purpose matching. A valid signature does not convert a token for another purpose into a notes-read grant.
The key is unavailable and signatureVerifiedDeclared=null. Does this record prove the token is a forgery?
Selected lesson artifact fields; teaching example
- rows[3].header.kid
- key-unlisted
- rows[3].signatureVerifiedDeclared
- null
- rows[3].reason
- key-unavailable
- rows[3].expectedResourceDelivery
- false
- boundaries.unavailableKeyProvesForgery
- false
- Yes. An unknown kid is always proven forgery.
- No. Acceptance is withheld, but forgery is not proven.
Read the explained answer
No. Acceptance is withheld, but forgery is not proven. — key-unavailable withholds delivery. unavailableKeyProvesForgery=false; the signature result is unknown.
JWS Compact provides no confidentiality, while JWE issuer identity remains profile-bound. What separate decisions are needed for key rotation and logout?
Read the explained answer
Decoding claims does not establish trusted identity. JWS provides signature/MAC protection, not confidentiality; JWE uses authenticated encryption but issuer acceptance still requires profile conditions. Key state and verifyUntil follow the configured lifecycle policy, and old-key overlap is not universal. Logout does not automatically revoke every JWT. Current revocation and resource policy remain separate. This ledger executes no real JWT/JWKS or revocation service.
□ I separated decoding, signature and encryption roles.
□ I did not infer universal revocation from rotation or logout.
Open the application console · request / response / browser
Also open request, URL, cookie and DOM examples
Sources and scope
- RFC7519 — JSON Web Token§2 NumericDate/JWT; §3 claims in JWS/JWE; §4.1.1–4.1.6 issuer/subject/audience/time; §5.1 typ application processing
- RFC7515 — JSON Web Signature§2 protected/unprotected header and digital signature/MAC; §3.1 Compact Serialization; §5.2 validation/application algorithm policy
- RFC7516 — JSON Web Encryption§2 authenticated encryption and AAD; §3/§3.1 integrity/confidentiality and five compact parts
- RFC8725 — JWT Best Current Practices (BCP225)§3.1–3.3 caller algorithm policy/all nested cryptographic operations; §3.8 issuer-key/subject binding; §3.9–3.12 audience/untrusted locators/typing/mutually exclusive profiles
- RFC7517 — JSON Web Key§4.2 use; §4.3 key_ops; §4.4 alg; §4.5 case-sensitive optional kid selection during rollover