Files
NextChair/src/auth.ts
T
Stefan Lazic cbeccc6c1f
CI / ci (push) Canceled after 0s
Auth Fix
Fixed an issue where the user would be redirected to a localhost address because an auth url was not set in the env.
2026-09-06 21:01:54 +01:00

67 lines
2.8 KiB
TypeScript

import { PrismaAdapter } from "@auth/prisma-adapter";
import NextAuth from "next-auth";
import Credentials from "next-auth/providers/credentials";
import Google from "next-auth/providers/google";
import { authConfig } from "@/auth.config";
import { authorizeCredentials } from "@/lib/auth/authorize-credentials";
import { prisma } from "@/lib/db/prisma";
export { authorizeCredentials } from "@/lib/auth/authorize-credentials";
export const { handlers, auth, signIn, signOut } = NextAuth({
...authConfig,
// `@auth/prisma-adapter`'s published types still import `PrismaClient`
// from the legacy `@prisma/client` path; Prisma 7's `prisma-client`
// generator no longer populates that path (see prisma/schema.prisma).
// The adapter only calls plain `prisma.<model>.<method>()` at runtime,
// so this is a type-only mismatch, not a behavioural one — narrowed
// here instead of silencing it project-wide.
adapter: PrismaAdapter(prisma as Parameters<typeof PrismaAdapter>[0]),
providers: [
Google,
Credentials({
credentials: {
email: { label: "Email", type: "email" },
code: { label: "Code", type: "text" },
// Only ever set by the installer's own trusted server-side sign-in
// call — never rendered on any real form. See
// src/lib/auth/authorize-credentials.ts's own header for the full
// finalize/token design.
finalize: { label: "Finalize", type: "text" },
token: { label: "Token", type: "text" },
},
// Kept in its own module (not inlined here) so it's importable from
// a plain Vitest test without dragging in this file's NextAuth(...)
// construction, which needs the Next.js runtime — see
// authorize-credentials.ts's own header.
authorize: authorizeCredentials,
}),
],
callbacks: {
async jwt({ token, user, trigger, session }) {
if (user?.id) {
token.id = user.id;
}
// Lets a client-side `useSession().update({ email })` call (see
// change-email.ts's verifyEmailChangeAction, whose caller triggers
// this right after a successful email change) refresh the JWT's own
// email claim without forcing a full sign-out/sign-in — otherwise
// session.user.email would keep showing the old address until the
// token's next natural refresh. Nothing else in this app reads
// session.user.email for authorization (every permission/tenant
// check is keyed on token.id/session.user.id), so this is purely a
// display-freshness fix.
if (trigger === "update" && typeof session?.email === "string") {
token.email = session.email;
}
return token;
},
async session({ session, token }) {
if (session.user && typeof token.id === "string") {
session.user.id = token.id;
}
return session;
},
},
});