tanstack-auth-session
v0.1.3
Published
Typed, request-scoped auth session for SSR React apps
Readme
tanstack-auth-session
Typed, request-scoped auth session for modern React SSR applications
tanstack-auth-session provides a real session layer for React applications that use
SSR, loaders, middleware, or server components.
It is framework-agnostic and works consistently across TanStack Router, Remix, Next.js, Express/Fastify, and plain Fetch-based SSR.
Why this library exists
In modern React apps:
- Cookies are not sessions
- JWT is not authorization
- SSR has no shared user state
- Global variables break in Node.js
- Auth logic is duplicated everywhere
Most projects re-implement:
- cookie parsing
- token verification
- user validation
- role & permission checks
- SSR → client hydration
This leads to bugs, security issues, and untyped user objects.
What tanstack-auth-session gives you
- Secure cookie-based authentication
- Request-scoped session (no globals, no memory leaks)
- Runtime validation with Zod
- Fully typed
session.user - Permissions with
session.can() - Request-level cache
- SSR → Client hydration
- Framework-agnostic core
Installation
npm install tanstack-auth-sessionPeer dependencies
You must provide these in your application:
react >= 18@tanstack/react-router >= 1(only if you use the adapter)
Core Concept
A Session:
- is created per request
- lives only during that request
- is cached per request
- is safe in concurrent SSR
- works on server and client
Basic Setup (Framework-agnostic)
import { createAuthSession } from 'tanstack-auth-session'
import { z } from 'zod'
export const auth = createAuthSession({
cookieName: 'auth',
schema: z.object({
id: z.string(),
role: z.enum(['user', 'admin']),
}),
verify: async (token) => {
if (token === 'admin-token') {
return { id: '1', role: 'admin' }
}
return null
},
permissions: {
admin: ['users.read', 'users.write'],
user: ['profile.read'],
},
})Session API
session.isAuthenticated()
session.isGuest()
session.user // typed user or null
session.can('users.write')Request-level cache
Calling fromRequest multiple times during the same request
will not re-verify the token or re-fetch the user.
const s1 = await auth.fromRequest(request)
const s2 = await auth.fromRequest(request)
// same instanceUsage with TanStack Router (SSR)
import { withAuthGuard } from 'tanstack-auth-session/adapters/tanstack-router'
export const beforeLoad = withAuthGuard(auth)beforeLoad: async ({ context }) => {
const session = await auth.fromRequest(context.request)
if (session.isGuest()) {
throw redirect({ to: '/login' })
}
return { session }
}Usage with Remix
export const loader = async ({ request }) => {
const session = await auth.fromRequest(request)
if (session.isGuest()) {
throw redirect('/login')
}
return json({ user: session.user })
}Usage with Next.js (App Router)
import { cookies } from 'next/headers'
export async function getSession() {
const cookieStore = cookies()
const request = new Request('http://localhost', {
headers: {
cookie: cookieStore.toString(),
},
})
return auth.fromRequest(request)
}Usage with Express / Fastify
app.use(async (req, res, next) => {
const request = new Request('http://localhost', {
headers: {
cookie: req.headers.cookie ?? '',
},
})
req.session = await auth.fromRequest(request)
next()
})Client-side usage (React)
Provider
import { AuthSessionProvider } from 'tanstack-auth-session'
<AuthSessionProvider session={sessionFromSSR}>
<App />
</AuthSessionProvider>Hook
import { useAuthSession } from 'tanstack-auth-session'
const session = useAuthSession()
if (session.can('users.write')) {
return <AdminPanel />
}Security notes
- Use
httpOnlycookies - Always validate user with Zod
- Never store session globally
- Rotate tokens on logout (recommended)
Who is this for
- Senior / Staff Frontend Engineers
- Fullstack React developers
- SSR applications
- SaaS & B2B products
- Teams that care about architecture
License
MIT
