T
TanStack7mo ago
wise-white

Tanstack auth context not working?

Followed this documentation https://tanstack.com/router/v1/docs/framework/react/guide/authenticated-routes#authentication-using-react-contexthooks And I'm getting this error. I'm having a hard time getting any leads. If anyone else can help me out lmk! Thanks!
Uncaught Error: useAuth must be used within an AuthProvider
Uncaught Error: useAuth must be used within an AuthProvider
My main.tsx
import 'mapbox-gl/dist/mapbox-gl.css'
import './styles/old-tailwind.css'
import './styles/index.css'

import { createRouter, RouterProvider } from '@tanstack/react-router'
import figlet from 'figlet'
import { StrictMode } from 'react'
import ReactDOM from 'react-dom/client'

import standard from '@/assets/figlet/standard'
import { ThemeProvider } from '@/context/theme-provider'

import { ErrorComponent } from './components/error'
import { AuthProvider, useAuth } from './context/auth'
import { routeTree } from './routeTree.gen'

const router = createRouter({
routeTree,
context: {
auth: undefined!, // This will be set after we wrap the app in an AuthProvider
},
})

declare module '@tanstack/react-router' {
interface Register {
router: typeof router
}
}

function App() {
return (
<AuthProvider>
<InnerApp />
</AuthProvider>
)
}

/** Inner app inserts auth into the context */
function InnerApp() {
const auth = useAuth()
return (
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
<RouterProvider
router={router}
context={{ auth }}
defaultErrorComponent={() => (
<ErrorComponent
error={{
displayable_message: 'An unknown error occurred',
detailed_error: 'An unknown error occurred',
}}
/>
)}
/>
</ThemeProvider>
)
}

const rootElement = document.getElementById('app')!
if (!rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement)
root.render(
<StrictMode>
<App />
</StrictMode>,
)
}
import 'mapbox-gl/dist/mapbox-gl.css'
import './styles/old-tailwind.css'
import './styles/index.css'

import { createRouter, RouterProvider } from '@tanstack/react-router'
import figlet from 'figlet'
import { StrictMode } from 'react'
import ReactDOM from 'react-dom/client'

import standard from '@/assets/figlet/standard'
import { ThemeProvider } from '@/context/theme-provider'

import { ErrorComponent } from './components/error'
import { AuthProvider, useAuth } from './context/auth'
import { routeTree } from './routeTree.gen'

const router = createRouter({
routeTree,
context: {
auth: undefined!, // This will be set after we wrap the app in an AuthProvider
},
})

declare module '@tanstack/react-router' {
interface Register {
router: typeof router
}
}

function App() {
return (
<AuthProvider>
<InnerApp />
</AuthProvider>
)
}

/** Inner app inserts auth into the context */
function InnerApp() {
const auth = useAuth()
return (
<ThemeProvider defaultTheme="dark" storageKey="vite-ui-theme">
<RouterProvider
router={router}
context={{ auth }}
defaultErrorComponent={() => (
<ErrorComponent
error={{
displayable_message: 'An unknown error occurred',
detailed_error: 'An unknown error occurred',
}}
/>
)}
/>
</ThemeProvider>
)
}

const rootElement = document.getElementById('app')!
if (!rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement)
root.render(
<StrictMode>
<App />
</StrictMode>,
)
}
Authenticated Routes | TanStack Router React Docs
Authentication is an extremely common requirement for web applications. In this guide, we'll walk through how to use TanStack Router to build protected routes, and how to redirect users to login if th...
2 Replies
wise-white
wise-whiteOP7mo ago
My auth context
import * as React from 'react'
import { z } from 'zod'

import { UserSchema } from '@/api/auth/auth'
import useAuthVerify from '@/api/auth/useAuthVerify'
import { isAgilityRole } from '@/lib/utils'

export interface AuthContext {
isAuthenticated: boolean
setUser: React.Dispatch<
React.SetStateAction<z.infer<typeof UserSchema> | null>
>
user: z.infer<typeof UserSchema> | null
isLoading: boolean
error?: ApiError
logout: () => void
mutate: ReturnType<typeof useAuthVerify>['mutate']
setDemoMode: (role: z.infer<typeof UserSchema>['role'] | undefined) => void
demoMode: {
role: z.infer<typeof UserSchema>['role'] | undefined
previousRole?: z.infer<typeof UserSchema>['role']
}
}

const AuthContext = React.createContext<AuthContext>(null!)

export function AuthProvider({ children }: { children: React.ReactNode }) {
const [demoModeRole, setDemoModeRole] =
React.useState<z.infer<typeof UserSchema>['role']>()
const {
data: auth,
error,
isLoading: isLoadingAuth,
isValidating,
mutate,
} = useAuthVerify()

const [user, setUser] = React.useState<z.infer<typeof UserSchema> | null>(
null,
)
const isAuthenticated = !!user
const isLoading = (!auth && !error) || (isLoadingAuth && !isValidating)

React.useEffect(() => {
if (isLoading) return

if (error) {
setUser(null)
}

if (auth) {
if (demoModeRole) {
setUser({
...auth,
role: demoModeRole,
})
} else {
setUser(auth)
}
}
}, [auth, error, isLoading, demoModeRole])

function logout() {
localStorage.removeItem('jwt')
setUser(null)
window.location.replace('/login')
}

function setDemoMode(role: z.infer<typeof UserSchema>['role'] | undefined) {
const isAgility = isAgilityRole(auth?.role)
if (!isAgility) return
setDemoModeRole(role)
}

return (
<AuthContext.Provider
value={{
isAuthenticated,
user,
setUser,
isLoading,
logout,
mutate,
setDemoMode,
demoMode: {
role: demoModeRole,
previousRole: auth?.role,
},
}}
>
{children}
</AuthContext.Provider>
)
}

export function useAuth() {
const context = React.useContext(AuthContext)
if (!context) {
throw new Error('useAuth must be used within an AuthProvider')
}
return context
}
import * as React from 'react'
import { z } from 'zod'

import { UserSchema } from '@/api/auth/auth'
import useAuthVerify from '@/api/auth/useAuthVerify'
import { isAgilityRole } from '@/lib/utils'

export interface AuthContext {
isAuthenticated: boolean
setUser: React.Dispatch<
React.SetStateAction<z.infer<typeof UserSchema> | null>
>
user: z.infer<typeof UserSchema> | null
isLoading: boolean
error?: ApiError
logout: () => void
mutate: ReturnType<typeof useAuthVerify>['mutate']
setDemoMode: (role: z.infer<typeof UserSchema>['role'] | undefined) => void
demoMode: {
role: z.infer<typeof UserSchema>['role'] | undefined
previousRole?: z.infer<typeof UserSchema>['role']
}
}

const AuthContext = React.createContext<AuthContext>(null!)

export function AuthProvider({ children }: { children: React.ReactNode }) {
const [demoModeRole, setDemoModeRole] =
React.useState<z.infer<typeof UserSchema>['role']>()
const {
data: auth,
error,
isLoading: isLoadingAuth,
isValidating,
mutate,
} = useAuthVerify()

const [user, setUser] = React.useState<z.infer<typeof UserSchema> | null>(
null,
)
const isAuthenticated = !!user
const isLoading = (!auth && !error) || (isLoadingAuth && !isValidating)

React.useEffect(() => {
if (isLoading) return

if (error) {
setUser(null)
}

if (auth) {
if (demoModeRole) {
setUser({
...auth,
role: demoModeRole,
})
} else {
setUser(auth)
}
}
}, [auth, error, isLoading, demoModeRole])

function logout() {
localStorage.removeItem('jwt')
setUser(null)
window.location.replace('/login')
}

function setDemoMode(role: z.infer<typeof UserSchema>['role'] | undefined) {
const isAgility = isAgilityRole(auth?.role)
if (!isAgility) return
setDemoModeRole(role)
}

return (
<AuthContext.Provider
value={{
isAuthenticated,
user,
setUser,
isLoading,
logout,
mutate,
setDemoMode,
demoMode: {
role: demoModeRole,
previousRole: auth?.role,
},
}}
>
{children}
</AuthContext.Provider>
)
}

export function useAuth() {
const context = React.useContext(AuthContext)
if (!context) {
throw new Error('useAuth must be used within an AuthProvider')
}
return context
}
rising-crimson
rising-crimson7mo ago
does useAuthVerify uses useAuth internally? In that case it would have the context as null

Did you find this page helpful?