Agent skill
auth0
Implements Auth0 authentication with Next.js SDK, React hooks, role-based access, and API protection. Use when integrating Auth0, implementing enterprise SSO, or needing managed authentication with MFA.
Stars
163
Forks
31
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/data/auth0
SKILL.md
Auth0
Auth0 is an identity platform providing authentication, authorization, and user management. The Next.js SDK (v4) offers full App Router and Pages Router support.
Quick Start
Installation
bash
npm install @auth0/nextjs-auth0
Environment Variables
env
# .env.local
AUTH0_SECRET='use-a-long-random-string-min-32-chars'
AUTH0_BASE_URL='http://localhost:3000'
AUTH0_ISSUER_BASE_URL='https://your-tenant.auth0.com'
AUTH0_CLIENT_ID='your-client-id'
AUTH0_CLIENT_SECRET='your-client-secret'
Generate secret: openssl rand -hex 32
Auth0 Dashboard Setup
- Create Regular Web Application
- Set Allowed Callback URLs:
http://localhost:3000/auth/callback - Set Allowed Logout URLs:
http://localhost:3000 - Set Allowed Web Origins:
http://localhost:3000
App Router Setup (Next.js 13+)
Create Auth Route Handler
typescript
// app/auth/[auth0]/route.ts
import { handleAuth } from '@auth0/nextjs-auth0'
export const GET = handleAuth()
This creates routes:
/auth/login- Initiates login/auth/logout- Logs out user/auth/callback- OAuth callback/auth/me- Returns user profile
Add Provider
typescript
// app/layout.tsx
import { Auth0Provider } from '@auth0/nextjs-auth0'
export default function RootLayout({
children
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>
<Auth0Provider>
{children}
</Auth0Provider>
</body>
</html>
)
}
Client Component Usage
typescript
'use client'
import { useUser } from '@auth0/nextjs-auth0'
export default function Profile() {
const { user, error, isLoading } = useUser()
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
if (!user) return <a href="/auth/login">Login</a>
return (
<div>
<img src={user.picture} alt={user.name} />
<h2>{user.name}</h2>
<p>{user.email}</p>
<a href="/auth/logout">Logout</a>
</div>
)
}
Server Component Usage
typescript
// app/dashboard/page.tsx
import { getSession } from '@auth0/nextjs-auth0'
import { redirect } from 'next/navigation'
export default async function Dashboard() {
const session = await getSession()
if (!session) {
redirect('/auth/login')
}
return (
<div>
<h1>Welcome, {session.user.name}</h1>
<pre>{JSON.stringify(session.user, null, 2)}</pre>
</div>
)
}
Protected Routes
Middleware Protection
typescript
// middleware.ts
import { withMiddlewareAuthRequired } from '@auth0/nextjs-auth0/edge'
export default withMiddlewareAuthRequired()
export const config = {
matcher: ['/dashboard/:path*', '/api/protected/:path*']
}
Page-Level Protection
typescript
// app/protected/page.tsx
import { withPageAuthRequired, getSession } from '@auth0/nextjs-auth0'
export default withPageAuthRequired(async function ProtectedPage() {
const session = await getSession()
return <div>Protected content for {session?.user.email}</div>
}, {
returnTo: '/protected'
})
API Route Protection
Server Component API
typescript
// app/api/me/route.ts
import { getSession } from '@auth0/nextjs-auth0'
import { NextResponse } from 'next/server'
export async function GET() {
const session = await getSession()
if (!session) {
return NextResponse.json(
{ error: 'Not authenticated' },
{ status: 401 }
)
}
return NextResponse.json({ user: session.user })
}
Protected API Route
typescript
// app/api/protected/route.ts
import { withApiAuthRequired, getSession } from '@auth0/nextjs-auth0'
import { NextResponse } from 'next/server'
export const GET = withApiAuthRequired(async function handler(req) {
const session = await getSession()
return NextResponse.json({
message: `Hello ${session?.user.name}`
})
})
Calling External APIs
Get Access Token
typescript
// app/api/external/route.ts
import { getAccessToken } from '@auth0/nextjs-auth0'
import { NextResponse } from 'next/server'
export async function GET() {
try {
const { accessToken } = await getAccessToken({
scopes: ['read:data']
})
const response = await fetch('https://api.example.com/data', {
headers: {
Authorization: `Bearer ${accessToken}`
}
})
const data = await response.json()
return NextResponse.json(data)
} catch (error) {
return NextResponse.json(
{ error: 'Failed to get token' },
{ status: 500 }
)
}
}
Configure API Audience
env
AUTH0_AUDIENCE='https://api.example.com'
AUTH0_SCOPE='openid profile email read:data'
Role-Based Access Control
Add Roles to Tokens
In Auth0 Dashboard > Actions > Flows > Login, add:
javascript
exports.onExecutePostLogin = async (event, api) => {
const namespace = 'https://myapp.com'
if (event.authorization) {
api.idToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles)
api.accessToken.setCustomClaim(`${namespace}/roles`, event.authorization.roles)
}
}
Check Roles
typescript
// lib/auth.ts
import { getSession } from '@auth0/nextjs-auth0'
export async function getUserRoles(): Promise<string[]> {
const session = await getSession()
if (!session) return []
return session.user['https://myapp.com/roles'] || []
}
export async function hasRole(role: string): Promise<boolean> {
const roles = await getUserRoles()
return roles.includes(role)
}
export async function requireRole(role: string) {
if (!(await hasRole(role))) {
throw new Error('Unauthorized')
}
}
Role-Protected Component
typescript
// app/admin/page.tsx
import { getSession } from '@auth0/nextjs-auth0'
import { redirect } from 'next/navigation'
export default async function AdminPage() {
const session = await getSession()
const roles = session?.user['https://myapp.com/roles'] || []
if (!roles.includes('admin')) {
redirect('/unauthorized')
}
return <div>Admin Dashboard</div>
}
Custom Login/Logout
Custom Login Options
typescript
// app/auth/[auth0]/route.ts
import { handleAuth, handleLogin } from '@auth0/nextjs-auth0'
export const GET = handleAuth({
login: handleLogin({
authorizationParams: {
audience: 'https://api.example.com',
scope: 'openid profile email read:data'
},
returnTo: '/dashboard'
}),
signup: handleLogin({
authorizationParams: {
screen_hint: 'signup'
}
})
})
Custom Logout
typescript
import { handleAuth, handleLogout } from '@auth0/nextjs-auth0'
export const GET = handleAuth({
logout: handleLogout({
returnTo: '/'
})
})
Session Management
Update Session
typescript
// app/api/update-session/route.ts
import { getSession, updateSession } from '@auth0/nextjs-auth0'
import { NextResponse } from 'next/server'
export async function POST(req: Request) {
const session = await getSession()
if (!session) {
return NextResponse.json({ error: 'Not authenticated' }, { status: 401 })
}
// Update session with custom data
await updateSession({
...session,
user: {
...session.user,
customData: 'new value'
}
})
return NextResponse.json({ success: true })
}
Session Configuration
typescript
// app/auth/[auth0]/route.ts
import { handleAuth } from '@auth0/nextjs-auth0'
export const GET = handleAuth({
onError(req, error) {
console.error(error)
}
})
Organization Support
Login to Organization
typescript
import { handleAuth, handleLogin } from '@auth0/nextjs-auth0'
export const GET = handleAuth({
login: handleLogin({
authorizationParams: {
organization: 'org_123'
}
})
})
Dynamic Organization
typescript
// app/login/[org]/route.ts
import { handleLogin } from '@auth0/nextjs-auth0'
import { NextRequest } from 'next/server'
export async function GET(
req: NextRequest,
{ params }: { params: { org: string } }
) {
return handleLogin(req, {
authorizationParams: {
organization: params.org
}
})
}
Multi-Factor Authentication
Enable MFA in Auth0 Dashboard > Security > Multi-factor Auth:
typescript
// Force MFA for sensitive actions
import { handleAuth, handleLogin } from '@auth0/nextjs-auth0'
export const GET = handleAuth({
'login-mfa': handleLogin({
authorizationParams: {
acr_values: 'http://schemas.openid.net/pape/policies/2007/06/multi-factor'
}
})
})
Testing
Mock User in Tests
typescript
// __tests__/profile.test.tsx
import { render, screen } from '@testing-library/react'
import { UserProvider } from '@auth0/nextjs-auth0'
import Profile from '@/app/profile/page'
const mockUser = {
name: 'Test User',
email: 'test@example.com',
picture: 'https://example.com/avatar.png'
}
test('renders user profile', () => {
render(
<UserProvider user={mockUser}>
<Profile />
</UserProvider>
)
expect(screen.getByText('Test User')).toBeInTheDocument()
})
Best Practices
- Use environment variables - Never hardcode secrets
- Protect API routes - Use
withApiAuthRequired - Add roles to tokens - Use Auth0 Actions
- Configure audiences - For API access tokens
- Handle errors gracefully - Provide user-friendly messages
- Use middleware - For route protection at scale
References
Didn't find tool you were looking for?