From c45f63ccbc577ce716983a907cdbd3f5a4081373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mehmet=20Can=20Karag=C3=B6z?= Date: Mon, 12 Oct 2026 23:42:26 +0300 Subject: [PATCH] Update v 0.1.0 With Docs Sample Page --- .../wwwroot/docs/auth-flows/refresh-flow.json | 90 +++++++------------ 1 file changed, 30 insertions(+), 60 deletions(-) diff --git a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/auth-flows/refresh-flow.json b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/auth-flows/refresh-flow.json index f0c9d34e..f7e92910 100644 --- a/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/auth-flows/refresh-flow.json +++ b/docs/website/CodeBeam.UltimateAuth.Docs.Wasm/CodeBeam.UltimateAuth.Docs.Wasm.Client/wwwroot/docs/auth-flows/refresh-flow.json @@ -1,106 +1,76 @@ { "Slug": "auth-flows/refresh-flow", "Title": "Refresh", - "Html": "\n\u003Cp\u003EThe refresh flow in UltimateAuth is not a single fixed operation.\u003C/p\u003E\n\u003Cp\u003E\uD83D\uDC49 It is a \u003Cstrong\u003Emode-dependent continuation strategy\u003C/strong\u003E.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022what-is-refresh\u0022\u003E\uD83E\uDDE0 What is Refresh?\u003C/h2\u003E\n\u003Cp\u003EIn traditional systems:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003ERefresh = get a new access token\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EIn UltimateAuth:\u003C/p\u003E\n\u003Cp\u003E\uD83D\uDC49 Refresh continues an existing authentication state\u003C/p\u003E\n\u003Cblockquote\u003E\n\u003Cp\u003ERefresh is not re-authentication\u003Cbr /\u003E\n\u2192 It is session continuation\u003C/p\u003E\n\u003C/blockquote\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022two-refresh-strategies\u0022\u003E\uD83D\uDD00 Two Refresh Strategies\u003C/h2\u003E\n\u003Cp\u003EUltimateAuth supports two fundamentally different refresh behaviors:\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022session-touch-stateful\u0022\u003E\uD83D\uDD39 Session Touch (Stateful)\u003C/h3\u003E\n\u003Cp\u003EUsed in \u003Cstrong\u003EPureOpaque mode\u003C/strong\u003E\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003ENo tokens involved\u003C/li\u003E\n\u003Cli\u003ENo new session created\u003C/li\u003E\n\u003Cli\u003EExisting session is extended\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cpre\u003E\u003Ccode\u003ESession \u2192 Validate \u2192 Touch \u2192 Continue\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cp\u003E\uD83D\uDC49 This updates activity without changing identity\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022token-rotation-stateless-hybrid\u0022\u003E\uD83D\uDD39 Token Rotation (Stateless / Hybrid)\u003C/h3\u003E\n\u003Cp\u003EUsed in:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Cp\u003EHybrid\u003C/p\u003E\n\u003C/li\u003E\n\u003Cli\u003E\u003Cp\u003ESemiHybrid\u003C/p\u003E\n\u003C/li\u003E\n\u003Cli\u003E\u003Cp\u003EPureJwt\u003C/p\u003E\n\u003C/li\u003E\n\u003Cli\u003E\u003Cp\u003ERefresh token is validated\u003C/p\u003E\n\u003C/li\u003E\n\u003Cli\u003E\u003Cp\u003EOld token is revoked\u003C/p\u003E\n\u003C/li\u003E\n\u003Cli\u003E\u003Cp\u003ENew tokens are issued\u003C/p\u003E\n\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cpre\u003E\u003Ccode\u003ERefreshToken \u2192 Validate \u2192 Revoke \u2192 Issue New Tokens\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cp\u003E\uD83D\uDC49 This ensures forward security\u003C/p\u003E\n\u003Cbr\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022mode-based-behavior\u0022\u003E\u2696\uFE0F Mode-Based Behavior\u003C/h2\u003E\n\u003Cp\u003ERefresh behavior is determined by the authentication mode:\u003C/p\u003E\n\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EMode\u003C/th\u003E\n\u003Cth\u003EBehavior\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EPureOpaque\u003C/td\u003E\n\u003Ctd\u003ESession Touch\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EHybrid\u003C/td\u003E\n\u003Ctd\u003ERotation \u002B Touch\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003ESemiHybrid\u003C/td\u003E\n\u003Ctd\u003ERotation\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003EPureJwt\u003C/td\u003E\n\u003Ctd\u003ERotation\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\u003Cp\u003E\uD83D\uDC49 UltimateAuth automatically selects the correct strategy.\u003C/p\u003E\n\u003Cbr\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022step-by-step-execution\u0022\u003E\uD83D\uDD04 Step-by-Step Execution\u003C/h2\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022input-resolution\u0022\u003E1\uFE0F\u20E3 Input Resolution\u003C/h3\u003E\n\u003Cp\u003EThe system resolves:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003ESessionId (if present)\u003C/li\u003E\n\u003Cli\u003ERefreshToken (if present)\u003C/li\u003E\n\u003Cli\u003EDevice context\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022mode-based-branching\u0022\u003E2\uFE0F\u20E3 Mode-Based Branching\u003C/h3\u003E\n\u003Cp\u003EThe system determines the refresh strategy:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003ESession-based \u2192 Touch\u003C/li\u003E\n\u003Cli\u003EToken-based \u2192 Rotation\u003C/li\u003E\n\u003Cli\u003EHybrid \u2192 Both\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022session-validation\u0022\u003E3\uFE0F\u20E3 Session Validation\u003C/h3\u003E\n\u003Cp\u003EIf session is involved:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003ESession is validated\u003C/li\u003E\n\u003Cli\u003EDevice binding is checked\u003C/li\u003E\n\u003Cli\u003EExpiration is evaluated\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022token-validation-if-applicable\u0022\u003E4\uFE0F\u20E3 Token Validation (if applicable)\u003C/h3\u003E\n\u003Cp\u003EIf refresh token is used:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EToken is validated\u003C/li\u003E\n\u003Cli\u003ESession and chain are verified\u003C/li\u003E\n\u003Cli\u003EDevice consistency is checked\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022security-checks\u0022\u003E5\uFE0F\u20E3 Security Checks\u003C/h3\u003E\n\u003Cp\u003EThe system enforces:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EToken reuse detection\u003C/li\u003E\n\u003Cli\u003ESession validity\u003C/li\u003E\n\u003Cli\u003EChain integrity\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003E\uD83D\uDC49 If validation fails \u2192 reauthentication required\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022execution\u0022\u003E6\uFE0F\u20E3 Execution\u003C/h3\u003E\n\u003Cp\u003EDepending on the strategy:\u003C/p\u003E\n\u003Ch4 id=\u0022session-touch\u0022\u003ESession Touch\u003C/h4\u003E\n\u003Cul\u003E\n\u003Cli\u003EUpdates \u003Ccode\u003ELastSeenAt\u003C/code\u003E\u003C/li\u003E\n\u003Cli\u003EApplies sliding expiration\u003C/li\u003E\n\u003Cli\u003ENo new tokens issued\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch4 id=\u0022token-rotation\u0022\u003EToken Rotation\u003C/h4\u003E\n\u003Cul\u003E\n\u003Cli\u003ERevokes old refresh token\u003C/li\u003E\n\u003Cli\u003EIssues new access token\u003C/li\u003E\n\u003Cli\u003EIssues new refresh token\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch4 id=\u0022hybrid-mode\u0022\u003EHybrid Mode\u003C/h4\u003E\n\u003Cul\u003E\n\u003Cli\u003EValidates session\u003C/li\u003E\n\u003Cli\u003ERotates tokens\u003C/li\u003E\n\u003Cli\u003EUpdates session activity\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022response-generation\u0022\u003E7\uFE0F\u20E3 Response Generation\u003C/h3\u003E\n\u003Cp\u003EThe response may include:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003ESessionId\u003C/li\u003E\n\u003Cli\u003EAccess token\u003C/li\u003E\n\u003Cli\u003ERefresh token\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003E\uD83D\uDC49 Output depends on mode and client\u003C/p\u003E\n\u003Cbr\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022security-model\u0022\u003E\uD83D\uDD10 Security Model\u003C/h2\u003E\n\u003Cp\u003EThe refresh flow includes strong protections:\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022token-reuse-detection\u0022\u003E\uD83D\uDD01 Token Reuse Detection\u003C/h3\u003E\n\u003Cp\u003EIf a refresh token is reused:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003EChain may be revoked\u003C/li\u003E\n\u003Cli\u003ESession may be revoked\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003E\uD83D\uDC49 This prevents replay attacks\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022session-binding\u0022\u003E\uD83D\uDD17 Session Binding\u003C/h3\u003E\n\u003Cul\u003E\n\u003Cli\u003ETokens are bound to session\u003C/li\u003E\n\u003Cli\u003ESession is bound to device\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003E\uD83D\uDC49 Prevents token misuse across devices\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022chain-integrity\u0022\u003E\uD83E\uDDEC Chain Integrity\u003C/h3\u003E\n\u003Cul\u003E\n\u003Cli\u003ERefresh operates within a chain\u003C/li\u003E\n\u003Cli\u003ECross-device usage is rejected\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cbr\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022mental-model\u0022\u003E\uD83E\uDDE0 Mental Model\u003C/h2\u003E\n\u003Cp\u003EIf you remember one thing:\u003C/p\u003E\n\u003Cp\u003E\uD83D\uDC49 Refresh = continuation\u003Cbr /\u003E\n\uD83D\uDC49 Not new authentication\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022key-takeaways\u0022\u003E\uD83D\uDCCC Key Takeaways\u003C/h2\u003E\n\u003Cul\u003E\n\u003Cli\u003ERefresh behavior depends on auth mode\u003C/li\u003E\n\u003Cli\u003EStateful systems use session touch\u003C/li\u003E\n\u003Cli\u003EStateless systems use token rotation\u003C/li\u003E\n\u003Cli\u003EHybrid systems combine both\u003C/li\u003E\n\u003Cli\u003ESecurity is enforced at every step\u003C/li\u003E\n\u003C/ul\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022next-step\u0022\u003E\u27A1\uFE0F Next Step\u003C/h2\u003E\n\u003Cp\u003EContinue to \u003Cstrong\u003ELogout Flow\u003C/strong\u003E\u003C/p\u003E\n", + "Html": "\n\u003Cp\u003ERefresh is how an existing authentication context continues without asking the user to authenticate again. In UltimateAuth, it is not synonymous with issuing a new access token: the operation depends on the active authentication mode and on whether the context is represented by a server-side session, refresh credentials, or both.\u003C/p\u003E\n\u003Cp\u003EA successful refresh preserves the authenticated identity and its continuity. It does \u003Cstrong\u003Enot\u003C/strong\u003E prove the user\u0027s credentials again, create a new login, or necessarily extend every lifetime associated with the authentication.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022the-model-continuity-not-a-second-login\u0022\u003EThe model: continuity, not a second login\u003C/h2\u003E\n\u003Cp\u003EUltimateAuth distinguishes three related operations:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Cstrong\u003EAuthentication\u003C/strong\u003E establishes a new authenticated context after the required proof is accepted.\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003ERefresh\u003C/strong\u003E attempts to continue an already established context, subject to its current validity and security policies.\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EReauthentication\u003C/strong\u003E establishes trust again when continuation is unavailable or no longer permitted.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EThis distinction matters for both security and client behavior. A refresh request can fail because a session expired, a refresh credential is invalid or consumed, the device context does not match, or the underlying chain is no longer usable. The client should treat an unsuccessful refresh as a need to authenticate again, not as an invitation to retry the same credential indefinitely.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022mode-dependent-strategies\u0022\u003EMode-dependent strategies\u003C/h2\u003E\n\u003Cp\u003EUltimateAuth implements refresh through two building blocks: \u003Cstrong\u003Esession touch\u003C/strong\u003E and \u003Cstrong\u003Erefresh-token rotation\u003C/strong\u003E. A mode selects how they are combined.\u003C/p\u003E\n\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EAuthentication mode\u003C/th\u003E\n\u003Cth\u003ERequired refresh input\u003C/th\u003E\n\u003Cth\u003EStrategy\u003C/th\u003E\n\u003Cth\u003EResult\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EPureOpaque\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003ESession ID\u003C/td\u003E\n\u003Ctd\u003EValidate session; touch when policy requires\u003C/td\u003E\n\u003Ctd\u003EContinue the existing session; no new access or refresh token\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EHybrid\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003ESession ID \u003Cstrong\u003Eand\u003C/strong\u003E refresh token\u003C/td\u003E\n\u003Ctd\u003EValidate and conditionally touch session; rotate refresh token\u003C/td\u003E\n\u003Ctd\u003EContinue session and issue replacement tokens\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003ESemiHybrid\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003ESession ID \u003Cstrong\u003Eand\u003C/strong\u003E refresh token\u003C/td\u003E\n\u003Ctd\u003EValidate session; rotate refresh token\u003C/td\u003E\n\u003Ctd\u003EIssue replacement tokens without a session touch\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EPureJwt\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003ERefresh token\u003C/td\u003E\n\u003Ctd\u003EValidate and rotate refresh token\u003C/td\u003E\n\u003Ctd\u003EIssue replacement tokens; no session touch in the flow\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\u003Cp\u003E\u003Cstrong\u003ECurrent support status:\u003C/strong\u003E \u003Ccode\u003EPureOpaque\u003C/code\u003E and \u003Ccode\u003EHybrid\u003C/code\u003E are the supported modes for the initial release. The \u003Ccode\u003ESemiHybrid\u003C/code\u003E and \u003Ccode\u003EPureJwt\u003C/code\u003E branches are present in the refresh implementation but should not be presented as completed, generally supported configurations in v0.1.0.\u003C/p\u003E\n\u003Cp\u003EThe mode is resolved from the effective authentication context on the server. Clients do not select a refresh algorithm independently.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022session-touch\u0022\u003ESession touch\u003C/h2\u003E\n\u003Cp\u003EA session touch is a controlled update to existing server-side authentication state. It does not issue a replacement credential or create a new session.\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-text\u0022\u003ESession ID\n \u2192 Validate session, chain and device context\n \u2192 Recheck active state and chain/session relationship\n \u2192 Touch if policy requires\n \u2192 Continue with the same session ID\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cp\u003EIn \u003Ccode\u003EPureOpaque\u003C/code\u003E, the refresh flow requires a session ID. The session validator checks the session against the current tenant, device context and session options. The touch service then reloads the session and chain from the store and checks that they are still active and consistent, including the chain\u0027s active session, tenant, user and chain identifiers.\u003C/p\u003E\n\u003Cp\u003ETouch behavior is governed by the effective session options:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003ETouchInterval\u003C/code\u003E avoids writing activity state on every request. If the interval has not elapsed, the operation may succeed as \u003Cstrong\u003ENoOp\u003C/strong\u003E.\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003ETouchMode\u003C/code\u003E is \u003Ccode\u003EIfNeeded\u003C/code\u003E by default; \u003Ccode\u003EForce\u003C/code\u003E requests a touch even when the normal interval has not elapsed.\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003ESlidingExpiration\u003C/code\u003E allows a touch to extend the session expiration using the configured \u003Ccode\u003ELifetime\u003C/code\u003E.\u003C/li\u003E\n\u003Cli\u003EAn absolute chain expiration remains an upper bound; sliding expiration cannot extend the session beyond it.\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003EIdleTimeout\u003C/code\u003E participates in chain-state validation. An idle or otherwise inactive chain cannot be revived merely by touching it.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EA successful \u003Cstrong\u003ENoOp\u003C/strong\u003E is not a failed refresh: the existing state was valid, but no persistence update was necessary. Likewise, a touch is not an unconditional promise to extend the session\u0027s expiry; that depends on policy and the absolute limit.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022refresh-token-rotation\u0022\u003ERefresh-token rotation\u003C/h2\u003E\n\u003Cp\u003ERotation replaces a valid refresh credential while preserving its association with the existing authentication context.\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode class=\u0022language-text\u0022\u003ERefresh token\n \u2192 Validate token, tenant, device and expected session (if supplied)\n \u2192 Resolve user, session and chain\n \u2192 Prepare replacement refresh/access tokens\n \u2192 Atomically consume old refresh token and store replacement\n \u2192 Return new credentials\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cp\u003EThe rotation service first rejects modes or configurations that do not permit refresh-token issuance (\u003Ccode\u003EPureOpaque\u003C/code\u003E or \u003Ccode\u003EIssueRefresh = false\u003C/code\u003E). It then validates the presented credential and its context. The replacement refresh token and access token are prepared before the existing token is consumed. Persistence uses the refresh-token store\u0027s execution boundary and \u003Ccode\u003ETryConsumeAsync\u003C/code\u003E, so competing requests cannot both successfully consume the same old token.\u003C/p\u003E\n\u003Cp\u003ERotation preserves the validated user, session and chain association; it is \u003Cstrong\u003Enot\u003C/strong\u003E a new authentication or a new session. Claims for the replacement access token are obtained through the configured claims provider.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022reuse-and-concurrent-requests\u0022\u003EReuse and concurrent requests\u003C/h3\u003E\n\u003Cp\u003EA consumed refresh token cannot be used again to obtain another replacement. UltimateAuth distinguishes two situations:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Cstrong\u003ELikely concurrent request:\u003C/strong\u003E if a consumed token has a recorded replacement and the second request falls within \u003Ccode\u003ERefreshTokenConcurrentRequestWindow\u003C/code\u003E, the second rotation is rejected without treating it as a confirmed replay.\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EReplay outside that window:\u003C/strong\u003E the rotation service revokes the associated refresh-token chain, or tokens associated with the session when a chain identifier is unavailable.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EThis distinction reduces destructive responses to ordinary client-side concurrency while retaining a response to suspicious reuse. The concurrency window is \u003Cstrong\u003Enot\u003C/strong\u003E a grace period in which the old token may be exchanged again: the second request still fails.\u003C/p\u003E\n\u003Cp\u003EThe rotation implementation shown here revokes refresh-token state. Do not interpret that as an unconditional guarantee that every related server-side session is also revoked; session invalidation is a separate concern.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022how-each-mode-executes\u0022\u003EHow each mode executes\u003C/h2\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022pureopaque-session-continuation\u0022\u003EPureOpaque: session continuation\u003C/h3\u003E\n\u003Cp\u003E\u003Ccode\u003EPureOpaque\u003C/code\u003E has no refresh-token rotation step. The endpoint resolves the existing session from the authentication flow context, validates it and performs a conditional touch. It returns \u003Ccode\u003ETouched\u003C/code\u003E when state was updated or \u003Ccode\u003ENoOp\u003C/code\u003E when the valid session required no update.\u003C/p\u003E\n\u003Cp\u003ENo access token or refresh token is issued. The existing session ID remains the credential representing the continued context.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022hybrid-session-and-token-continuity\u0022\u003EHybrid: session and token continuity\u003C/h3\u003E\n\u003Cp\u003E\u003Ccode\u003EHybrid\u003C/code\u003E requires \u003Cstrong\u003Eboth\u003C/strong\u003E a valid session ID and a refresh token. The flow:\u003C/p\u003E\n\u003Col\u003E\n\u003Cli\u003EValidates the session and device context.\u003C/li\u003E\n\u003Cli\u003EPerforms the session touch operation according to policy.\u003C/li\u003E\n\u003Cli\u003EValidates and rotates the refresh token, requiring it to match the expected session.\u003C/li\u003E\n\u003Cli\u003EReturns the existing session ID together with replacement access and refresh tokens.\u003C/li\u003E\n\u003C/ol\u003E\n\u003Cp\u003EThe order is important: \u003Cstrong\u003Esession touch happens before token rotation\u003C/strong\u003E in the current implementation. These operations are not presented as one cross-store transaction. If rotation subsequently fails, the refresh response fails, although a preceding session touch may already have been persisted. This should not be described as an all-or-nothing operation.\u003C/p\u003E\n\u003Ch3 class=\u0022mud-scrollspy-section\u0022 id=\u0022semihybrid-and-purejwt-implementation-branches\u0022\u003ESemiHybrid and PureJwt: implementation branches\u003C/h3\u003E\n\u003Cp\u003EThe current service includes branches for two additional modes:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003ESemiHybrid\u003C/code\u003E requires a session ID and refresh token, validates the session and rotates the token, but does not touch the session.\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003EPureJwt\u003C/code\u003E uses the refresh token for rotation without a session touch step in \u003Ccode\u003ERefreshFlowService\u003C/code\u003E.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EThese describe the existing code paths, \u003Cstrong\u003Enot a promise of v0.1.0 production support\u003C/strong\u003E. Configuration validation and supported-mode documentation remain authoritative for which modes applications can enable.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022request-resolution-and-response-delivery\u0022\u003ERequest resolution and response delivery\u003C/h2\u003E\n\u003Cp\u003EThe refresh endpoint uses the server\u0027s \u003Ccode\u003EAuthFlowContext\u003C/code\u003E. It obtains the session ID from \u003Ccode\u003Eflow.Session\u003C/code\u003E, the device from \u003Ccode\u003Eflow.Device\u003C/code\u003E, and the refresh token through \u003Ccode\u003ERefreshTokenResolver\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EFor refresh-token input, the resolver checks:\u003C/p\u003E\n\u003Col\u003E\n\u003Cli\u003EThe explicit \u003Ccode\u003EX-Refresh-Token\u003C/code\u003E header, if present.\u003C/li\u003E\n\u003Cli\u003EThe configured refresh cookie, when cookie delivery is active.\u003C/li\u003E\n\u003Cli\u003EThe configured refresh header, when header delivery is active.\u003C/li\u003E\n\u003C/ol\u003E\n\u003Cp\u003EThe explicit header takes precedence. Header values may be supplied with a \u003Ccode\u003EBearer \u003C/code\u003E prefix, which the resolver strips.\u003C/p\u003E\n\u003Cp\u003EOn success, the endpoint chooses a \u003Cstrong\u003Eprimary credential\u003C/strong\u003E according to the refresh response policy, rather than automatically writing every credential returned by the flow. The refresh token is written separately when permitted by the response policy and when a replacement exists. Actual cookie/header placement is determined by the effective response configuration and client profile.\u003C/p\u003E\n\u003Cp\u003EThe HTTP endpoint returns \u003Cstrong\u003E\u003Ccode\u003E204 No Content\u003C/code\u003E\u003C/strong\u003E on successful refresh and \u003Cstrong\u003E\u003Ccode\u003E401 Unauthorized\u003C/code\u003E\u003C/strong\u003E when continuation fails. Clients should obtain credentials from the configured response delivery mechanism rather than expecting a JSON token payload. When \u003Ccode\u003EDiagnostics.EnableRefreshDetails\u003C/code\u003E is enabled, the endpoint also writes the refresh outcome through its diagnostic response writer.\u003C/p\u003E\n\u003Cblockquote\u003E\n\u003Cp\u003EResponse delivery customization is not fully independent in v0.1.0: mode templates and client-profile adaptation constrain the effective behavior. Do not assume every configured credential-delivery override is honored.\u003C/p\u003E\n\u003C/blockquote\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022outcomes-and-client-expectations\u0022\u003EOutcomes and client expectations\u003C/h2\u003E\n\u003Ctable\u003E\n\u003Cthead\u003E\n\u003Ctr\u003E\n\u003Cth\u003EOutcome\u003C/th\u003E\n\u003Cth\u003EMeaning\u003C/th\u003E\n\u003Cth\u003EClient interpretation\u003C/th\u003E\n\u003C/tr\u003E\n\u003C/thead\u003E\n\u003Ctbody\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003ENoOp\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EExisting session is valid; no touch was necessary\u003C/td\u003E\n\u003Ctd\u003EContinue normally\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003ETouched\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EExisting session activity was updated\u003C/td\u003E\n\u003Ctd\u003EContinue normally\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003ERotated\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003ERefresh token was consumed and replacement credentials issued\u003C/td\u003E\n\u003Ctd\u003EReplace stored credentials with the new values\u003C/td\u003E\n\u003C/tr\u003E\n\u003Ctr\u003E\n\u003Ctd\u003E\u003Ccode\u003EReauthRequired\u003C/code\u003E\u003C/td\u003E\n\u003Ctd\u003EThe flow could not safely continue\u003C/td\u003E\n\u003Ctd\u003EStop using the failed refresh credential and require authentication\u003C/td\u003E\n\u003C/tr\u003E\n\u003C/tbody\u003E\n\u003C/table\u003E\n\u003Cp\u003E\u003Ccode\u003ERefreshFlowResult\u003C/code\u003E also recognizes \u003Ccode\u003ESuccess\u003C/code\u003E as a successful outcome, although the mode-specific branches described above return \u003Ccode\u003ENoOp\u003C/code\u003E, \u003Ccode\u003ETouched\u003C/code\u003E, \u003Ccode\u003ERotated\u003C/code\u003E or \u003Ccode\u003EReauthRequired\u003C/code\u003E.\u003C/p\u003E\n\u003Cp\u003EClients should serialize refresh attempts where practical. Parallel refresh requests using the same token do not produce multiple valid replacements, even when they fall within the concurrency window.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022security-boundaries\u0022\u003ESecurity boundaries\u003C/h2\u003E\n\u003Cp\u003ERefresh continues existing trust only while the relevant state remains valid:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Cstrong\u003ESession and chain checks:\u003C/strong\u003E session-based paths validate active state, tenant, user, chain and session relationships.\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EDevice context:\u003C/strong\u003E session and refresh-token validation receive the current device context; mismatches can prevent continuation.\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003ESingle-use refresh tokens:\u003C/strong\u003E successful rotation consumes the old credential and persists a replacement.\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EReplay response:\u003C/strong\u003E suspicious reuse can revoke refresh-token state associated with the chain or session.\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EExpiration:\u003C/strong\u003E idle, session, chain and refresh-token validity rules can end continuation. Refresh does not bypass those limits.\u003C/li\u003E\n\u003Cli\u003E\u003Cstrong\u003EIssuance policy:\u003C/strong\u003E \u003Ccode\u003EIssueRefresh = false\u003C/code\u003E prevents rotation before the old token is consumed.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003EThese controls complement one another. A refresh token should be treated as a sensitive credential, not as a harmless request to generate another access token.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022summary\u0022\u003ESummary\u003C/h2\u003E\n\u003Cp\u003EThe useful distinction is not simply \u003Cem\u003Estateful versus stateless\u003C/em\u003E. It is \u003Cstrong\u003Ewhat must remain valid for authentication to continue\u003C/strong\u003E:\u003C/p\u003E\n\u003Cul\u003E\n\u003Cli\u003E\u003Ccode\u003EPureOpaque\u003C/code\u003E continues an existing server-side session, with conditional activity updates.\u003C/li\u003E\n\u003Cli\u003E\u003Ccode\u003EHybrid\u003C/code\u003E requires both session validity and successful refresh-token rotation.\u003C/li\u003E\n\u003Cli\u003EOther rotation branches exist, but are not part of the completed v0.1.0 supported-mode set.\u003C/li\u003E\n\u003C/ul\u003E\n\u003Cp\u003ERefresh does not authenticate a user again. It extends the usefulness of an already established authentication context only within the boundaries of the selected mode and configured security policies.\u003C/p\u003E\n\u003Ch2 class=\u0022mud-scrollspy-section\u0022 id=\u0022next-step\u0022\u003ENext step\u003C/h2\u003E\n\u003Cp\u003EContinue to \u003Ca href=\u0022./logout-flow\u0022\u003ELogout Flow\u003C/a\u003E.\u003C/p\u003E\n", "Headings": [ { - "Id": "what-is-refresh", - "Text": "\uD83E\uDDE0 What is Refresh?", + "Id": "the-model-continuity-not-a-second-login", + "Text": "The model: continuity, not a second login", "Level": 0 }, { - "Id": "two-refresh-strategies", - "Text": "\uD83D\uDD00 Two Refresh Strategies", + "Id": "mode-dependent-strategies", + "Text": "Mode-dependent strategies", "Level": 0 }, { - "Id": "session-touch-stateful", - "Text": "\uD83D\uDD39 Session Touch (Stateful)", - "Level": 1 - }, - { - "Id": "token-rotation-stateless-hybrid", - "Text": "\uD83D\uDD39 Token Rotation (Stateless / Hybrid)", - "Level": 1 - }, - { - "Id": "mode-based-behavior", - "Text": "\u2696\uFE0F Mode-Based Behavior", + "Id": "session-touch", + "Text": "Session touch", "Level": 0 }, { - "Id": "step-by-step-execution", - "Text": "\uD83D\uDD04 Step-by-Step Execution", + "Id": "refresh-token-rotation", + "Text": "Refresh-token rotation", "Level": 0 }, { - "Id": "input-resolution", - "Text": "1\uFE0F\u20E3 Input Resolution", - "Level": 1 - }, - { - "Id": "mode-based-branching", - "Text": "2\uFE0F\u20E3 Mode-Based Branching", - "Level": 1 - }, - { - "Id": "session-validation", - "Text": "3\uFE0F\u20E3 Session Validation", + "Id": "reuse-and-concurrent-requests", + "Text": "Reuse and concurrent requests", "Level": 1 }, { - "Id": "token-validation-if-applicable", - "Text": "4\uFE0F\u20E3 Token Validation (if applicable)", - "Level": 1 + "Id": "how-each-mode-executes", + "Text": "How each mode executes", + "Level": 0 }, { - "Id": "security-checks", - "Text": "5\uFE0F\u20E3 Security Checks", + "Id": "pureopaque-session-continuation", + "Text": "PureOpaque: session continuation", "Level": 1 }, { - "Id": "execution", - "Text": "6\uFE0F\u20E3 Execution", + "Id": "hybrid-session-and-token-continuity", + "Text": "Hybrid: session and token continuity", "Level": 1 }, { - "Id": "response-generation", - "Text": "7\uFE0F\u20E3 Response Generation", + "Id": "semihybrid-and-purejwt-implementation-branches", + "Text": "SemiHybrid and PureJwt: implementation branches", "Level": 1 }, { - "Id": "security-model", - "Text": "\uD83D\uDD10 Security Model", + "Id": "request-resolution-and-response-delivery", + "Text": "Request resolution and response delivery", "Level": 0 }, { - "Id": "token-reuse-detection", - "Text": "\uD83D\uDD01 Token Reuse Detection", - "Level": 1 - }, - { - "Id": "session-binding", - "Text": "\uD83D\uDD17 Session Binding", - "Level": 1 - }, - { - "Id": "chain-integrity", - "Text": "\uD83E\uDDEC Chain Integrity", - "Level": 1 + "Id": "outcomes-and-client-expectations", + "Text": "Outcomes and client expectations", + "Level": 0 }, { - "Id": "mental-model", - "Text": "\uD83E\uDDE0 Mental Model", + "Id": "security-boundaries", + "Text": "Security boundaries", "Level": 0 }, { - "Id": "key-takeaways", - "Text": "\uD83D\uDCCC Key Takeaways", + "Id": "summary", + "Text": "Summary", "Level": 0 }, { "Id": "next-step", - "Text": "\u27A1\uFE0F Next Step", + "Text": "Next step", "Level": 0 } ]