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:
76
server/azureAuth.ts
Normal file
76
server/azureAuth.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import { ConfidentialClientApplication } from "@azure/msal-node";
|
||||
|
||||
// ─── Azure AD Authentication ──────────────────────────────────────────────────
|
||||
|
||||
let msalClient: ConfidentialClientApplication | null = null;
|
||||
|
||||
/**
|
||||
* Vérifie que les 3 variables d'environnement Azure AD sont présentes
|
||||
*/
|
||||
export function isAzureAdConfigured(): boolean {
|
||||
return !!(
|
||||
process.env.AZURE_AD_TENANT_ID &&
|
||||
process.env.AZURE_AD_CLIENT_ID &&
|
||||
process.env.AZURE_AD_CLIENT_SECRET
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Instancie le client MSAL (lazy, singleton)
|
||||
*/
|
||||
function getMsalClient(): ConfidentialClientApplication {
|
||||
if (!isAzureAdConfigured()) {
|
||||
throw new Error("Azure AD is not configured");
|
||||
}
|
||||
if (!msalClient) {
|
||||
msalClient = new ConfidentialClientApplication({
|
||||
auth: {
|
||||
clientId: process.env.AZURE_AD_CLIENT_ID!,
|
||||
authority: `https://login.microsoftonline.com/${process.env.AZURE_AD_TENANT_ID}`,
|
||||
clientSecret: process.env.AZURE_AD_CLIENT_SECRET!,
|
||||
},
|
||||
});
|
||||
}
|
||||
return msalClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne l'URL de redirection Azure AD pour l'utilisateur
|
||||
*/
|
||||
export async function getAzureAuthUrl(): Promise<string> {
|
||||
const client = getMsalClient();
|
||||
const redirectUri =
|
||||
process.env.AZURE_AD_REDIRECT_URI ||
|
||||
"http://localhost:3000/api/auth/azure/callback";
|
||||
return client.getAuthCodeUrl({
|
||||
scopes: ["user.read"],
|
||||
redirectUri,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Échange le code OAuth contre un token et retourne les infos utilisateur.
|
||||
* azureAdId = homeAccountId = "{objectId}.{tenantId}" (~73 caractères)
|
||||
*/
|
||||
export async function handleAzureCallback(code: string) {
|
||||
const client = getMsalClient();
|
||||
const redirectUri =
|
||||
process.env.AZURE_AD_REDIRECT_URI ||
|
||||
"http://localhost:3000/api/auth/azure/callback";
|
||||
|
||||
const response = await client.acquireTokenByCode({
|
||||
code,
|
||||
scopes: ["user.read"],
|
||||
redirectUri,
|
||||
});
|
||||
|
||||
if (!response || !response.account) {
|
||||
throw new Error("Failed to acquire token from Azure AD");
|
||||
}
|
||||
|
||||
return {
|
||||
azureAdId: response.account.homeAccountId, // "{objectId}.{tenantId}"
|
||||
email: response.account.username, // UPN (ex: user@domain.com)
|
||||
name: response.account.name || response.account.username,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user