Checkpoint: Connexion Microsoft 365 (Azure AD OAuth2) : migration DB azureAdId, helpers backend, route callback, bouton Login, page AzureCallback, tests OK
This commit is contained in:
@@ -11,8 +11,9 @@ import { serveStatic, setupVite } from "./vite";
|
||||
import { runFullImport } from "../importer";
|
||||
import uploadRoutes from "../uploadRoutes";
|
||||
import scheduledRoutes from "../scheduledRoutes";
|
||||
import { ensureAdminExists } from "../localAuth";
|
||||
import { getSetting, purgeOldArticles } from "../db";
|
||||
import { ensureAdminExists, generateLocalToken } from "../localAuth";
|
||||
import { isAzureAdConfigured, getAzureAuthUrl, handleAzureCallback } from "../azureAuth";
|
||||
import { getLocalUserByAzureAdId, getLocalUserByEmail, upsertLocalUserAzure, getSetting, purgeOldArticles } from "../db";
|
||||
import { runRssFetch } from "../rssEngine";
|
||||
|
||||
function isPortAvailable(port: number): Promise<boolean> {
|
||||
@@ -126,6 +127,87 @@ async function startServer() {
|
||||
registerOAuthRoutes(app);
|
||||
app.use(uploadRoutes);
|
||||
app.use(scheduledRoutes);
|
||||
|
||||
// ─── Azure AD OAuth2 callback ─────────────────────────────────────────────
|
||||
app.get("/api/auth/azure/callback", async (req, res) => {
|
||||
const code = req.query.code as string | undefined;
|
||||
const error = req.query.error as string | undefined;
|
||||
|
||||
if (error) {
|
||||
res.redirect(`/login?error=${encodeURIComponent("Connexion Microsoft refus\u00e9e")}`);
|
||||
return;
|
||||
}
|
||||
if (!code) {
|
||||
res.redirect("/login?error=" + encodeURIComponent("Code OAuth manquant"));
|
||||
return;
|
||||
}
|
||||
if (!isAzureAdConfigured()) {
|
||||
res.redirect("/login?error=" + encodeURIComponent("Azure AD non configur\u00e9"));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const azureUser = await handleAzureCallback(code);
|
||||
|
||||
// Chercher par azureAdId puis par email
|
||||
let user = await getLocalUserByAzureAdId(azureUser.azureAdId);
|
||||
if (!user) user = await getLocalUserByEmail(azureUser.email);
|
||||
|
||||
if (!user) {
|
||||
// Cr\u00e9er automatiquement avec r\u00f4le "user"
|
||||
await upsertLocalUserAzure({
|
||||
email: azureUser.email,
|
||||
name: azureUser.name,
|
||||
azureAdId: azureUser.azureAdId,
|
||||
role: "user",
|
||||
});
|
||||
user = await getLocalUserByEmail(azureUser.email);
|
||||
} else if (!user.azureAdId) {
|
||||
// Lier le compte existant \u00e0 Azure AD
|
||||
await upsertLocalUserAzure({
|
||||
email: user.email ?? azureUser.email,
|
||||
azureAdId: azureUser.azureAdId,
|
||||
});
|
||||
}
|
||||
|
||||
if (!user || !user.isActive) {
|
||||
res.redirect("/login?error=" + encodeURIComponent("Compte inactif ou introuvable"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Mettre \u00e0 jour lastSignedIn
|
||||
const db = await (await import("../db")).getDb();
|
||||
if (db) {
|
||||
const { localUsers } = await import("../../drizzle/schema");
|
||||
const { eq } = await import("drizzle-orm");
|
||||
await db.update(localUsers).set({ lastSignedIn: new Date() }).where(eq(localUsers.id, user.id));
|
||||
}
|
||||
|
||||
// G\u00e9n\u00e9rer le token JWT local et le stocker dans le cookie
|
||||
const token = await generateLocalToken(user.id, user.role);
|
||||
res.cookie("veille_local_auth", token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
sameSite: "lax",
|
||||
path: "/",
|
||||
maxAge: 7 * 24 * 60 * 60 * 1000,
|
||||
});
|
||||
|
||||
// Retourner les infos user en JSON pour que le frontend hydrate LocalAuthContext
|
||||
const userPayload = JSON.stringify({
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
username: user.username ?? null,
|
||||
email: user.email ?? null,
|
||||
role: user.role,
|
||||
});
|
||||
// Rediriger vers une page de callback qui hydrate le contexte
|
||||
res.redirect(`/azure-callback?user=${encodeURIComponent(userPayload)}`);
|
||||
} catch (err: any) {
|
||||
console.error("[Azure AD] Erreur callback:", err.message);
|
||||
res.redirect("/login?error=" + encodeURIComponent("Erreur d'authentification Microsoft"));
|
||||
}
|
||||
});
|
||||
app.use(
|
||||
"/api/trpc",
|
||||
createExpressMiddleware({ router: appRouter, createContext })
|
||||
|
||||
Reference in New Issue
Block a user