Middleware
gau provides composable middleware helpers for framework integrations. Use what you need.
Auth middleware
Section titled “Auth middleware”The base middleware attaches two methods to your request context:
getSession()- Returns client-safe session data.getServerSession()- Returns the full session including OAuth tokens.
SvelteKitAuth returns a handle hook that sets up locals.getSession():
export { handle } from './routes/api/auth/[...gau]/+server'Now you can use locals.getSession() in load functions, endpoints, and remote functions.
Use authMiddleware to attach locals.getSession. The first argument controls preloading:
import { authMiddleware } from '@rttnd/gau/solidstart'import { createMiddleware } from '@solidjs/start/middleware'import { auth } from './server/auth'
export default createMiddleware({ onRequest: [ authMiddleware(true, auth), ],})Options for the first argument:
true- Preload session on all routesfalse- Lazy load (resolve on firstgetSession()call)['/dashboard', '/settings']- Preload only on specific paths
getSession vs getServerSession
Section titled “getSession vs getServerSession”Use getSession() for data that will be serialized to the browser:
const session = await locals.getSession()return { session }Use getServerSession() only on the server, like when you need OAuth tokens:
const { accounts } = await locals.getServerSession()const githubAccount = accounts?.find(a => a.provider === 'github')
if (githubAccount?.accessToken) { const res = await fetch('https://api.github.com/user/repos', { headers: { Authorization: `Bearer ${githubAccount.accessToken}` } })}Eager vs Lazy Loading
Section titled “Eager vs Lazy Loading”SvelteKit is lazy by default.
The pathsToPreLoad parameter controls when the session is validated:
Eager (preload): Session is validated immediately during middleware, before your route runs.
// Session already resolved when getSession() is calledconst session = await event.locals.getSession() // instant, cachedLazy: Session validation is deferred until getSession() is first called.
// Validation happens here, on first callconst session = await event.locals.getSession()// Subsequent calls return the cached resultconst again = await event.locals.getSession() // instant, same promiseWhen to use each:
| Scenario | Recommendation |
|---|---|
Protected routes (/dashboard, /settings) | Eager - you’ll need the session anyway |
Public routes (/, /about, /pricing) | Lazy - skip validation if page never checks auth |
| API routes that always check auth | Eager - avoid latency in the handler |
Refresh middleware
Section titled “Refresh middleware”The Refresh middleware adds automatic session refresh:
- Reads the token from Cookie first, then Authorization: Bearer
- Refreshes if past the threshold, or every request
- Responds appropriately:
- Cookie:
Set-Cookieheader - Bearer:
X-Refreshed-Tokenheader (for Tauri/mobile)
- Cookie:
import { sequence } from '@sveltejs/kit/hooks'import { handle as authHandle } from './routes/api/auth/[...gau]/+server'import { createRefreshHandle } from '@rttnd/gau/sveltekit'import { auth } from '$lib/server/auth'
export const handle = sequence( authHandle, createRefreshHandle(auth, { threshold: 0.5 }),)import { authMiddleware, refreshMiddleware } from '@rttnd/gau/solidstart'import { createMiddleware } from '@solidjs/start/middleware'import { auth } from './server/auth'
export default createMiddleware({ onRequest: [ authMiddleware(true, auth), refreshMiddleware(auth, { threshold: 0.5 }), ],})Options:
threshold- Only refresh if past this fraction of TTL (0-1). Example:0.5= refresh after 50% of session lifetime.ttl- Override the TTL for the new token.
Token-based clients
Section titled “Token-based clients”If your app uses bearer tokens instead of cookies, the server middleware sends refreshed tokens via the X-Refreshed-Token header. Use the fetch method from useAuth() to handle this automatically.
See the Integrations page for details.