Aller au contenu

Stratégie d'authentification GS-Apps

Document de référence pour comprendre tous les flux d’auth de GS-Apps.
Lecture 15 min. Audience : devs, auditeurs sécurité.
Date : 2026-04-27 (mise à jour 2026-06-22) | Version : 1.1

GS-Apps utilise 2 systèmes d’autorisation en production (+ 1 historique retiré) :

SystèmePour quoiCible
Azure AD claims groupsRoutes Admin api-portailapi-portail (Phase 1)
ug.UserAppRoles (Système B)(retiré 2026-06-22)
ug.UserCompanyBcRoles (Système C)Multi-company UG — source unique des rôlesEn prod (admin, hub, inv, ug, portail)

Tous se basent sur Azure AD comme source de vérité pour l’identité (qui tu es).
La différence est où réside l’autorisation (ce que tu as le droit de faire).

Flux scan QR public
sequenceDiagram
participant S as Signaleur
participant B as Browser
participant P as api-portail
participant Q as SQL ptl.Stickers
S->>B: scan sticker QR
B->>P: GET /p/QR-XXXXX
P->>Q: SELECT sticker (non PII)
Q-->>P: métadonnées
P-->>B: SSR HTML mobile
Note over P,B: Aucune session utilisateur
Voir aussi : thème neutral / terminal

Exports D2 : docs/architecture/diagrams/rendered/neutral/auth-flow-public-scan.svg et docs/architecture/diagrams/rendered/terminal/auth-flow-public-scan.svg.

Source D2 sur GitHub

Aucune authentification requise. La page mobile /p/QR-XXXXX est publique.

Flux :

  1. Signaleur scanne sticker QR avec téléphone
  2. Browser → https://portail.groupesignalisation.ca/p/QR-00001
  3. api-portail → SQL SELECT sur ptl.Stickers (colonnes non-PII exposées publiquement)
  4. api-portail → SSR HTML mobile-first
  5. Signaleur clique « Santé et sécurité » → redirection vers intranet GS

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.

Cas 2 — Gestionnaire login via MSAL (apps existantes)

Section intitulée « Cas 2 — Gestionnaire login via MSAL (apps existantes) »
Flux MSAL SPA
sequenceDiagram
participant U as Utilisateur
participant SPA as SPA React
participant AD as Azure AD
participant API as APIs internes
U->>SPA: ouvre Hub/Admin/Inv/Fit
SPA->>AD: loginRedirect / silent token
AD-->>SPA: JWT (audience API)
SPA->>API: Bearer JWT
API->>API: valide + ug.UserCompanyBcRoles
Voir aussi : thème neutral / terminal

Exports D2 : docs/architecture/diagrams/rendered/neutral/auth-flow-msal.svg et docs/architecture/diagrams/rendered/terminal/auth-flow-msal.svg.

Source D2 sur GitHub

Stack : MSAL.js navigateur + Azure AD + audience JWT partagée.

Flux :

  1. Gestionnaire ouvre https://hub.groupesignalisation.ca/
  2. SPA React détecte pas de session → MSAL loginRedirect() (pattern standard monorepo — éviter loginPopup() en prod)
  3. Azure AD prompt MFA si configuré → JWT retourné au browser
  4. Cache token MSAL + token aud=api://<client_id> envoyé en Bearer aux APIs
  5. APIs valident JWT (signature, audience, issuer v1+v2, expiration)
  6. Lookup ug.UserCompanyBcRoles pour autoriser/refuser

Sécurité : cache MSAL sécurisé, refresh silencieux, MFA par policy AAD.

Cas 3 — Gestionnaire/Admin sur Portail (OAuth PKCE)

Section intitulée « Cas 3 — Gestionnaire/Admin sur Portail (OAuth PKCE) »
Flux OAuth PKCE (api-portail)
flowchart LR
U[Utilisateur] -->|navigateur| P[api-portail SSR]
P -->|Authorization Code + PKCE| AD[Azure AD]
AD -->|tokens| P
P -->|HttpOnly cookies| U
classDef interne fill:#dbeafe,stroke:#1e40af,color:#1e40af
class P,AD interne
Voir aussi : thème neutral / terminal

Exports D2 : docs/architecture/diagrams/rendered/neutral/auth-flow-oauth-pkce.svg et docs/architecture/diagrams/rendered/terminal/auth-flow-oauth-pkce.svg.

Source D2 sur GitHub

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.

Cas 4 — Service-to-Service (Managed Identity SQL)

Section intitulée « Cas 4 — Service-to-Service (Managed Identity SQL) »
Flux Managed Identity SQL
flowchart TB
subgraph Apps["Apps Node"]
  A1[api-portail]
  A2[gs-hub / admin / inv / fit]
end
MI[Managed Identity<br/>System-assigned]
SQL[(Azure SQL)]
Apps --> MI
MI -->|azure-active-directory-default| SQL
classDef interne fill:#dbeafe,stroke:#1e40af,color:#1e40af
class A1,A2,MI interne
Voir aussi : thème neutral / terminal

Exports D2 : docs/architecture/diagrams/rendered/neutral/auth-flow-managed-identity.svg et docs/architecture/diagrams/rendered/terminal/auth-flow-managed-identity.svg.

Source D2 sur GitHub

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).

Cible : api-portail uniquement.

Constantes dans apps/api-portail/src/middleware/requireAuth.ts :

const AZURE_GROUP_ADMIN = '7a9bf9f7-dde9-44ff-86c1-deee829462c4';
const AZURE_GROUP_GEST = 'e1594515-5d26-4b84-b14c-30f69d7d3ae6';
const AZURE_GROUP_USER = '8dd154cd-c43e-4fd8-aa4f-50f385d94486';

Gestion : Azure Portal → Entra ID → Groups → ajouter/retirer des membres.

AspectSystème A (groups)Système B (ug.UserAppRoles)Système C (multi-company)
Source donnéesAzure ADAzure SQLAzure SQL
Multi-companyNonNonOui
GranularitéApp-levelApp-levelApp × BC × Compagnie
GestionAzure Portal UI(retiré)Console UG
Apps qui utilisentapi-portail(aucune — retiré)admin, hub, inv, ug, portail
StatutProdRetiré 2026-06-22Prod

Stratégie de migration vers Système C — ✅ COMPLÉTÉE (admin, 2026-06-22)

Section intitulée « Stratégie de migration vers Système C — ✅ COMPLÉTÉE (admin, 2026-06-22) »

La fusion B→C et le retrait de ug.UserAppRoles sont livrés côté repo (mig 136 DROP écrite, application prod = STOP David). Reste : porter shophub en C.

État migration multi-company (2026-06-22)
flowchart LR
B[ug.UserAppRoles RETIRÉ] --> C[ug.UserCompanyBcRoles PROD]
C --> R[Reste: shophub → C]
classDef interne fill:#dbeafe,stroke:#1e40af,color:#1e40af
class B,C,R interne
Voir aussi : thème neutral / terminal

Exports D2 : docs/architecture/diagrams/rendered/neutral/multi-company-roadmap.svg et docs/architecture/diagrams/rendered/terminal/multi-company-roadmap.svg.

Source D2 sur GitHub

  1. Implémenter ug.UserCompanyBcRoles en BD ✅ (mig 69-71)
  2. Migrer données depuis ug.UserAppRoles ✅ N/A (gate vert : 0 user actif)
  3. Modifier middleware admin pour lire UCBR ✅ (resolveDisplayRole, 2026-06-22)
  4. Dropper ug.UserAppRoles ✅ ÉCRIT (mig 136, HORS SQL_FILES — STOP David)
  5. Porter shophub en C (reste)
  6. Activer multi-company UG Phase 2+ (ADR-032)
Couches de défense
flowchart TB
L1[Identité — Azure AD + MFA]
L2[Auth — MSAL / PKCE / MI]
L3[AuthZ — groups / DIM / futur C]
L4[Audit + réseau + secrets]
L1 --> L2 --> L3 --> L4
classDef layer fill:#fef2f2,stroke:#D92231,stroke-width:2px,color:#7f1d1d
class L1,L2,L3,L4 layer
Voir aussi : thème neutral / terminal

Exports D2 : docs/architecture/diagrams/rendered/neutral/auth-security-layers.svg et docs/architecture/diagrams/rendered/terminal/auth-security-layers.svg.

Source D2 sur GitHub

  1. Identité : Azure AD (MFA via Conditional Access)
  2. Authentification : MSAL.js (SPA) + OAuth PKCE (SSR portail) + Managed Identity (service)
  3. Autorisation : Claims / lookup SQL selon système A/B/C
  4. Audit : ptl.AccessLog (futur, ADR-032 §5) + Azure SQL Auditing (à activer)
  5. Réseau : HTTPS uniquement, VNet pour SOFI, NSG sortants
  6. 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 partage CloudSA34b30667, break-glass documenté.

OWASP A04:2021

Insecure Design — OAuth PKCE, MI, pas de secret SQL en clair pour GS_Apps.