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

Firebase部署后Next.js+Clerk认证重定向异常求助

解决Next.js + Firebase Hosting + Clerk认证重定向循环问题

问题现象

Next.js项目部署到Firebase App Hosting生产环境后,其他功能正常,但认证模块出现异常:本地开发环境无问题,生产环境创建账号并登录后,被重定向至https://mydomain/sign-in?redirect_url=https%3A%2F%2F0.0.0.0%3A8080%2Fdashboard,陷入登录页面循环。

报错信息:

clerk.browser.js:2 Clerk: Redirect URL https://0.0.0.0:8080/dashboard is not on one of the allowedRedirectOrigins, falling back to the default redirect URL.

已配置内容

环境变量

- variable: NEXT_PUBLIC_CLERK_SIGN_IN_FALLBACK_REDIRECT_URL
  value: "/dashboard"
- variable: NEXT_PUBLIC_CLERK_SIGN_UP_FORCE_REDIRECT_URL
  value: "/membercard/onboarding"
- variable: NEXT_PUBLIC_CLERK_SIGN_IN_FORCE_REDIRECT_URL
  value: "/dashboard"
- variable: NEXT_PUBLIC_CLERK_SIGN_IN_URL
  value: "/sign-in"
- variable: NEXT_PUBLIC_CLERK_SIGN_UP_URL
  value: "/sign-up"
- variable: NEXT_PUBLIC_CLERK_SIGN_IN_URL
  value: "/sign-in"

Middleware代码

import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'
import { NextRequest, NextResponse } from 'next/server';

const isPublicRoute = createRouteMatcher(['/sign-in(.*)', '/sign-up(.*)','/','/api/webhooks(.*)','/api/wallet(.*)','/membercard/profiles(.*)']);
const isOnboardingRoute = createRouteMatcher(['/membercard/onboarding']);
const isAdminRoute = createRouteMatcher(['/admin(.*)']); // New route matcher for admin routes

export default clerkMiddleware((auth, req: NextRequest) => {
  const { userId, sessionClaims, redirectToSignIn } = auth();
  console.log("Middleware triggered for URL:", req.url);

  // Check for admin routes
  if (isAdminRoute(req)) {
    if (!userId) {
      return redirectToSignIn({ returnBackUrl: req.url });
    }
    if (sessionClaims?.metadata?.role !== 'admin') {
      return NextResponse.redirect(new URL('/dashboard', req.url));
    }
  }

  if (userId && isOnboardingRoute(req)) {
    console.log("User is authenticated and on onboarding route.");
    return NextResponse.next();
  }

  if (!userId && !isPublicRoute(req)) {
    console.log("User is not authenticated and route is not public. Redirecting to sign-in.");
    const redirectUrl = new URL(req.url, process.env.NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL);
    console.log("Redirect URL:", redirectUrl); 
    return redirectToSignIn({ returnBackUrl: redirectUrl.toString() });
  }

  if (userId && !sessionClaims?.metadata?.onboardingComplete) {
    const onboardingUrl = new URL("/membercard/onboarding", req.url);
    return NextResponse.redirect(onboardingUrl);
  }

  if (userId && !isPublicRoute(req)) return NextResponse.next();
  console.log("User is authenticated and route is protected. Allowing access.");
  return NextResponse.next();
});

export const config = {
  matcher: ['/((?!.*\..*|_next).*)', '/', '/(api|trpc)(.*)'],
};

Clerk支持团队回复

该报错表明存在网络问题,可能是K8s、Docker或Firebase Hosting的网络控制导致,建议在请求头中转发主机域名。同时请确认已在Firebase变量中配置生产环境密钥。

云控制台日志

2024-08-13 07:31:04.796 CEST
User is not authenticated and route is not public. Redirecting to sign-in.
2024-08-13 07:31:04.796 CEST
Redirect URL: URL {  }
2024-08-13 07:31:04.949 CEST
GET307378 B9 msGoogle https://t-4011972723---enigmamembers-backend-fxedffxlpa-uc.a.run.app/dashboard?_rsc=2qkwf 
2024-08-13 07:31:04.957 CEST
Middleware triggered for URL: https://0.0.0.0:8080/dashboard
2024-08-13 07:31:04.959 CEST
User is not authenticated and route is not public. Redirecting to sign-in.
2024-08-13 07:31:04.959 CEST
Redirect URL: URL {  }
2024-08-13 07:31:05.542 CEST
GET200640 B41 msGoogle https://t-4011972723---enigmamembers-backend-fxedffxlpa-uc.a.run.app/sign-in?redirect_url=https%3A%2F%2F0.0.0.0%3A8080%2Fmembercard 
2024-08-13 07:31:05.544 CEST
GET2001.1 KB42 msGoogle https://t-4011972723---enigmamembers-backend-fxedffxlpa-uc.a.run.app/sign-in?redirect_url=https%3A%2F%2F0.0.0.0%3A8080%2Fdashboard 

解决方案

1. 修复Middleware中的RedirectUrl构建错误

从日志可见redirectUrl输出为空,说明process.env.NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL未正确配置,且new URL(req.url, base)的用法逻辑颠倒(正确应为new URL(path, base))。修改对应代码:

if (!userId && !isPublicRoute(req)) {
  console.log("User is not authenticated and route is not public. Redirecting to sign-in.");
  // 直接使用当前请求URL作为返回地址,避免环境变量依赖错误
  return redirectToSignIn({ returnBackUrl: req.url });
}

若需使用环境变量,确保NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL为生产域名(如https://mydomain.com),并正确构建URL:

const baseUrl = process.env.NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL || req.nextUrl.origin;
const redirectUrl = new URL(req.nextUrl.pathname, baseUrl);
return redirectToSignIn({ returnBackUrl: redirectUrl.toString() });

2. 配置Firebase Hosting转发主机头

Firebase Hosting代理请求时可能修改主机头,导致Clerk无法获取正确域名。在firebase.json中添加以下配置:

{
  "hosting": {
    "headers": [
      {
        "source": "**",
        "headers": [
          {
            "key": "X-Forwarded-Host",
            "value": "$host"
          },
          {
            "key": "Host",
            "value": "$host"
          }
        ]
      }
    ]
  }
}

3. 确认Clerk控制台的Allowed Redirect Origins

在Clerk控制台Authentication > Settings > Redirects中,添加生产环境完整域名(如https://mydomain.com)及Firebase云运行实例域名(如日志中的https://t-4011972723---enigmamembers-backend-fxedffxlpa-uc.a.run.app)。

4. 清理冗余环境变量

删除重复定义的NEXT_PUBLIC_CLERK_SIGN_IN_URL,确保所有变量值无多余引号。

5. 检查Clerk Provider配置

在app/layout.tsx或pages/_app.tsx中,确保<ClerkProvider>的domain属性设置为生产域名:

<ClerkProvider domain="https://mydomain.com">
  {/* 应用内容 */}
</ClerkProvider>

内容的提问来源于stack exchange,提问作者Jan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 19:38:13