@melvinprince/next-authz
v0.1.0
Published
A reusable Next.js authentication library with Google OAuth support
Maintainers
Readme
@melvin/next-authz
A secure, edge-compatible authentication library for Next.js with Google OAuth support.
Features
- 🔐 Secure OAuth Flow - PKCE, state validation, nonce protection
- ⚡ Edge Compatible - Runs on Vercel Edge Functions and Cloudflare Workers
- 🍪 Secure Cookies - httpOnly, secure, sameSite with rotation support
- 🔄 Key Rotation - Seamless secret rotation without downtime
- 📦 Tree Shakeable - ESM-only with minimal bundle size
- 🛡️ Type Safe - Full TypeScript support with strict types
Quick Start
1. Install
npm install @melvin/next-authz2. Environment Variables
Create .env.local:
AUTH_SECRET="your-32-character-secret-here"
AUTH_APP_URL="http://localhost:3000"
GOOGLE_CLIENT_ID="your-google-client-id"
GOOGLE_CLIENT_SECRET="your-google-client-secret"
GOOGLE_REDIRECT_URI="http://localhost:3000/api/auth/callback"3. Create Auth Configuration
// lib/auth.ts
import { googleProvider, createAuth } from '@melvin/next-authz'
const authConfig = {
appUrl: process.env.AUTH_APP_URL!,
callbackPath: '/api/auth/callback',
secrets: [process.env.AUTH_SECRET!],
clockSkewTolerance: 60,
}
const provider = googleProvider(
process.env.GOOGLE_CLIENT_ID!,
process.env.GOOGLE_CLIENT_SECRET!,
process.env.GOOGLE_REDIRECT_URI!
)
export const auth = createAuth(authConfig, provider)4. Add Route Handlers
// app/api/auth/start/route.ts
import { auth } from '@/lib/auth'
export const GET = auth.startHandler// app/api/auth/callback/route.ts
import { auth } from '@/lib/auth'
export const GET = auth.callbackHandler// app/api/auth/session/route.ts
import { auth } from '@/lib/auth'
import { NextRequest, NextResponse } from 'next/server'
export async function GET(request: NextRequest) {
const session = await auth.getSession(request)
return NextResponse.json({ user: session.user, valid: session.valid })
}5. Add Middleware
// middleware.ts
import { auth } from '@/lib/auth'
export default auth.middleware6. Protect Routes
// app/dashboard/page.tsx
import { auth } from '@/lib/auth'
import { requireSession } from '@melvin/next-authz'
export default async function DashboardPage(request: NextRequest) {
const session = await requireSession(request, auth.getConfig())
return (
<div>
<h1>Welcome, {session.name}!</h1>
<p>Email: {session.email}</p>
</div>
)
}7. Client-Side Session
// components/UserProfile.tsx
'use client'
import { useSession } from '@melvin/next-authz/client'
export function UserProfile() {
const { user, loading, error } = useSession()
if (loading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
if (!user) return <div>Please sign in</div>
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
)
}Configuration
AuthConfig Options
interface AuthConfig {
appUrl: string // Your app's base URL
callbackPath: string // OAuth callback path
cookiePrefix?: string // Cookie name prefix (default: 'auth')
secrets: string[] // Array of secrets for rotation
sessionStrategy?: 'jwt' // Session strategy (default: 'jwt')
clockSkewTolerance?: number // Clock skew tolerance in seconds (default: 60)
allowedOrigins?: string[] // Allowed origins for CSRF protection
logger?: {
// Telemetry hooks
onLoginStart?: (data) => void
onLoginSuccess?: (data) => void
onLoginFailure?: (data) => void
}
}Middleware Configuration
// middleware.ts
import { createAuthMiddleware } from '@melvin/next-authz'
export default createAuthMiddleware(authConfig, {
matcher: {
include: ['/dashboard/:path*', '/admin/:path*'],
exclude: ['/api/auth/:path*', '/_next/:path*'],
},
redirectTo: '/login',
return401: false, // Return 401 instead of redirect
})Advanced Usage
Role-Based Access Control
// Add roles to session
const session = await requireSession(request, authConfig)
if (!session.roles?.includes('admin')) {
return NextResponse.json({ error: 'Forbidden' }, { status: 403 })
}Google API Integration
// Get access token for Google APIs
const accessToken = await getGoogleAccessToken(session)
const response = await fetch('https://www.googleapis.com/calendar/v3/calendars/primary/events', {
headers: { Authorization: `Bearer ${accessToken}` },
})Custom Error Handling
import { AuthError, OAuthError, SessionError } from '@melvin/next-authz'
try {
const session = await requireSession(request, authConfig)
} catch (error) {
if (error instanceof SessionError) {
// Handle session errors
} else if (error instanceof OAuthError) {
// Handle OAuth errors
}
}Security
Cookie Security
All cookies use secure defaults:
httpOnly- Prevents XSS attackssecure- HTTPS onlysameSite=lax- CSRF protection- Short TTL for temporary cookies
- Encryption for sensitive data
OAuth Security
- PKCE - Prevents authorization code interception
- State Parameter - CSRF protection
- Nonce Validation - Prevents replay attacks
- Clock Skew Tolerance - Handles time sync issues
Environment Variables
| Variable | Description | Required |
| ---------------------- | -------------------------------------- | -------- |
| AUTH_SECRET | Primary secret for signing (32+ chars) | Yes |
| AUTH_SECRETS | Comma-separated secrets for rotation | No |
| AUTH_APP_URL | Your application URL | Yes |
| AUTH_CALLBACK_PATH | OAuth callback path | No |
| GOOGLE_CLIENT_ID | Google OAuth client ID | Yes |
| GOOGLE_CLIENT_SECRET | Google OAuth client secret | Yes |
| GOOGLE_REDIRECT_URI | OAuth redirect URI | Yes |
Examples
API Reference
Server-Side Functions (from @melvin/next-authz)
createAuth(config, provider)- Create auth instancegoogleProvider(clientId, clientSecret, redirectUri)- Google providercreateStartHandler(config, provider)- Login start handlercreateCallbackHandler(config, provider)- OAuth callback handlercreateAuthMiddleware(config, options)- Authentication middlewaregetSession(request, config)- Get session (server-side)requireSession(request, config)- Require session (server-side)rotateKeys(config, newSecret)- Rotate secrets
Client-Side Functions (from @melvin/next-authz/client)
useSession(options)- Session hook (client-side)
Note: Client-side functions must be imported from the /client entry point and used in components marked with 'use client'.
Types
AuthUser- User profile dataAuthSession- Session with JWT claimsAuthConfig- Configuration optionsAuthProvider- Provider interfaceAuthErrorCode- Standardized error codes
Build Considerations
Client-Side Bundle
The client-side bundle (@melvin/next-authz/client) is optimized for browser usage:
- Bundle Size: Minimized for optimal performance
- Tree Shaking: Unused code is automatically removed
- ESM Only: Modern module format for better tree shaking
- React Hooks: Includes
useSessionhook for client-side session management
Note: The build process strips the 'use client' directive from the compiled bundle as it's handled by Next.js at runtime. This is expected behavior and doesn't affect functionality.
Development vs Production
- Development: Source maps included for debugging
- Production: Minified and optimized for size
- TypeScript: Full type definitions included
Contributing
See CONTRIBUTING.md for development setup and guidelines.
License
MIT License - see LICENSE for details.
