Files
EME_APP/eme-backend/src/services/authentication.service.ts
T
2026-07-23 12:35:21 +02:00

69 lines
1.8 KiB
TypeScript

import { env } from '../config/env';
import { AppError } from '../errors/app-error';
import {
findByEmail,
findByMicrosoftId,
UtilisateurAvecRole,
} from '../repositories/utilisateur.repository';
import { AuthenticatedUser } from '../types/authenticated-user';
import { verifyAzureAccessToken } from './azure-token.service';
export interface AuthenticationHeaders {
authorization?: string;
demoEmail?: string;
}
function toAuthenticatedUser(utilisateur: UtilisateurAvecRole): AuthenticatedUser {
return {
id: utilisateur.id,
email: utilisateur.email,
roleCode: utilisateur.role.code,
campusId: utilisateur.campusId,
};
}
function bearerToken(authorization: string | undefined): string {
const match = authorization?.match(/^Bearer\s+(\S+)$/i);
if (!match) {
throw new AppError(401, 'Jeton Bearer requis');
}
return match[1];
}
async function authenticateDemo(email: string | undefined): Promise<UtilisateurAvecRole | null> {
if (!email) {
throw new AppError(401, 'En-tete x-user-email requis en mode demo');
}
return findByEmail(email.trim().toLowerCase());
}
async function authenticateAzure(
authorization: string | undefined,
): Promise<UtilisateurAvecRole | null> {
const identity = await verifyAzureAccessToken(bearerToken(authorization));
const byMicrosoftId = await findByMicrosoftId(identity.microsoftId);
if (byMicrosoftId) {
return byMicrosoftId;
}
return findByEmail(identity.email);
}
export async function authenticateUser(
headers: AuthenticationHeaders,
): Promise<AuthenticatedUser> {
const utilisateur =
env.auth.mode === 'azure'
? await authenticateAzure(headers.authorization)
: await authenticateDemo(headers.demoEmail);
if (!utilisateur || !utilisateur.actif) {
throw new AppError(401, 'Utilisateur non reconnu');
}
return toAuthenticatedUser(utilisateur);
}