Backend du service AssistantCore.
Le projet fournit actuellement :
- une API ASP.NET Core;
- une authentification Microsoft Entra ID multitenant;
- une separation des donnees par organisation;
- une base SQL Server initialisee avec Flyway;
- une collection Postman pour tester les endpoints authentifies.
- .NET SDK 10;
- Docker Desktop avec Docker Compose;
- Postman pour les tests OAuth 2.0;
- un acces a Microsoft Entra ID pour tester l'authentification.
Verifier les installations :
dotnet --version
docker --version
docker compose versionPour configurer CERTIF dans Azure Container Apps, suivre le guide Installer CERTIF dans Azure Container Apps.
dotnet restore Solution.sln
dotnet build Solution.slnCreer un fichier .env.database a la racine :
SQL_SERVER_PASSWORD=Password123!
SQLPAD_ADMIN_EMAIL=admin@local.dev
SQLPAD_ADMIN_PASSWORD=Password123!Ces identifiants servent uniquement au developpement local. Le fichier est ignore par Git et ne doit pas etre utilise en production.
bash scripts/start-database-stack.shCe script demarre :
- SQL Server sur
localhost:1433; - Flyway, qui cree la base et applique les migrations;
- SQLPad sur
http://localhost:3000.
Verifier les conteneurs :
docker compose --env-file .env.database psSi necessaire, approuver le certificat HTTPS local :
dotnet dev-certs https --trustDemarrer le service :
dotnet run --project AssistantCore.Service --launch-profile httpsSwagger est disponible sur :
https://localhost:7292/swagger
Ce mode utilise un JWT local et un serveur WireMock pour Microsoft 365,
Azure AI Search, les embeddings et OpenAI. Les valeurs factices sont versionnées
dans les fichiers appsettings.Local.json; elles ne sont pas lues depuis les
user-secrets.
bash scripts/start-local-wiremock.shLe script fonctionne tel quel sous Linux, macOS et Windows avec Git Bash. Aucune variable d'environnement ni fonction preparatoire n'est necessaire.
Le script :
- démarre SQL Server et recrée la base isolée
AssistantCoreLocalDb; - crée une organisation locale et son administrateur de manière idempotente;
- démarre WireMock sur
https://localhost:9443; - génère un JWT valable huit heures dans
.local/local-jwt.txt; - démarre l'API et le Worker avec l'environnement
Local.
Le JWT est également affiché au démarrage. Dans Swagger, utiliser Authorize,
coller uniquement le JWT, puis appeler GET /api/core/authenticateUser pour
valider l'identité locale.
La SPA utilise ce mode par défaut. Après le démarrage du présent script,
démarrer le dépôt Assistant.SPA avec npm start, ouvrir /login, puis choisir
Continuer comme administrateur local. La SPA récupère alors le JWT auprès de
WireMock et le conserve dans le sessionStorage de l'onglet. Le JWT disparaît
à la déconnexion ou lorsque l'onglet est fermé.
Dans Postman, importer la collection et l'environnement local du dossier
postman, puis sélectionner l'environnement AssistantCore Local. Aucune copie
du JWT n'est nécessaire : avant chaque requête, la collection récupère
automatiquement le token à l'adresse https://localhost:9443/local-auth/token
et ajoute l'en-tête Authorization. Cette automatisation est active uniquement
lorsque authentication_mode vaut LocalJwt.
Le mode LocalJwt est refusé par l'application dans tout environnement autre
que Local.
La base AssistantCoreLocalDb est supprimée et recréée à chaque lancement du
mode WireMock. La base AssistantCoreDb, utilisée par le mode connecté, n'est
pas réinitialisée.
Ce mode conserve Microsoft Entra, Microsoft Graph, Azure AI Search et OpenAI.
Il utilise les vrais secrets configurés avec dotnet user-secrets comme décrit
dans la section suivante.
Dans Postman, définir authentication_mode à MicrosoftEntra pour conserver
le parcours OAuth 2.0 configuré dans la collection.
bash scripts/start-local-live.shLe script vérifie l'URL webhook publique avant de démarrer le Worker. Si elle ne répond pas correctement, il démarre automatiquement ngrok avec l'URL réservée de l'environnement Certif. L'agent ngrok doit donc être authentifié localement et cette URL doit appartenir au compte utilisé.
Pour tester également le vrai parcours Microsoft dans la SPA locale, renseigner
ses identifiants publics Entra dans
public/assets/config/config.certification.json du dépôt Assistant.SPA, puis
lancer npm run start:entra. Aucun client secret n'est utilisé par la SPA.
Le parcours de test démarre l'API et le Worker Microsoft 365 dans le même terminal. Le DOCX reste téléversé dans une bibliothèque SharePoint; il n'est pas envoyé directement à l'API.
Configurer les secrets nécessaires à l'API et au Worker. Les deux projets
partagent le même magasin user-secrets :
dotnet user-secrets --project AssistantCore.Service set "Microsoft365:ClientId" "<client-id>"
dotnet user-secrets --project AssistantCore.Service set "Microsoft365:ClientSecret" "<secret>"
dotnet user-secrets --project AssistantCore.Service set "Microsoft365:ClientStateHmacKey" "<32+ caracteres aleatoires>"
dotnet user-secrets --project AssistantCore.Service set "Microsoft365:SharePointCertificatePath" "<absolute-pfx-path>"
dotnet user-secrets --project AssistantCore.Service set "Microsoft365:SharePointCertificatePassword" "<pfx-password>"
dotnet user-secrets --project AssistantCore.Service set "Microsoft365:EmbeddingApiKey" "<azure-openai-embedding-api-key>"
dotnet user-secrets --project AssistantCore.Service set "Microsoft365:OcrEndpoint" "https://<vision-resource>.cognitiveservices.azure.com"
dotnet user-secrets --project AssistantCore.Service set "Microsoft365:OcrApiKey" "<azure-vision-key>"
dotnet user-secrets --project AssistantCore.Service set "AzureSearch:Endpoint" "https://<service>.search.windows.net"
dotnet user-secrets --project AssistantCore.Service set "AzureSearch:IndexName" "microsoft-content-dev"
dotnet user-secrets --project AssistantCore.Service set "AzureSearch:ApiKey" "<azure-search-api-key>"
dotnet user-secrets --project AssistantCore.Service set "AzureSearch:PlanningModelApiKey" "<azure-openai-planning-api-key>"LocalLive utilise m365-text-embedding-3-small pour l’indexation et la
vectorisation des requêtes. Sa Knowledge Base DEV possède un nom distinct de
celle de CERTIF. Le raisonnement auto est utilisé par défaut : Azure commence
par une recherche légère et active la planification si les résultats sont
insuffisants. Pour forcer un mode, définir temporairement par exemple :
AzureSearch__KnowledgeBaseRetrievalReasoningEffort=low bash scripts/start-local-live.shLes valeurs acceptées sont minimal, low et auto.
La connexion SQL n'a pas besoin d'être ajoutée aux user-secrets. Le script
lit SQL_SERVER_PASSWORD dans .env.database, construit la chaîne de
connexion en mémoire et la transmet à l'API et au Worker par variable
d'environnement.
Azure Service Bus reste désactivé en développement local. Les demandes de
synchronisation sont persistées dans SQL, puis réclamées directement par le
Worker. En environnement Azure, activer ServiceBus:Enabled uniquement
lorsque le namespace, les files et leurs consommateurs sont déployés.
La définition FoundryAgent doit pointer vers une version d’agent réellement accessible
avec la clé configurée. L'App Registration Microsoft 365 doit aussi accepter
exactement ce callback Web :
https://localhost:7292/api/microsoft365/consent/callback
Créer .env.database comme indiqué plus haut, puis exécuter :
bash scripts/start-local-live.shLe script démarre SQL Server, applique les migrations, compile la solution,
configure les valeurs locales non sensibles, puis démarre l'API et le Worker.
Utiliser Ctrl+C pour arrêter les deux processus.
Importer de nouveau la collection et l'environnement Postman du dépôt, puis :
- exécuter
AuthenticateUseravec un membre AssistantCoreAdmin; - exécuter
Start Consentet ouvrirauthorization_urldans un navigateur; - renseigner
site_id, puis exécuterRegister Site; - exécuter
Get Drives; la bibliothèque nommée pardrive_nameest placée automatiquement dansdrive_id; - téléverser le DOCX dans cette bibliothèque SharePoint;
- exécuter
Enable Driveet attendre quelques secondes pendant l'indexation; - renseigner
question, puis exécuterSend Message.
La réponse doit contenir le texte généré et le DOCX dans sources. Pour une
première synchronisation, le Worker interroge directement les tâches SQL; un
tunnel HTTPS et les webhooks ne sont nécessaires que pour recevoir ensuite les
modifications SharePoint automatiquement.
Microsoft Entra ID est le service cloud de gestion des identites et des acces
de Microsoft. Il portait auparavant le nom Azure Active Directory ou
Azure AD.
Une entreprise peut utiliser Entra ID pour gerer :
- ses utilisateurs;
- leurs mots de passe et methodes de connexion;
- l'authentification multifacteur, aussi appelee MFA;
- les groupes et certaines permissions;
- les applications auxquelles les utilisateurs peuvent acceder;
- les politiques de securite et d'acces conditionnel;
- la connexion unique, aussi appelee Single Sign-On ou SSO.
Dans le contexte d'AssistantCore, Entra ID joue le role de fournisseur d'identite. Cela signifie que Microsoft confirme l'identite de l'utilisateur et remet a l'application un token signe qui contient les informations necessaires pour identifier cet utilisateur.
AssistantCore ne recoit donc jamais le mot de passe Microsoft de l'utilisateur. Le mot de passe, la MFA et les autres mecanismes de connexion sont geres par Microsoft Entra ID.
Microsoft Entra ID ne doit pas etre confondu avec un abonnement Azure :
- un tenant Entra ID est un annuaire qui contient des identites et des applications;
- un abonnement Azure sert a payer et organiser des ressources Azure comme des serveurs, bases de donnees ou comptes de stockage;
- ce projet utilise actuellement Entra ID pour l'identite, meme si l'API est executee localement et n'est pas encore hebergee dans Azure.
AssistantCore est concu comme une application SaaS destinee a plusieurs compagnies. Les utilisateurs doivent pouvoir se connecter avec le compte professionnel deja gere par leur entreprise.
Utiliser Entra ID permet notamment :
- d'eviter de creer un systeme de mots de passe propre a AssistantCore;
- de laisser chaque compagnie gerer ses utilisateurs et ses politiques de connexion;
- de profiter de la MFA et des politiques de securite de la compagnie;
- d'identifier de maniere fiable l'utilisateur et son entreprise;
- de permettre une future experience SSO;
- de retirer automatiquement la possibilite de se connecter lorsque le compte professionnel est bloque dans Entra ID;
- de supporter plusieurs entreprises avec une seule inscription d'API multitenant.
Le principe general est le suivant :
Utilisateur de la compagnie
|
| connexion Microsoft
v
Microsoft Entra ID
|
| access token signe
v
Postman, puis le futur client UI
|
| Authorization: Bearer <token>
v
AssistantCore API
|
| tid -> organisation
| oid -> membre
v
AssistantCoreDb
En developpement, Postman remplace temporairement le futur client UI. Postman ne valide pas lui-meme le mot de passe et ne fabrique pas le token : il ouvre la page de connexion Microsoft, recoit le resultat du flux OAuth 2.0 et transmet le token obtenu a l'API.
Un tenant est l'annuaire d'une organisation dans Microsoft Entra ID.
Il contient notamment :
- les utilisateurs de l'organisation;
- les groupes;
- les inscriptions d'applications appartenant a l'organisation;
- les applications externes autorisees par l'organisation;
- les politiques de securite et de consentement.
Chaque tenant possede un identifiant unique appele Tenant ID. Dans un access
token, cet identifiant apparait dans le claim tid.
AssistantCore utilise tid pour determiner a quelle compagnie appartient la
requete. La valeur doit correspondre a Organization.ExternalTenantId dans la
base de donnees.
Un utilisateur est un compte present dans un tenant Entra ID. Il possede un
identifiant d'objet unique dans ce tenant, appele Object ID.
Dans le token, cet identifiant apparait dans le claim oid. AssistantCore
utilise la combinaison de l'organisation et de oid pour trouver ou creer le
membre interne correspondant.
Deux utilisateurs appartenant a deux tenants differents peuvent avoir des adresses similaires, mais ils restent des identites distinctes. L'email ne doit donc pas servir seul comme identifiant de securite.
Une inscription d'application, ou App registration, decrit une application
connue par Microsoft Entra ID.
Elle definit notamment :
- son
Application (client) ID; - les types de comptes qui peuvent l'utiliser;
- ses Redirect URIs;
- les permissions qu'elle demande;
- les scopes qu'elle expose;
- ses secrets ou certificats lorsqu'elle est un client confidentiel.
Le projet utilise deux inscriptions :
AssistantCore API, qui represente la ressource protegee;AssistantCore Postman, qui represente le client demandant un token.
Une inscription d'application est une configuration. Elle n'est ni un utilisateur, ni le code de l'application, ni un serveur Azure.
Lorsqu'un tenant client autorise une application multitenant, Entra ID cree une representation locale de cette application dans le tenant client.
Cette representation est appelee :
Enterprise applicationdans le portail;service principaldans le modele technique Entra ID.
L'App registration principale reste dans le tenant fournisseur. Le service principal permet au tenant client de controler localement l'acces a cette application sans devenir proprietaire de son inscription principale.
Le Client ID est l'identifiant public d'une inscription d'application.
Il indique a Entra ID quelle application participe au flux. Ce n'est pas un mot de passe et il peut apparaitre dans une configuration versionnee.
AssistantCore utilise deux Client IDs differents :
API_CLIENT_IDidentifie l'API et son audience;POSTMAN_CLIENT_IDidentifie le client qui demande le token.
Le Client Secret est une valeur confidentielle utilisee par un client pour prouver son identite au endpoint de token.
Dans l'environnement actuel, le secret appartient a l'inscription
AssistantCore Postman. Il ne s'agit pas d'un mot de passe utilisateur et il
ne donne pas, a lui seul, acces aux donnees d'un utilisateur.
Le secret ne doit jamais etre ajoute au depot. Une application UI executee dans un navigateur ou installee sur un appareil ne peut pas conserver un secret de maniere fiable; le futur client UI utilisera donc PKCE plutot qu'un secret embarque.
Un scope represente une action qu'une application cliente demande le droit d'effectuer.
AssistantCore expose actuellement :
api://<API_CLIENT_ID>/access_as_user
access_as_user signifie que Postman appelle l'API au nom de l'utilisateur
connecte. Entra ID authentifie l'utilisateur, mais l'API doit encore decider
ce que cet utilisateur a le droit de faire.
Le consentement est l'autorisation donnee a une application cliente pour utiliser certaines permissions.
Selon les politiques du tenant, le consentement peut etre accorde :
- par l'utilisateur pour lui-meme;
- par un administrateur pour toute l'organisation.
Le consentement ne remplace pas l'authentification et ne donne pas
automatiquement le role Admin dans AssistantCore.
Un access token est une preuve temporaire signee par Microsoft Entra ID. Le client le transmet a l'API dans le header :
Authorization: Bearer <access_token>Le token contient notamment :
aud, la ressource a laquelle le token est destine;iss, l'autorite qui a emis le token;tid, l'identifiant du tenant;oid, l'identifiant de l'utilisateur dans ce tenant;- des informations de profil selon les scopes demandes;
scp, les permissions deleguees accordees;- une date d'expiration.
Le token n'est pas une simple chaine d'identification. Il donne temporairement acces a l'API avec les droits de l'utilisateur et doit etre protege comme une information sensible.
Microsoft Entra ID est responsable de :
- connecter l'utilisateur;
- verifier ses informations de connexion;
- appliquer la MFA et les politiques Entra;
- emettre et signer le token;
- fournir les claims d'identite;
- gerer le consentement OAuth.
AssistantCore est responsable de :
- valider que le token est destine a l'API;
- retrouver l'organisation avec
tid; - refuser les tenants qui ne sont pas inscrits dans la plateforme;
- retrouver ou creer le membre avec
oid; - verifier que l'organisation et le membre sont actifs;
- attribuer et verifier les roles internes
AdminetUser; - isoler les donnees entre les organisations.
Cette separation est importante : etre authentifie par Microsoft ne signifie pas automatiquement avoir acces a AssistantCore. Le tenant doit etre inscrit dans la base et le membre doit respecter les regles internes de l'application.
Le tenant fournisseur represente l'entreprise qui construit et exploite
AssistantCore. Il possede les inscriptions AssistantCore API et
AssistantCore Postman.
Le tenant client fictif represente une compagnie externe qui achete ou utilise le produit. Il possede ses propres utilisateurs et autorise l'application multitenant du fournisseur.
Utiliser deux tenants permet de tester un vrai scenario SaaS :
- l'utilisateur appartient reellement a une autre organisation;
- le token contient le
tiddu client fictif; - le consentement doit etre accorde dans le tenant client;
- l'application d'entreprise est creee chez le client;
- AssistantCore doit faire correspondre ce tenant a une organisation interne;
- les donnees et les roles restent propres a cette organisation.
Tester uniquement avec le tenant fournisseur masquerait plusieurs problemes
possibles : mauvaise configuration multitenant, consentement externe absent,
mauvais tid, service principal manquant ou melange de donnees entre clients.
Le scenario actuel reproduit un SaaS utilise par plusieurs compagnies.
Il utilise deux tenants Microsoft Entra ID :
- Le tenant fournisseur represente notre compagnie. Il contient les inscriptions d'applications de l'API et du client Postman.
- Le tenant client represente une compagnie fictive. Il contient les utilisateurs qui se connectent a AssistantCore comme employes d'un client.
L'API accepte les comptes professionnels provenant de plusieurs organisations.
Le claim tid du token identifie la compagnie et le claim oid identifie
l'utilisateur dans cette compagnie.
Cette procedure est utile lorsqu'un developpeur veut recreer un environnement complet et isole. Les noms affiches ci-dessous sont seulement des exemples.
Creer deux tenants Microsoft Entra ID :
AssistantCore Dev, qui represente le fournisseur;Contoso Test, qui represente une compagnie cliente fictive.
Dans le tenant client, creer au moins un utilisateur de test avec lequel effectuer la connexion.
Un tenant est un annuaire Entra ID. Un compte utilisateur appartient a un tenant; les deux notions ne doivent pas etre confondues.
Dans le tenant fournisseur :
- Ouvrir le centre d'administration Microsoft Entra.
- Selectionner le tenant fournisseur
AssistantCore Dev. - Ouvrir
Identity > Applications > App registrations. - Selectionner
New registration. - Utiliser le nom
AssistantCore API. - Dans
Supported account types, selectionnerAccounts in any organizational directory. - Ne pas ajouter de Redirect URI : l'API ne connecte pas directement l'utilisateur dans un navigateur.
- Selectionner
Register. - Dans
Overview, noter la valeurApplication (client) ID. Cette valeur sera appeleeAPI_CLIENT_IDdans la suite.
L'inscription est multitenant : une compagnie cliente peut donc obtenir un token pour cette API sans que l'inscription principale soit recreee dans son propre tenant.
Dans l'inscription AssistantCore API :
- Ouvrir
Expose an API. - A cote de
Application ID URI, selectionnerAdd. - Conserver la valeur proposee
api://<API_CLIENT_ID>et sauvegarder. - Selectionner
Add a scope. - Utiliser
access_as_usercommeScope name. - Selectionner
Admins and userspourWho can consentdans l'environnement de developpement. - Utiliser un nom de consentement explicite, par exemple
Access AssistantCore API. - Expliquer dans les descriptions que l'application agit au nom de l'utilisateur connecte.
- Conserver
StateaEnabledet selectionnerAdd scope.
Le nom complet de la permission devient :
api://<API_CLIENT_ID>/access_as_user
Il s'agit d'une permission deleguee : l'application cliente appelle l'API au
nom d'un utilisateur connecte. Il ne s'agit pas du flux Client Credentials,
qui representerait une application sans utilisateur.
Reporter l'identifiant de l'API dans AssistantCore.Service/appsettings.json :
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "organizations",
"ClientId": "<API_CLIENT_ID>",
"Audience": "<API_CLIENT_ID>"
}Les identifiants de client et de tenant ne sont pas des secrets. Les secrets, certificats et mots de passe ne doivent jamais etre ajoutes au depot.
Le projet ne possede pas encore de client UI. Postman joue temporairement le role de l'application cliente : il ouvre la connexion Microsoft, recupere un code d'autorisation, l'echange contre un access token et utilise ce token pour appeler AssistantCore.
Toujours dans le tenant fournisseur AssistantCore Dev :
- Retourner dans
App registrationset selectionnerNew registration. - Utiliser le nom
AssistantCore Postman. - Dans
Supported account types, selectionnerAccounts in any organizational directory. - Dans
Redirect URI, selectionner la plateformeWeb. - Entrer exactement
https://oauth.pstmn.io/v1/callback. - Selectionner
Register. - Dans
Overview, noter la valeurApplication (client) ID. Cette valeur sera appeleePOSTMAN_CLIENT_ID.
L'inscription Postman est distincte de l'inscription API :
AssistantCore APIrepresente la ressource protegee qui valide le token;AssistantCore Postmanrepresente le client qui demande et utilise le token.
Le POSTMAN_CLIENT_ID doit etre utilise dans le champ Client ID de Postman.
Le API_CLIENT_ID sert dans le scope et dans la configuration du backend.
Intervertir les deux identifiants produit un token avec une mauvaise audience
ou une erreur de consentement.
Dans l'inscription AssistantCore Postman :
- Ouvrir
Certificates & secrets. - Ouvrir l'onglet
Client secrets. - Selectionner
New client secret. - Utiliser une description comme
Postman local development. - Choisir une expiration courte adaptee au developpement.
- Selectionner
Add. - Copier immediatement la colonne
Value.
La Value est le POSTMAN_CLIENT_SECRET. Elle n'est affichee qu'au moment de
la creation. La colonne Secret ID est seulement l'identifiant administratif
du secret et ne peut pas etre utilisee pour obtenir un token.
Le secret prouve l'identite de l'application Postman pendant l'echange du code d'autorisation. Il doit rester dans les valeurs locales de Postman : ne jamais l'ajouter au README, a la collection exportee, a un ticket, a une capture d'ecran ou a Git. Creer un nouveau secret lorsque celui-ci expire ou est expose, puis supprimer l'ancien dans Entra ID.
Cette configuration avec secret reproduit l'environnement Postman actuel. Le futur client UI, surtout s'il s'agit d'une SPA ou d'une application installee, ne devra pas embarquer ce secret. Il devra utiliser Authorization Code avec PKCE comme client public.
Dans l'inscription AssistantCore Postman :
- Ouvrir
API permissions. - Selectionner
Add a permission. - Selectionner
My APIs. - Selectionner
AssistantCore API. - Selectionner
Delegated permissions. - Cocher
access_as_useret selectionnerAdd permissions. - Selectionner
Grant admin consentpour le tenant fournisseur et confirmer.
La permission declare ce que Postman peut demander. Le consentement autorise effectivement cette application a agir au nom des utilisateurs pour ce scope.
Documentation officielle :
- https://learn.microsoft.com/entra/identity-platform/quickstart-configure-app-expose-web-apis
- https://learn.microsoft.com/entra/identity-platform/single-and-multi-tenant-apps
- https://learning.postman.com/docs/use/authorization/oauth-20/
L'inscription des applications reste dans le tenant fournisseur. Le tenant client recoit plutot une application d'entreprise, aussi appelee service principal, lorsqu'il accorde son consentement.
Dans le tenant client Contoso Test :
- Ouvrir
Identity > Overviewet copierTenant ID. Cette valeur sera appeleeTENANT_CLIENT_ID. - Creer au moins deux utilisateurs de test, par exemple un futur administrateur et un utilisateur standard.
- Dans Postman, commencer la demande d'un token avec un administrateur du tenant client.
- Accepter les permissions demandees et consentir pour l'organisation si le compte possede les droits necessaires.
- Verifier ensuite dans
Enterprise applicationsque l'application cliente existe dans le tenant.
Si les politiques du tenant bloquent le consentement utilisateur, un
administrateur Entra doit accorder explicitement le consentement. Cette etape
est distincte du role Admin stocke dans AssistantCore : un administrateur
Entra gere l'annuaire Microsoft, alors qu'un administrateur AssistantCore gere
les membres de son organisation dans l'application.
Un token Entra ID valide ne suffit pas. Le tenant client doit aussi correspondre a une organisation active dans AssistantCore.
Ouvrir SQLPad sur http://localhost:3000 et executer :
USE [AssistantCoreDb];
INSERT INTO [dbo].[Organization]
(
[Id],
[Name],
[IdentityProvider],
[ExternalTenantId],
[Status]
)
VALUES
(
NEWID(),
N'Contoso Test',
N'MicrosoftEntraId',
N'<TENANT_CLIENT_ID>',
N'Actif'
);ExternalTenantId doit correspondre exactement au claim tid du token.
Sinon, GET /api/core/authenticateUser retourne 403 Forbidden.
Importer dans Postman :
postman/AssistantCore.postman_collection.json;postman/AssistantCore.local.postman_environment.json.
Selectionner ensuite l'environnement AssistantCore Local.
Dans l'environnement AssistantCore Local, renseigner les valeurs locales :
base_url=https://localhost:7292
tenant_id=<TENANT_CLIENT_ID>
api_client_id=<API_CLIENT_ID>
postman_client_id=<POSTMAN_CLIENT_ID>
postman_client_secret=<POSTMAN_CLIENT_SECRET>
scope=api://<API_CLIENT_ID>/access_as_user openid profile email
tenant_id correspond au tenant de la compagnie fictive, pas au tenant
fournisseur. Il sert a enregistrer et diagnostiquer la compagnie cliente. Les
URLs OAuth utilisent volontairement organizations pour accepter les comptes
professionnels de tous les tenants Microsoft Entra ID.
Marquer postman_client_secret comme variable de type secret et enregistrer
sa valeur uniquement dans la valeur locale de l'environnement. Avant de
partager ou d'exporter un environnement Postman, verifier que cette valeur
n'est pas incluse.
Ouvrir la collection, puis Authorization. Utiliser les valeurs suivantes :
| Champ Postman | Valeur |
|---|---|
| Type | OAuth 2.0 |
| Add auth data to | Request Headers |
| Token Name | AssistantCore local |
| Grant Type | Authorization Code |
| Callback URL | https://oauth.pstmn.io/v1/callback |
| Auth URL | https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize |
| Access Token URL | https://login.microsoftonline.com/organizations/oauth2/v2.0/token |
| Client ID | {{postman_client_id}} |
| Client Secret | {{postman_client_secret}} |
| Scope | {{scope}} |
| State | assistantcore-bootstrap |
| Client Authentication | Send client credentials in body |
Signification des champs :
Grant Typeindique que l'utilisateur se connecte dans un navigateur. Entra retourne d'abord un code temporaire, jamais directement le token a l'API.Callback URLest l'adresse vers laquelle Entra renvoie le code. Elle doit correspondre exactement, protocole et chemin inclus, a l'URIWebenregistree dansAssistantCore Postman.Auth URLest le endpoint interactif qui affiche la connexion Microsoft et recueille le consentement.Access Token URLest le endpoint appele par Postman pour echanger le code contre un access token.organizationsaccepte les comptes professionnels ou scolaires provenant de n'importe quel tenant Entra ID, mais exclut les comptes Microsoft personnels.Client IDidentifie publiquement l'inscriptionAssistantCore Postman.Client Secretprouve l'identite du client Postman. Contrairement au Client ID, cette valeur est confidentielle.Scopeest une liste separee par des espaces. Le scopeapi://<API_CLIENT_ID>/access_as_userdemande un access token pour AssistantCore.openidactive OpenID Connect,profiledemande les claims de profil etemaildemande l'adresse courriel lorsqu'elle existe.Stateest une valeur retournee sans modification apres la connexion afin de lier la reponse a la demande initiale et limiter les attaques de substitution de requete.Send client credentials in bodyenvoieclient_idetclient_secretdans le corps du POST vers/tokenau lieu d'utiliser un header Basic.Request Headersfait heriter les requetes de la collection du headerAuthorization: Bearer <access_token>.
Dans l'onglet Authorization de la collection :
- Selectionner
Get New Access Token. - Activer
Authorize using browsersi Postman le propose. - Se connecter avec un utilisateur du tenant client fictif, pas avec un utilisateur du tenant fournisseur.
- Accepter le consentement si Entra ID le demande.
- Verifier que Postman a recu un access token.
- Selectionner
Use Token.
Pendant ce flux :
- Postman ouvre l'Auth URL avec le Client ID, le callback et les scopes.
- Entra ID authentifie l'utilisateur et retourne un code au callback Postman.
- Postman envoie le code, le Client ID et le Client Secret a l'Access Token URL.
- Entra ID retourne un access token destine a AssistantCore.
- Postman ajoute ce token comme Bearer token aux requetes de la collection.
Le backend valide notamment la signature, l'audience et l'emetteur du token.
Il utilise ensuite le claim tid pour trouver l'organisation et le claim
oid pour trouver ou creer le membre. Ne pas partager un token dans un ticket
ou un outil public : un access token actif permet d'appeler l'API avec les
droits de l'utilisateur.
Toutes les routes AssistantCore heritent du token OAuth 2.0 configure au niveau de la collection.
| Requete Postman | Methode et route | Resultat attendu |
|---|---|---|
AuthenticateUser |
GET /api/core/authenticateUser |
Valide l'identite, retrouve l'organisation et cree le membre avec le role User s'il n'existe pas. |
Get Members |
GET /api/members |
Retourne les membres de l'organisation courante. Le membre connecte doit avoir le role Admin. |
Update Member Role |
PATCH /api/members/{{member_id}}/role |
Remplace le role du membre cible par Admin ou User. Le membre connecte doit avoir le role Admin. |
AuthenticateUser enregistre automatiquement current_user_id dans
l'environnement. Get Members cherche un autre membre actif et enregistre son
identifiant dans member_id. Update Member Role utilise member_id et la
valeur member_role dans le body suivant :
{
"role": "{{member_role}}"
}Les valeurs acceptees pour member_role sont Admin et User.
La requete GET https://graph.microsoft.com/v1.0/me presente dans certaines
collections locales n'est pas une route AssistantCore. Elle exige une
permission Microsoft Graph deleguee telle que User.Read et un access token
dont l'audience est Microsoft Graph. Le token demande avec
api://<API_CLIENT_ID>/access_as_user est destine a AssistantCore et ne doit
pas etre reutilise pour appeler Microsoft Graph.
Executer les requetes dans cet ordre :
- Obtenir un token avec le premier utilisateur du tenant client.
- Executer
AuthenticateUser. Le backend cree ce membre avec le roleUser. - Promouvoir ce premier membre en
Adminavec SQLPad :
USE [AssistantCoreDb];
UPDATE [dbo].[OrganizationMember]
SET [Role] = N'Admin'
WHERE [Email] = N'<EMAIL_UTILISATEUR_TEST>';- Obtenir un nouveau token avec le deuxieme utilisateur du meme tenant.
- Executer
AuthenticateUserafin de creer ce deuxieme membre avec le roleUser. - Obtenir de nouveau un token avec le premier utilisateur administrateur.
- Executer
AuthenticateUser, puisGet Members. La collection place l'identifiant du deuxieme membre dansmember_id. - Choisir
AdminouUserdansmember_role. - Executer
Update Member Roleet verifier le code200ainsi que le role retourne.
Erreurs courantes :
401 Unauthorized: token absent, expire, signature invalide ou mauvaise audience;403 ForbiddensurAuthenticateUser: letiddu token ne correspond a aucune organisation active dans la base;403 Forbiddensur les routes membres : le membre connecte n'a pas le role interneAdmin;AADSTS50011: le Callback URL Postman ne correspond pas exactement a l'URI configuree dans Entra ID;invalid_client: mauvais Client ID, secret invalide ou secret expire;- erreur de consentement : la permission
access_as_usern'a pas ete ajoutee au client Postman ou autorisee dans le tenant concerne.
Compilation du projet :
dotnet build Solution.slnTests manuels d'integration :
- connexion Entra ID depuis le tenant client;
- validation du token par l'API;
- creation automatique du membre;
- isolation de l'organisation avec le claim
tid; - consultation et modification des membres avec un administrateur;
- scripts de validation inclus dans la collection Postman.
Le projet contient des tests unitaires pour le flux AuthenticateUser, le
controleur CoreController et ExceptionMiddleware. Ils couvrent les regles
de creation et d'acces des membres, la construction de la reponse, la
delegation du controleur et la traduction des exceptions en reponses HTTP.
Executer tous les tests automatises :
dotnet test Solution.slnArreter les conteneurs sans supprimer les donnees :
docker compose --env-file .env.database downSupprimer aussi les volumes et reinitialiser la base :
docker compose --env-file .env.database down --volumesCette derniere commande supprime les donnees locales SQL Server et SQLPad.
A court terme, chaque developpeur peut recreer les deux tenants pour disposer d'un environnement completement isole.
A moyen terme, l'approche recommandee est de maintenir :
- un tenant fournisseur de developpement commun;
- un tenant client fictif commun;
- des inscriptions d'applications dediees a l'environnement de developpement;
- un compte nominatif par developpeur dans le tenant client;
- des comptes de test generiques seulement pour les scenarios automatises;
- les secrets et acces de recuperation dans un gestionnaire de secrets d'equipe.
Un identifiant et un mot de passe uniques partages par toute l'equipe sont deconseilles : ils compliquent la MFA, la tracabilite et la revocation d'acces.