You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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控制台的关键配置

  1. 确认API Audience完全匹配:middleware和API路由里的audience必须和Auth0控制台中API的标识符完全一致(包括大小写、是否带斜杠)。
  2. 应用程序配置:确保你的Next.js应用的Allowed Callback URLs、Allowed Logout URLs、Allowed Web Origins都添加了http://localhost:3000(生产环境替换成你的域名)。
  3. 权限范围(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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.20 11:32:56