Next.js authentication utilities for FastAPI backend
npm install @gittielabs/nextjs-fastapi-authAuthentication and authorization library for Next.js 15+ applications with Supabase backend integration.
``bash`
npm install @gittielabs/nextjs-fastapi-author
yarn add @gittielabs/nextjs-fastapi-author
pnpm add @gittielabs/nextjs-fastapi-auth
- 🔐 JWT Token Management - Extract and validate Supabase JWT tokens
- 🛡️ Admin Authentication - Server-side admin role verification
- 🔄 Auth Middleware - Automatic authentication and subdomain handling
- 🌐 Multi-Tenancy - Organization context via subdomains
- 📡 WebSocket Support - Authenticated WebSocket connections
- 🚀 Next.js 15 Compatible - Full support for async cookies and headers
Create a .env.local file:
`env`
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
Create or update middleware.ts:
`typescript
import { authMiddleware } from '@gittielabs/nextjs-fastapi-auth/middleware'
export default authMiddleware
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico|public/).*)',
],
}
`
Use admin authentication in API routes:
`typescript
// app/api/admin/users/route.ts
import { validateAdminAuth } from '@gittielabs/nextjs-fastapi-auth/server'
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
const auth = validateAdminAuth(request)
if (auth.error) {
return auth.error
}
// User is authenticated as admin
return NextResponse.json({
user: auth.user,
message: 'Admin access granted'
})
}
`
Use authenticated fetch for API calls:
`typescript
'use client'
import { authenticatedFetch } from '@gittielabs/nextjs-fastapi-auth/client'
export default function MyComponent() {
const fetchData = async () => {
const response = await authenticatedFetch('/api/data')
const data = await response.json()
console.log(data)
}
return
}
`
Extract and decode JWT tokens:
`typescript
import {
extractJwtFromRequest,
extractJwtPayload,
extractSubdomainFromJwt
} from '@gittielabs/nextjs-fastapi-auth/jwt'
// Extract JWT from NextRequest
const token = extractJwtFromRequest(request)
// Decode JWT payload
const payload = extractJwtPayload(token)
if (payload) {
console.log('User ID:', payload.sub)
console.log('Email:', payload.email)
}
// Extract organization subdomain
const subdomain = extractSubdomainFromJwt(token)
`
Validate admin access in API routes:
`typescript
import { validateAdminAuth } from '@gittielabs/nextjs-fastapi-auth/server'
export async function POST(request: NextRequest) {
const auth = validateAdminAuth(request)
if (auth.error) {
return auth.error // Returns 401 or 403 response
}
// Access authenticated user data
const { user } = auth
console.log('Admin user:', user.email)
console.log('Organization:', user.organization_subdomain)
// Proceed with admin operation...
}
`
The auth middleware handles:
- Authentication verification
- Subdomain-based routing
- WWW redirect
- Protected route enforcement
`typescript
import { authMiddleware } from '@gittielabs/nextjs-fastapi-auth/middleware'
// Use as-is or customize configuration
export default authMiddleware
// Or create custom middleware
import { NextRequest, NextResponse } from 'next/server'
import { extractJwtFromRequest } from '@gittielabs/nextjs-fastapi-auth/jwt'
export async function middleware(request: NextRequest) {
const token = extractJwtFromRequest(request)
if (!token && request.nextUrl.pathname.startsWith('/protected')) {
return NextResponse.redirect(new URL('/login', request.url))
}
return NextResponse.next()
}
`
Client-side fetch with automatic authentication:
`typescript
import { authenticatedFetch } from '@gittielabs/nextjs-fastapi-auth/client'
// Automatically includes Authorization header
const response = await authenticatedFetch('/api/data', {
method: 'POST',
body: JSON.stringify({ key: 'value' }),
})
const data = await response.json()
`
Create authenticated WebSocket connections:
`typescript
import { createAuthenticatedWebSocket } from '@gittielabs/nextjs-fastapi-auth/client'
const ws = await createAuthenticatedWebSocket('wss://api.example.com/ws')
ws.onmessage = (event) => {
console.log('Message:', event.data)
}
ws.send(JSON.stringify({ action: 'subscribe', channel: 'updates' }))
`
The library supports role-based access control:
`typescript`
interface JwtPayload {
sub: string // User ID
email: string // User email
user_metadata: {
role?: string // User role
is_super_admin?: boolean // Super admin flag
organization_subdomain?: string
}
// ... other Supabase JWT fields
}
Roles are used by the admin authentication to control access:
- Super admins have access to all organizations
- Organization admins can access their organization's admin routes
- Regular users are blocked from admin routes
#### extractJwtFromRequest(request: NextRequest): string | null
Extract JWT token from request headers or cookies.
#### extractJwtPayload(token: string): JwtPayload | null
Decode and parse JWT payload.
#### extractSubdomainFromJwt(token: string): string | null
Extract organization subdomain from JWT metadata.
#### extractSubdomainFromRequest(request: NextRequest): string | null
Extract subdomain from request hostname.
#### validateAdminAuth(request: NextRequest): { user: JwtPayload } | { error: NextResponse }
Validate that the request is from an authenticated admin user.
Returns either:
- { user: JwtPayload } - User is authenticated as admin{ error: NextResponse }
- - Authentication failed (401 or 403)
#### authMiddleware(request: NextRequest): Promise
Complete authentication middleware with:
- WWW redirect
- Subdomain handling
- Authentication verification
- Protected route enforcement
#### authenticatedFetch(url: string, options?: RequestInit): Promise
Fetch with automatic JWT authentication.
#### createAuthenticatedWebSocket(url: string): Promise
Create WebSocket connection with JWT authentication.
This library is written in TypeScript and includes full type definitions:
`typescript`
import type {
JwtPayload,
AdminAuthResult,
AuthenticatedUser
} from '@gittielabs/nextjs-fastapi-auth'
`bash
npm test
$3
`bash
npm run build
`$3
`bash
npm run lint
`Best Practices
$3
Always validate authentication on the server side:
`typescript
// ✅ Good - Server-side validation
export async function GET(request: NextRequest) {
const auth = validateAdminAuth(request)
if (auth.error) return auth.error
// ... secure operation
}// ❌ Bad - Client-side only
'use client'
export default function AdminPanel() {
// Client-side checks can be bypassed
}
`$3
Keep sensitive keys secure:
`typescript
// ✅ Good - Use environment variables
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL// ❌ Bad - Hardcoded values
const supabaseUrl = 'https://myproject.supabase.co'
`$3
Handle authentication errors gracefully:
`typescript
const auth = validateAdminAuth(request)if (auth.error) {
// Log error details server-side
console.error('Auth failed:', auth.error)
// Return user-friendly error
return auth.error
}
`$3
Use subdomains for organization isolation:
`typescript
// Extract subdomain for data filtering
const subdomain = extractSubdomainFromRequest(request)// Filter queries by organization
const data = await db.query({
where: { organization_subdomain: subdomain }
})
`Troubleshooting
$3
Ensure the client is sending the Authorization header:
`typescript
// Check if token exists in cookies
const cookies = await import('next/headers')
const cookieStore = await cookies.cookies()
const token = cookieStore.get('sb-access-token')
`$3
Verify your Supabase configuration:
- Check
NEXT_PUBLIC_SUPABASE_URL is correct
- Ensure SUPABASE_SERVICE_ROLE_KEY is the service role key (not anon key)
- Confirm the JWT hasn't expired$3
Ensure your middleware is properly configured:
`typescript
export const config = {
matcher: [
'/((?!_next/static|_next/image|favicon.ico).*)',
],
}
`Migration Guide
$3
If migrating from an older version:
1. Update to Next.js 15+
2. Make cookies and headers async:
`typescript
// Before
const cookieStore = cookies()// After (Next.js 15+)
const cookieStore = await cookies()
`3. Update middleware exports:
`typescript
// Before
export { middleware } from '@gittielabs/nextjs-fastapi-auth'// After
import { authMiddleware } from '@gittielabs/nextjs-fastapi-auth/middleware'
export default authMiddleware
``Contributions are welcome! Please see the main repository for guidelines.
MIT © GittieLabs
For issues and questions:
- GitHub Issues: Create an issue
- Documentation: Full docs