| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- 'use client'
- import type { AuthError, Session } from '@supabase/supabase-js'
- import {
- createContext,
- PropsWithChildren,
- useCallback,
- useContext,
- useEffect,
- useMemo,
- useState,
- } from 'react'
- import { clearLocalStorage } from './constants/local-storage'
- import { gotrueClient, type User } from './gotrue'
- export type { User }
- const DEFAULT_SESSION: any = {
- access_token: undefined,
- expires_at: 0,
- expires_in: 0,
- refresh_token: '',
- token_type: '',
- user: {
- aud: '',
- app_metadata: {},
- confirmed_at: '',
- created_at: '',
- email: '',
- email_confirmed_at: '',
- id: '',
- identities: [],
- last_signed_in_at: '',
- phone: '',
- role: '',
- updated_at: '',
- user_metadata: {},
- },
- } as unknown as Session
- /* Auth Context */
- type AuthState =
- | {
- session: Session | null
- error: AuthError | null
- isLoading: false
- }
- | {
- session: null
- error: AuthError | null
- isLoading: true
- }
- export type AuthContext = { refreshSession: () => Promise<Session | null> } & AuthState
- export const AuthContext = createContext<AuthContext>({
- session: null,
- error: null,
- isLoading: true,
- refreshSession: () => Promise.resolve(null),
- })
- export type AuthProviderProps = {
- alwaysLoggedIn?: boolean
- }
- export const AuthProvider = ({
- alwaysLoggedIn,
- children,
- }: PropsWithChildren<AuthProviderProps>) => {
- const [state, setState] = useState<AuthState>({ session: null, error: null, isLoading: true })
- useEffect(() => {
- let mounted = true
- gotrueClient.initialize().then(({ error }) => {
- if (mounted && error !== null) {
- setState((prev) => ({ ...prev, error }))
- }
- })
- return () => {
- mounted = false
- }
- }, [])
- // Keep the session in sync
- useEffect(() => {
- const {
- data: { subscription },
- } = gotrueClient.onAuthStateChange((_event, session) => {
- setState((prev) => ({
- session,
- // If there is a session, we clear the error
- error: session !== null ? null : prev.error,
- isLoading: false,
- }))
- })
- return subscription.unsubscribe
- }, [])
- // Helper method to refresh the session.
- // For example after a user updates their profile
- const refreshSession = useCallback(async () => {
- const {
- data: { session },
- } = await gotrueClient.refreshSession()
- return session
- }, [])
- const value = useMemo(() => {
- if (alwaysLoggedIn) {
- return { session: DEFAULT_SESSION, error: null, isLoading: false, refreshSession } as const
- } else {
- return { ...state, refreshSession } as const
- }
- }, [state, refreshSession])
- return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
- }
- /* Auth Utils */
- export const useAuth = () => useContext(AuthContext)
- export const useSession = () => useAuth().session
- export const useUser = () => useSession()?.user ?? null
- export const useIsUserLoading = () => useAuth().isLoading
- export const useIsLoggedIn = () => {
- const user = useUser()
- return user !== null
- }
- export const useAuthError = () => useAuth().error
- export const useIsMFAEnabled = () => {
- const user = useUser()
- return user !== null && user.factors && user.factors.length > 0
- }
- export const signOut = async () => await gotrueClient.signOut()
- export const logOut = async () => {
- await signOut()
- clearLocalStorage()
- }
- gotrueClient.onAuthStateChange((_event, _session) => {})
- /**
- * Gets a current access token.
- *
- * Calls getSession, which will refresh the token if needed.
- */
- export async function getAccessToken() {
- // ignore if server-side
- if (typeof window === 'undefined') return undefined
- const {
- data: { session },
- error,
- } = await gotrueClient.getSession()
- if (error) {
- throw error
- }
- return session?.access_token
- }
|