feat(auth): proactive session expiry redirect across all delivery paths
- Split auth config into auth.config.ts (edge-safe, no argon2) and auth-edge.ts for middleware use; auth.ts now spreads the shared config - Middleware wraps with auth() to redirect unauthenticated requests to /auth/signin before any page render; passes through /auth/, /api/, /invite/ paths - SessionGuard client component watches useSession() and redirects on status=unauthenticated, closing the SPA navigation gap - QueryCache + MutationCache in TRPCProvider redirect on UNAUTHORIZED tRPC errors without retrying; SessionProvider polls session state every 5 minutes - Middleware tests updated for async auth wrapper and auth-edge mock Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
import NextAuth from "next-auth";
|
||||
import { authConfig } from "./auth.config.js";
|
||||
|
||||
// Lightweight NextAuth instance for Edge runtime (middleware).
|
||||
// Does not import any native modules — only verifies JWT sessions.
|
||||
export const { auth } = NextAuth(authConfig);
|
||||
@@ -0,0 +1,45 @@
|
||||
import type { NextAuthConfig } from "next-auth";
|
||||
|
||||
// Edge-safe auth config — no native modules (no argon2, no prisma).
|
||||
// Used by auth-edge.ts (middleware) to verify JWT sessions without
|
||||
// pulling in Node.js-only packages into the Edge runtime.
|
||||
export const authConfig = {
|
||||
pages: {
|
||||
signIn: "/auth/signin",
|
||||
},
|
||||
providers: [],
|
||||
session: {
|
||||
strategy: "jwt",
|
||||
maxAge: 28800, // 8 hours absolute timeout
|
||||
updateAge: 1800, // refresh token every 30 minutes
|
||||
},
|
||||
cookies: {
|
||||
sessionToken: {
|
||||
name: "authjs.session-token",
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: "strict" as const,
|
||||
path: "/",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
},
|
||||
},
|
||||
callbackUrl: {
|
||||
name: "authjs.callback-url",
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: "strict" as const,
|
||||
path: "/",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
},
|
||||
},
|
||||
csrfToken: {
|
||||
name: "authjs.csrf-token",
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: "strict" as const,
|
||||
path: "/",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
},
|
||||
},
|
||||
},
|
||||
} satisfies NextAuthConfig;
|
||||
@@ -8,6 +8,7 @@ import { CredentialsSignin } from "next-auth";
|
||||
import { verify } from "@node-rs/argon2";
|
||||
import { z } from "zod";
|
||||
import { assertSecureRuntimeEnv } from "./runtime-env";
|
||||
import { authConfig } from "./auth.config.js";
|
||||
|
||||
assertSecureRuntimeEnv();
|
||||
|
||||
@@ -30,7 +31,8 @@ const LoginSchema = z.object({
|
||||
totp: z.string().optional(),
|
||||
});
|
||||
|
||||
const authConfig = {
|
||||
const config = {
|
||||
...authConfig,
|
||||
trustHost: true,
|
||||
providers: [
|
||||
Credentials({
|
||||
@@ -277,43 +279,6 @@ const authConfig = {
|
||||
});
|
||||
},
|
||||
},
|
||||
cookies: {
|
||||
sessionToken: {
|
||||
name: "authjs.session-token",
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: "strict" as const,
|
||||
path: "/",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
},
|
||||
},
|
||||
callbackUrl: {
|
||||
name: "authjs.callback-url",
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: "strict" as const,
|
||||
path: "/",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
},
|
||||
},
|
||||
csrfToken: {
|
||||
name: "authjs.csrf-token",
|
||||
options: {
|
||||
httpOnly: true,
|
||||
sameSite: "strict" as const,
|
||||
path: "/",
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
},
|
||||
},
|
||||
},
|
||||
pages: {
|
||||
signIn: "/auth/signin",
|
||||
},
|
||||
session: {
|
||||
strategy: "jwt",
|
||||
maxAge: 28800, // 8 hours absolute timeout
|
||||
updateAge: 1800, // Refresh token every 30 minutes (idle timeout)
|
||||
},
|
||||
} satisfies NextAuthConfig;
|
||||
|
||||
export const { handlers, auth } = NextAuth(authConfig);
|
||||
export const { handlers, auth } = NextAuth(config);
|
||||
|
||||
Reference in New Issue
Block a user