57 lines
1.8 KiB
TypeScript
57 lines
1.8 KiB
TypeScript
/**
|
|
* Native session bridge: reads the session from the OS secure store, applies it
|
|
* to the in-memory auth store, and refreshes against Authentik when needed.
|
|
* Mirrors `session-sync.ts` (the web/httpOnly-cookie path) for the Tauri shells.
|
|
*/
|
|
import { useAuthStore } from "@/lib/api/auth-store"
|
|
import { useSessionGuardStore } from "@/lib/auth/session-guard-store"
|
|
import type { PlatformUser } from "@/lib/auth/jwt-claims"
|
|
import { readSession, type NativeSession } from "@/lib/native/secure-store"
|
|
import { nativeRefresh } from "@/lib/auth/native-auth"
|
|
|
|
const REFRESH_LEAD_MS = 60_000
|
|
|
|
function applyNativeSession(session: NativeSession | null): boolean {
|
|
if (session?.accessToken && session.expiresAt) {
|
|
useAuthStore
|
|
.getState()
|
|
.login(
|
|
session.accessToken,
|
|
session.refreshToken ?? "",
|
|
session.expiresAt,
|
|
(session.user as PlatformUser | null) ?? null
|
|
)
|
|
useSessionGuardStore.getState().clear()
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
/** Hydrate the store from the secure store (used on boot). */
|
|
export async function loadNativeSession(): Promise<boolean> {
|
|
return applyNativeSession(await readSession())
|
|
}
|
|
|
|
/** Return a valid bearer token, refreshing first if it's about to expire. */
|
|
export async function ensureNativeAccessToken(): Promise<string | null> {
|
|
let session = await readSession()
|
|
if (!session) {
|
|
useAuthStore.getState().logout()
|
|
return null
|
|
}
|
|
|
|
const aboutToExpire = Date.now() >= session.expiresAt - REFRESH_LEAD_MS
|
|
if (aboutToExpire && session.refreshToken) {
|
|
const refreshed = await nativeRefresh()
|
|
if (refreshed) session = refreshed
|
|
}
|
|
|
|
if (Date.now() >= session.expiresAt && !session.refreshToken) {
|
|
useAuthStore.getState().logout()
|
|
return null
|
|
}
|
|
|
|
applyNativeSession(session)
|
|
return useAuthStore.getState().accessToken
|
|
}
|