Next.js 13(App Router)中使用Auth0 withMiddlewareAuthRequired验证API路由时持续返回401的问题求助
Next.js 13(App Router)中使用Auth0 withMiddlewareAuthRequired验证API路由时持续返回401的问题求助
看起来你遇到了Next.js 13 App Router结合Auth0中间件时API路由认证的典型坑,我来帮你梳理下问题根源和解决方案:
一、你的中间件逻辑存在几个关键问题
你当前的中间件里手动做了URL rewrite,而且调用getAccessToken时没有指定API Audience,这会导致拿到的Token可能不匹配你的API,或者传递方式不对。另外,没必要对所有路由都做rewrite,应该只针对API路由处理Token传递。
二、修正中间件实现
先修改你的middleware.ts,确保正确获取针对API的AccessToken,并只对API路由添加认证头:
import { withMiddlewareAuthRequired, getAccessToken } from '@auth0/nextjs-auth0/edge'; import { NextResponse } from 'next/server'; export default withMiddlewareAuthRequired(async function middleware(req) { const res = NextResponse.next(); const { pathname } = req.nextUrl; // 仅对API路由处理Token传递 if (pathname.startsWith('/api/')) { try { // 必须指定你的API Audience,否则获取的Token无法通过API验证 const { accessToken } = await getAccessToken(req, res, { audience: 'YOUR_AUTH0_API_AUDIENCE', // 替换成你在Auth0控制台配置的API Audience }); if (accessToken) { // 给请求头添加Bearer Token const requestHeaders = new Headers(req.headers); requestHeaders.set('Authorization', `Bearer ${accessToken}`); return NextResponse.next({ request: { headers: requestHeaders } }); } } catch (error) { console.error('获取AccessToken失败:', error); return new NextResponse(JSON.stringify({ error: 'Unauthorized' }), { status: 401 }); } } return res; }); // 配置中间件的匹配规则,排除不需要保护的路由 export const config = { matcher: ['/((?!login|api/auth|_next/static|_next/image|favicon.ico).*)'], };
三、API路由需要正确验证Token
你的API路由不能只依赖会话,要主动验证请求头里的Bearer Token(毕竟API是无状态的,前端调用/Postman不会带会话Cookie)。可以用两种方式实现:
方式1:用Auth0的getSession快速验证(依赖中间件传递的会话)
// app/api/sample/route.ts import { getSession } from '@auth0/nextjs-auth0'; import { NextResponse } from 'next/server'; export async function GET(req: Request) { const session = await getSession(); if (!session || !session.user) { return new NextResponse( JSON.stringify({ error: "not_authenticated", description: "The user does not have an active session or is not authenticated" }), { status: 401 } ); } return NextResponse.json({ message: "API认证成功", user: session.user }); }
方式2:手动验证JWT Token(更适合纯API场景,无状态)
// app/api/sample/route.ts import jwt from 'jsonwebtoken'; import { NextResponse } from 'next/server'; // 从Auth0控制台获取你的API公钥,或者用JWKS endpoint自动获取 const AUTH0_PUBLIC_KEY = 'YOUR_AUTH0_API_PUBLIC_KEY'; const API_AUDIENCE = 'YOUR_AUTH0_API_AUDIENCE'; const AUTH0_DOMAIN = 'https://your-domain.auth0.com/'; export async function GET(req: Request) { const authHeader = req.headers.get('Authorization'); if (!authHeader || !authHeader.startsWith('Bearer ')) { return new NextResponse( JSON.stringify({ error: "not_authenticated", description: "Missing or invalid Authorization header" }), { status: 401 } ); } const token = authHeader.split(' ')[1]; try { // 验证Token的有效性、受众、签发者 jwt.verify(token, AUTH0_PUBLIC_KEY, { audience: API_AUDIENCE, issuer: AUTH0_DOMAIN, algorithms: ['RS256'] }); } catch (error) { return new NextResponse( JSON.stringify({ error: "invalid_token", description: "Token verification failed" }), { status: 401 } ); } return NextResponse.json({ message: "API认证成功" }); }
四、检查Auth0控制台的关键配置
- 确认API Audience完全匹配:middleware和API路由里的
audience必须和Auth0控制台中API的标识符完全一致(包括大小写、是否带斜杠)。 - 应用程序配置:确保你的Next.js应用的
Allowed Callback URLs、Allowed Logout URLs、Allowed Web Origins都添加了http://localhost:3000(生产环境替换成你的域名)。 - 权限范围(Scopes):如果你的API需要特定权限,要在Auth0控制台的API里添加对应的Scopes,并且用户登录时要请求这些Scopes(比如在
loginWithRedirect时指定scope: 'openid profile email read:data')。
五、解决Postman测试的问题
用Postman测试时,确保:
- 请求头里的
Authorization格式是Bearer YOUR_ACCESS_TOKEN - 用jwt.io解析Token,检查
aud字段是否和你的API Audience一致,如果不一致,说明获取Token时没有指定audience,需要重新获取正确的Token。
关于你的困惑:为什么浏览器直接访问API路由可以?
因为用户登录后,浏览器会携带Auth0的会话Cookie,getSession可以通过这个Cookie获取用户会话,所以能通过验证。但前端调用(比如fetch/axios)默认不会携带Cookie(除非配置credentials: 'include'),Postman也没有这个Cookie,所以必须依赖Bearer Token认证。
备注:内容来源于stack exchange,提问作者Rudrank Basant
相关产品推荐
相关产品推荐

