Fix SSO: use /api/auth (no basePath) as OAuth redirect_uri

next-auth v5 beta.30 cannot reliably pass the /hp-prod-tracker prefix
through OAuth redirect_uri — redirectProxyUrl is silently ignored.

Instead: AUTH_URL=https://…/api/auth (matches basePath exactly), Auth.js
sends consistent redirect_uri in both authorization and token exchange,
Apache proxies /api/auth → :3001 before the OliVAS /api/ rule.

Azure must have https://optical-dev.oliver.solutions/api/auth/callback/microsoft-entra-id registered.
Server .env: AUTH_URL=https://optical-dev.oliver.solutions/api/auth

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Vadym Samoilenko 2026-04-15 15:54:37 +01:00
parent f5b091ceea
commit bf0bee9c28
2 changed files with 14 additions and 20 deletions

View file

@ -12,6 +12,11 @@ RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/hp-prod-tracker/(.*) ws://127.0.0.1:3001/hp-prod-tracker/$1 [P,L]
# OAuth callback — must be defined BEFORE the global /api/ → OliVAS rule.
# Auth.js uses /api/auth/* without the Next.js basePath in redirect_uri.
ProxyPass /api/auth http://127.0.0.1:3001/api/auth
ProxyPassReverse /api/auth http://127.0.0.1:3001/api/auth
# Chat + AI endpoints: long timeout for streaming responses
ProxyPass /hp-prod-tracker/api/chat http://127.0.0.1:3001/hp-prod-tracker/api/chat timeout=300
ProxyPassReverse /hp-prod-tracker/api/chat http://127.0.0.1:3001/hp-prod-tracker/api/chat

View file

@ -4,22 +4,18 @@ import { PrismaAdapter } from "@auth/prisma-adapter";
import { prisma } from "@/lib/prisma";
import type { Role } from "@/generated/prisma/client";
// AUTH_URL must be the full auth endpoint URL including basePath, e.g.:
// https://optical-dev.oliver.solutions/hp-prod-tracker/api/auth
// AUTH_URL = https://optical-dev.oliver.solutions/api/auth
//
// next-auth v5 beta ignores redirectProxyUrl for the authorization request
// (strips pathname from AUTH_URL) but DOES use it for the token exchange.
// We fix the authorization request via authorization.params.redirect_uri
// and restore redirectProxyUrl so token exchange uses the same URI.
const authUrl = process.env.AUTH_URL; // e.g. https://…/hp-prod-tracker/api/auth
const explicitRedirectUri = authUrl
? `${authUrl}/callback/microsoft-entra-id`
: undefined;
// We intentionally use the /api/auth path WITHOUT the Next.js /hp-prod-tracker
// basePath. next-auth v5 beta cannot reliably pass the app basePath through the
// OAuth redirect_uri — redirectProxyUrl is silently ignored in beta.30.
//
// Instead: AUTH_URL matches basePath exactly (/api/auth) so there is no
// env-url-basepath-mismatch, Auth.js sends a consistent redirect_uri in both
// the authorization and token exchange requests, and Apache proxies /api/auth
// directly to the container (see apache/hp-prod-tracker.conf).
export const { handlers, auth, signIn, signOut } = NextAuth({
// Explicit basePath prevents AUTH_URL's pathname from overriding it.
// Next.js strips the /hp-prod-tracker prefix before Auth.js sees the request,
// so internally routes must match /api/auth/*.
basePath: "/api/auth",
adapter: PrismaAdapter(prisma),
providers: [
@ -30,13 +26,6 @@ export const { handlers, auth, signIn, signOut } = NextAuth({
// Safe for Entra ID — Microsoft verifies organizational emails.
// Required to link SSO accounts to pre-seeded User records by email match.
allowDangerousEmailAccountLinking: true,
// authorization.params: fixes redirect_uri in the authorization request
// redirectProxyUrl: fixes redirect_uri in the token exchange request
// Both are needed — beta.30 ignores redirectProxyUrl for authorization.
...(explicitRedirectUri && {
authorization: { params: { redirect_uri: explicitRedirectUri } },
}),
redirectProxyUrl: authUrl,
}),
],
session: {