Authentication
Complete guide to authentication in NotebookLLM using Supabase Auth with OAuth and session management.
Overview
NotebookLLM uses Supabase Auth for user authentication. The system supports email/password authentication and OAuth providers (Google, GitHub). JWT tokens are used for API authorization.
Authentication Flow
How It Works
- User logs in via Supabase Auth (email/password or OAuth)
- Supabase returns JWT access and refresh tokens
- Frontend stores tokens via Supabase client
- API client includes JWT in Authorization header
- Backend validates JWT and extracts user ID
- Session refreshes automatically before expiration
Supabase Client Setup
Browser Client
Used in client components for authentication and data fetching.
// lib/supabase/client.ts
import { createBrowserClient } from "@supabase/ssr"
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
)
}Server Client
Used in server components and API routes for authenticated requests.
// lib/supabase/server.ts
import { createServerClient } from "@supabase/ssr"
import { cookies } from "next/headers"
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
try {
cookiesToSet.forEach(({ name, value, options }) =>
cookieStore.set(name, value, options)
)
} catch {
// Called from Server Component
}
},
},
}
)
}Session Management
Automatic Session Refresh
Sessions are automatically refreshed every 50 minutes to prevent expiration.
// lib/auth/session-refresh.ts
import { createClient } from "@/lib/supabase/client"
let refreshInterval: ReturnType<typeof setInterval> | null = null
export function startSessionRefresh(): void {
if (refreshInterval) return
const REFRESH_INTERVAL_MS = 50 * 60 * 1000 // 50 minutes
refreshInterval = setInterval(async () => {
try {
const supabase = createClient()
const { error } = await supabase.auth.refreshSession()
if (error) {
console.warn("Session refresh failed:", error.message)
}
} catch {
// Silently fail — user will be redirected on next action
}
}, REFRESH_INTERVAL_MS)
}
export function stopSessionRefresh(): void {
if (refreshInterval) {
clearInterval(refreshInterval)
refreshInterval = null
}
}Using Session in Components
"use client"
import { createClient } from "@/lib/supabase/client"
import { useEffect, useState } from "react"
export function useSession() {
const supabase = createClient()
const [session, setSession] = useState<Session | null>(null)
const [loading, setLoading] = useState(true)
useEffect(() => {
// Get initial session
supabase.auth.getSession().then(({ data: { session } }) => {
setSession(session)
setLoading(false)
})
// Listen for changes
const { data: { subscription } } = supabase.auth.onAuthStateChange(
(_event, session) => {
setSession(session)
setLoading(false)
}
)
return () => subscription.unsubscribe()
}, [])
return { session, loading }
}Auth Event Logging
Comprehensive logging system for authentication events to monitor security and debug issues.
Event Types
| Event | Description |
|---|---|
LOGIN_SUCCESS | User logged in successfully |
LOGIN_FAILURE | Login attempt failed |
LOGOUT | User logged out |
OAUTH_COMPLETED | OAuth flow completed |
SESSION_REFRESH | Session refreshed |
TOKEN_EXPIRED | JWT token expired |
UNAUTHORIZED_ACCESS | 401 response received |
Using the Logger
import { authLogger } from "@/lib/auth-logger"
// Log successful login
authLogger.logLoginSuccess(userId, email)
// Log failed login
authLogger.logLoginFailure(email, errorMessage)
// Log OAuth flow
authLogger.logOAuthStarted("google", redirectUrl)
authLogger.logOAuthCompleted(userId, "google")
// Log unauthorized access (auto-handled by API client)
authLogger.logUnauthorizedAccess("/api/v1/documents", 401)API Authorization
JWT in Requests
The API client automatically includes the JWT token in all requests.
// lib/api/client.ts
async function getAuthHeaders(): Promise<HeadersInit> {
const supabase = createSupabaseClient()
const {
data: { session },
} = await supabase.auth.getSession()
if (!session?.access_token) {
throw new ApiError(401, "Not authenticated")
}
return {
Authorization: `Bearer ${session.access_token}`,
"Content-Type": "application/json",
}
}Error Handling
The API client handles 401/403 errors by redirecting to login.
401- Unauthorized, redirect to login403- Forbidden, redirect to login (except task endpoints)429- Rate limited, auto-retry with backoff
OAuth Providers
Configure OAuth providers in the Supabase dashboard and backend environment.
| Provider | Backend Variable |
|---|---|
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | |
| GitHub | Configured in Supabase |
| Email/Password | Built-in with Supabase Auth |
Protected Routes
Middleware Protection
// middleware.ts
import { createServerClient } from "@supabase/ssr"
import { NextResponse, type NextRequest } from "next/server"
export async function middleware(request: NextRequest) {
let supabaseResponse = NextResponse.next({
request,
})
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) =>
request.cookies.set(name, value)
)
supabaseResponse = NextResponse.next({
request,
})
cookiesToSet.forEach(({ name, value, options }) =>
supabaseResponse.cookies.set(name, value, options)
)
},
},
}
)
// Check auth
const { data: { session } } = await supabase.auth.getSession()
if (!session && !request.nextUrl.pathname.startsWith("/auth")) {
return NextResponse.redirect(new URL("/auth/login", request.url))
}
return supabaseResponse
}Security Best Practices
Token Security
- Tokens stored securely in httpOnly cookies
- Auto-refresh before expiration
- Clear on logout
API Security
- JWT validation on all endpoints
- Rate limiting enabled
- CORS restricted to frontend
OAuth Security
- State parameter for CSRF protection
- Secure redirect URIs
- Token rotation enabled
Monitoring
- Auth events logged
- Failed attempts tracked
- Session anomalies detected