fix(auth): restore cross-tab permissions and bind retries to session identity
This commit is contained in:
+21
-1
@@ -19,9 +19,29 @@ export function getRefreshToken() {
|
||||
return localStorage.getItem(REFRESH_TOKEN_KEY) || sessionStorage.getItem(REFRESH_TOKEN_KEY) || ''
|
||||
}
|
||||
|
||||
// Only binds a retry to its original identity; never grants permissions. Expired
|
||||
// access tokens remain readable here because they are the normal refresh trigger.
|
||||
export function accessTokenIdentity(token: string): string | null {
|
||||
try {
|
||||
const encoded = token.split('.')[1]
|
||||
if (!encoded) return null
|
||||
const normalized = encoded.replace(/-/g, '+').replace(/_/g, '/')
|
||||
const bytes = Uint8Array.from(atob(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, '=')), character => character.charCodeAt(0))
|
||||
const value = JSON.parse(new TextDecoder().decode(bytes))
|
||||
if (!value?.user_id || !value.tenant_id || !value.membership_id || value.app_code !== 'MERCHANT') return null
|
||||
return JSON.stringify([value.user_id, value.tenant_id, value.membership_id, value.operator_tenant_id, value.app_code, value.client_type].map(item => item == null ? null : String(item)))
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export function persistTokenPair(tokens: TokenPair) {
|
||||
clearSessionTokens()
|
||||
// Replace the pair without publishing a transient logout to other tabs.
|
||||
sessionStorage.removeItem(ACCESS_TOKEN_KEY)
|
||||
sessionStorage.removeItem(REFRESH_TOKEN_KEY)
|
||||
sessionStorage.removeItem('cc-client-token')
|
||||
localStorage.removeItem('cc-client-token')
|
||||
localStorage.setItem(ACCESS_TOKEN_KEY, tokens.accessToken)
|
||||
localStorage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user