53 lines
1.7 KiB
TypeScript
53 lines
1.7 KiB
TypeScript
import { useMemo, useState } from 'react'
|
|
import type { PropsWithChildren } from 'react'
|
|
import { clearAuthSession, getAuthSession, isAccessTokenStale, setAuthSession } from '../lib/auth-storage'
|
|
import type { AuthSession } from '../lib/auth-storage'
|
|
import { loginCenter, logoutCenter, refreshCenter } from '../lib/center-auth-client'
|
|
import { AuthContext } from './auth-context'
|
|
import type { AuthContextValue } from './auth-context'
|
|
|
|
export function AuthProvider({ children }: PropsWithChildren) {
|
|
const [session, setSession] = useState<AuthSession | null>(getAuthSession())
|
|
|
|
const value = useMemo<AuthContextValue>(
|
|
() => ({
|
|
session,
|
|
isAuthed: !!session,
|
|
login: async (email: string, password: string) => {
|
|
const next = await loginCenter({ email, password })
|
|
setAuthSession(next)
|
|
setSession(next)
|
|
},
|
|
logout: async () => {
|
|
if (session?.refreshToken) {
|
|
try {
|
|
await logoutCenter(session.refreshToken)
|
|
} catch {
|
|
// noop
|
|
}
|
|
}
|
|
clearAuthSession()
|
|
setSession(null)
|
|
},
|
|
ensureFreshToken: async () => {
|
|
if (!session) return null
|
|
if (!isAccessTokenStale(session.accessToken)) return session.accessToken
|
|
|
|
const refreshed = await refreshCenter(session.refreshToken)
|
|
const next: AuthSession = {
|
|
...session,
|
|
accessToken: refreshed.accessToken,
|
|
refreshToken: refreshed.refreshToken,
|
|
tokenType: refreshed.tokenType,
|
|
}
|
|
setAuthSession(next)
|
|
setSession(next)
|
|
return next.accessToken
|
|
},
|
|
}),
|
|
[session],
|
|
)
|
|
|
|
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
|
|
}
|