import NextAuth from "next-auth"; import MicrosoftEntraID from "next-auth/providers/microsoft-entra-id"; const DV = process.env.DATAVERSE_URL; // https://.crm.dynamics.com export const { handlers, auth, signIn, signOut } = NextAuth({ trustHost: true, providers: [ MicrosoftEntraID({ clientId: process.env.AZURE_CLIENT_ID, clientSecret: process.env.AZURE_CLIENT_SECRET, issuer: `https://login.microsoftonline.com/${process.env.AZURE_TENANT_ID}/v2.0`, authorization: { params: { scope: `openid profile email offline_access ${DV}/user_impersonation`, }, }, }), ], callbacks: { async jwt({ token, account }) { if (account) { token.accessToken = account.access_token; token.refreshToken = account.refresh_token; token.expiresAt = account.expires_at; } if (token.expiresAt && Date.now() / 1000 > token.expiresAt - 300 && token.refreshToken) { try { const r = await fetch( `https://login.microsoftonline.com/${process.env.AZURE_TENANT_ID}/oauth2/v2.0/token`, { method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ client_id: process.env.AZURE_CLIENT_ID, client_secret: process.env.AZURE_CLIENT_SECRET, grant_type: "refresh_token", refresh_token: token.refreshToken, scope: `openid profile email offline_access ${DV}/user_impersonation`, }), } ); if (r.ok) { const d = await r.json(); token.accessToken = d.access_token; token.expiresAt = Math.floor(Date.now() / 1000) + d.expires_in; if (d.refresh_token) token.refreshToken = d.refresh_token; } else { token.error = "RefreshFailed"; } } catch { token.error = "RefreshFailed"; } } return token; }, async session({ session, token }) { session.accessToken = token.accessToken; session.error = token.error; const email = (session.user?.email || "").toLowerCase(); session.email = email; session.isAdmin = (process.env.ADMIN_EMAILS || "") .toLowerCase() .split(",") .map((s) => s.trim()) .filter(Boolean) .includes(email); return session; }, }, session: { strategy: "jwt" }, });