Vous êtes ici : Comprendre — comment on entre dans la suite (les flux d’authentification).
Comprendre tous les flux d’authentification de GS-Apps — MSAL, OAuth PKCE, Managed Identity.
Lecture 15 min. Audience : devs, auditeurs sécurité.
Date : 2026-07-07 | Version : 1.2 — mise au gabarit Diátaxis ; retrait des identifiants internes (site public) ; apps alignées réalité juillet 2026 ; Système A (groups) marqué retiré — api-portail résout ses rôles en Système C (vérifié dans le code)
Modèle d'autorisation — voir la page dédiée
Cette page décrit les flux d’authentification (MSAL / PKCE / Managed Identity), toujours d’actualité. Le modèle d’autorisation , lui, a évolué depuis avril 2026 : le Système C (ug.UserCompanyBcRoles) est désormais en production comme source unique des rôles, avec délégation à deux étages et corporate-admin data-driven . Pour le modèle à jour, voir Modèle d’accès .
GS-Apps a un seul système d’autorisation en production (+ 2 historiques retirés) :
Système
Pour quoi
Statut
Azure AD claims groups (Système A)
(retiré — api-portail porté en Système C)
—
ug.UserAppRoles (Système B)
(retiré 2026-06-22)
—
ug.UserCompanyBcRoles (Système C)
Source unique des rôles , multi-company
En prod (admin, hub, inv, ug, portail)
Azure AD reste la source de vérité pour l’identité (qui tu es) ;
l’autorisation (ce que tu as le droit de faire) vit en BD ug.
Flux scan QR public Un signaleur scanne un sticker QR avec son téléphone personnel. Le navigateur appelle api-portail sur la page publique /p/QR. api-portail fait un SELECT des colonnes non-PII dans ptl.Stickers et renvoie une page HTML mobile rendue côté serveur. Aucune session utilisateur n’est créée. Signaleur téléphone personnel api-portail SSR mobile · public ptl.Stickers colonnes non-PII scan QR · GET /p/QR-… SELECT (non-PII) HTML mobile aucune session utilisateur — la page /p/:qrCode est publique Le scan public : aucune authentification, aucune PII — seules les colonnes non sensibles de ptl.Stickers sont servies.
Aucune authentification requise. La page mobile /p/QR-XXXXX est publique.
Flux :
Signaleur scanne sticker QR avec téléphone
Browser → https://portail.groupesignalisation.ca/p/QR-00001
api-portail → SQL SELECT sur ptl.Stickers (colonnes non-PII exposées publiquement)
api-portail → SSR HTML mobile-first
Signaleur clique « Santé et sécurité » → redirection vers l’intranet de Groupe Signalisation
Sécurité : aucune donnée personnelle sur la surface publique ; conformité Loi 25 pour cette zone — détail dans PUBLIC_VS_PRIVATE.md sur GitHub .
Flux MSAL — SPA React L’utilisateur ouvre une SPA React (hub, admin, inv ou ug). La SPA fait un loginRedirect ou une acquisition silencieuse vers Microsoft Entra ID, qui retourne un JWT avec l’audience API. La SPA envoie ce JWT en Bearer aux APIs internes, qui valident la signature et l’issuer puis résolvent les rôles dans ug.UserCompanyBcRoles. Microsoft Entra ID MFA par policy SPA React hub · admin · inv · ug APIs internes valide signature · audience · issuer rôles : ug.UserCompanyBcRoles 1 · loginRedirect 2 · JWT (aud API) 3 · Bearer JWT Le flux MSAL des SPAs : connexion par redirection, JWT d’audience API, validation complète côté backend — les rôles viennent de la BD, pas du jeton.
Stack : MSAL.js navigateur + Azure AD + audience JWT partagée.
Flux :
Gestionnaire ouvre https://hub.groupesignalisation.ca/
SPA React détecte pas de session → MSAL loginRedirect() (pattern standard monorepo — éviter loginPopup() en prod)
Azure AD prompt MFA si configuré → JWT retourné au browser
Cache token MSAL + token aud=api://<client_id> envoyé en Bearer aux APIs
APIs valident JWT (signature, audience, issuer v1+v2, expiration)
Lookup ug.UserCompanyBcRoles pour autoriser/refuser
Sécurité : cache MSAL sécurisé, refresh silencieux, MFA par policy AAD.
Flux OAuth Authorization Code + PKCE (api-portail) L’utilisateur accède à api-portail par son navigateur. Le serveur SSR fait un échange Authorization Code avec PKCE auprès de Microsoft Entra ID, reçoit les tokens, et pose des cookies HttpOnly dans le navigateur de l’utilisateur. Utilisateur navigateur api-portail SSR · sans secret client Microsoft Entra ID redirectUri strict HTTPS Auth Code + PKCE tokens cookies HttpOnly · SameSite=Lax Le flow OIDC d’api-portail : Authorization Code + PKCE (client public, sans secret), session ensuite portée par un cookie httpOnly.
Stack : OAuth Authorization Code + PKCE côté serveur Node.js (api-portail).
Pourquoi pas MSAL : api-portail est SSR (server-side), pas SPA. PKCE est le pattern moderne pour serveurs publics sans secret client.
Sécurité : PKCE-only, HTTPS forcé, cookies HttpOnly + SameSite=Lax, redirectUri strictement listé dans App Registration.
Flux Managed Identity vers Azure SQL Les apps Node (api-portail et les SPAs backend hub, admin, inv, ug) utilisent chacune leur Managed Identity system-assigned. La connexion SQL passe par le mode azure-active-directory-default vers Azure SQL GS_Apps — aucun mot de passe SQL dans la configuration. APPS NODE api-portail hub · admin · inv · ug Managed Identity system-assigned · une par app azure-active-directory-default Azure SQL GS_Apps · zéro mot de passe Service-to-service : chaque app Node porte sa Managed Identity ; le driver renouvelle les jetons tout seul. Détail : Managed Identity .
Stack : Managed Identity System-Assigned + tedious 16+ azure-active-directory-default.
Sécurité : aucun mot de passe SQL en App Settings pour GS_Apps ; MI scopée par app ; journalisation côté Azure (voir ADR-033 ).
Statut : RETIRÉ. Historiquement, api-portail dérivait le rôle des claims groups du JWT (trois groupes de sécurité Entra). Le portail a été porté en Système C : le rôle ne vient plus des groupes Azure AD, mais de ug.UserCompanyBcRoles (module Portail) — même source unique que les autres apps.
Statut : DÉCOMMISSIONNÉ 2026-06-22. Table orpheline, 0 lecteur runtime. Migration DROP 136 écrite HORS SQL_FILES — application prod = David db_owner. Section conservée pour historique ADR-055 / SUB-D.
Cible : admin, hub, inv, ug, portail + Console UG (control plane).
Matrice : user_id × company_id × bc_key × role. Conçu pour multi-company UG (ADR-032 ).
Statut : source unique d’autorisation en production (fusion B→C complétée admin 2026-06-22).
Aspect
Système A (groups)
Système B (ug.UserAppRoles)
Système C (multi-company)
Source données
Azure AD
Azure SQL
Azure SQL
Multi-company
Non
Non
Oui
Granularité
App-level
App-level
App × BC × Compagnie
Gestion
Azure Portal UI
(retiré)
Console UG
Apps qui utilisent
(aucune — retiré)
(aucune — retiré)
admin, hub, inv, ug, portail
Statut
Retiré (portail porté en C)
Retiré 2026-06-22
Prod — source unique
La fusion B→C et le retrait de ug.UserAppRoles sont livrés (2026-06-22), et api-portail — dernier utilisateur du Système A (groups) — a été porté en Système C. Toutes les apps en production résolvent leurs rôles dans ug.UserCompanyBcRoles.
État de la migration multi-company ug.UserAppRoles (Système B) est retiré. ug.UserCompanyBcRoles (Système C) est la source unique en production. Toutes les apps — admin, hub, inv, ug et portail — résolvent leurs rôles en Système C. ug.UserAppRoles Système B — retiré ug.UserCompanyBcRoles Système C — prod, source unique Toutes les apps les cinq apps en production La migration est terminée : le Système C est l’unique source des rôles pour toutes les apps en production.
Implémenter ug.UserCompanyBcRoles en BD ✅
Migrer données depuis ug.UserAppRoles ✅ N/A (aucun utilisateur actif à migrer)
Modifier les middlewares pour lire ug.UserCompanyBcRoles ✅ (2026-06-22)
Retirer ug.UserAppRoles ✅ (Système B décommissionné)
Porter api-portail (Système A → C) ✅ (le rôle vient de la BD, plus des groupes)
Activer multi-company UG Phase 2+ (ADR-032 )
Couches de défense Quatre couches successives : l’identité (Azure AD avec MFA), l’authentification (MSAL, PKCE, Managed Identity), l’autorisation (Système C — la BD ug, source unique des rôles), puis l’audit, le réseau et les secrets. 1 · Identité Azure AD + MFA (Conditional Access) 2 · Authentification MSAL (SPA) · OAuth PKCE (SSR) · Managed Identity 3 · Autorisation Système C (BD ug) — source unique des rôles 4 · Audit · réseau · secrets journaux · HTTPS/VNet · zéro secret SQL Quatre couches successives — une porte franchie n’ouvre jamais la suivante toute seule.
Identité : Azure AD (MFA via Conditional Access)
Authentification : MSAL.js (SPA) + OAuth PKCE (SSR portail) + Managed Identity (service)
Autorisation : lookup BD ug (Système C — source unique des rôles)
Audit : ptl.AccessLog (futur, ADR-032 §5) + Azure SQL Auditing (à activer)
Réseau : HTTPS uniquement, VNet pour SOFI, NSG sortants
Secrets : pas de mot de passe SQL GS_Apps en App Settings (migration MI 2026-04-27, ADR-033 )
Loi 25 Québec
Art. 5 — accès limité. MI : identité par app, droits DB minimaux ; surface publique sans PII — SECURITY-SQL-ADMIN.md
ISO 27001
A.9.4 — accès privilégiés. ADR-033, fin du compte SQL administrateur partagé historique, break-glass documenté.
OWASP A04:2021
Insecure Design — OAuth PKCE, MI, pas de secret SQL en clair pour GS_Apps.