// src/auth.ts import NextAuth from "next-auth"; import { PrismaAdapter } from "@auth/prisma-adapter"; import { prisma } from "@/lib/prisma"; import authConfig from "./auth.config"; export const { handlers, signIn, signOut, auth } = NextAuth({ adapter: PrismaAdapter(prisma), session: { strategy: "jwt" }, ...authConfig, callbacks: { async jwt({ token, account, user }) { // 1. Handle OAuth tokens (from first sign-in) // This captures the tokens directly from the Microsoft Azure response if (account) { token.accessToken = account.access_token; token.refreshToken = account.refresh_token; token.expiresAt = account.expires_at; } // 2. Attach User ID and Role to the token // This runs when the user first logs in if (user) { token.sub = user.id; // @ts-ignore - 'role' is a custom field in your Postgres User table token.role = user.role; } return token; }, async session({ session, token }) { // 3. Pass values from the JWT Token into the Client-facing Session // This makes the tokens and IDs available to your API routes and Components if (session?.user) { session.user.id = token.sub as string; // @ts-ignore - Attaching the role for UI permissions session.user.role = token.role as string; // IMPORTANT: We must attach the accessToken here so the // /api/download route can use it to fetch from MS Graph session.accessToken = token.accessToken as string; } return session; }, }, events: { async linkAccount({ account, user }) { console.log("🔗 Account linked successfully for user:", user.id); if (!account.refresh_token) { console.warn("⚠️ WARNING: No refresh_token received in linkAccount event!"); } } } });