Vous travaillez dans une entreprise et devez mettre en place un système d’authentification unique (SSO) sur Azure avec FastAPI ? Vous ne trouvez pas ce dont vous avez besoin dans la documentation officielle d’Azure ? Vous êtes au bon endroit !
Dans ce guide complet, nous allons parcourir l’ensemble du processus de configuration de l’authentification unique Azure (SSO) avec FastAPI, depuis la configuration de votre application Microsoft Entra ID jusqu’à l’implémentation du flux d’authentification dans votre application FastAPI.
Remarque : Microsoft a renommé Azure Active Directory (Azure AD) en Microsoft Entra ID. Ce guide utilisera la nouvelle terminologie, mais vous pouvez encore rencontrer les anciens noms dans certaines documentations et articles en ligne.
Comprendre le flux d’authentification
Avant de plonger dans l’implémentation, il est important de comprendre comment fonctionne l’ensemble du processus d’authentification. Lorsqu’un utilisateur tente d’accéder à votre application FastAPI, il sera redirigé vers la page de connexion de Microsoft. Après une authentification réussie, Microsoft Entra ID renvoie un code d’autorisation à votre application, que vous échangez ensuite contre des jetons d’accès. Ces jetons contiennent des informations sur l’utilisateur et peuvent être validés pour garantir que la requête est légitime. Si votre utilisateur est déjà connecté, il ne verra même pas ces redirections. Voici le déroulement complet ci-dessous :

La beauté de cette approche réside dans le fait que votre application ne gère jamais directement les mots de passe des utilisateurs. Toute l’authentification est prise en charge par l’infrastructure sécurisée de Microsoft, et vous vous contentez de valider les jetons qu’ils fournissent.
Étape 1 : Configuration d’Azure
1.1 Créer l’enregistrement de l’application
Tout d’abord, nous devons configurer un enregistrement d’application avant de mettre en place l’authentification unique (SSO) sur notre application. En environnement de production, il est recommandé de réaliser cette étape à l’aide de pipelines IaC (Infrastructure-as-Code), mais pour ce tutoriel, nous allons passer cette partie et effectuer la configuration manuellement.
L’enregistrement de l’application sera l’identité de votre application dans Azure. Il peut être utilisé à diverses fins, telles que l’accès basé sur les rôles aux ressources Azure. Ici, nous l’utiliserons uniquement pour l’authentification unique (SSO). Sélectionnez l’enregistrement d’application dans le Portail Azure et cliquez sur « Enregistrer une application ».

Pour créer votre application, il vous suffit de choisir un nom et de sélectionner le type de comptes pris en charge. Cela est assez explicite, comme vous pouvez le voir ci-dessous.

L’URI de redirection est la partie la plus intéressante. Ici, vous allez définir l’URL qu’Azure sera autorisé à utiliser après le processus de connexion. Il s’agit d’une mesure de sécurité utilisée par Azure pour garantir que vos jetons ne puissent pas être volés lors d’une attaque de type « homme du milieu » vers une autre adresse.
Le type d’URI de redirection pour ce tutoriel sera Web, qui est la solution générique pour une API web.
Après cela, vous pouvez alors créer l’enregistrement de votre application.
1.2 Optionnel : Ajouter d’autres URL de redirection
Remarque : Après la création, il sera possible de répertorier plusieurs URI de redirection. Cela est utile, par exemple, pour indiquer une URL locale pour le développement et une URL de production. Il suffit d’aller dans l’onglet d’authentification et de cliquer sur « Ajouter une URI », d’ajouter une nouvelle URL, puis de cliquer sur « Enregistrer ».

1.3 Créer un secret
Ok, nous avons presque terminé, il ne nous reste plus qu’à créer un secret client. Celui-ci servira de mot de passe pour utiliser l’enregistrement de l’application dans notre application.
- Cliquez sur l’onglet « Certificats et secrets »
- Dans la section Secrets client, cliquez sur « + Nouveau secret client ».
- Saisissez une description (par exemple, clé d’accès API) et choisissez une période d’expiration
- Cliquez sur « Ajouter ».
- Copiez la valeur immédiatement — elle ne sera affichée qu’une seule fois.

Encore une fois, en pratique, vous feriez cela en utilisant un type de pipeline IaC et vous stockeriez le secret dans un coffre de clés après l’avoir créé automatiquement. De plus, les secrets clients doivent être renouvelés, donc n’oubliez pas de planifier un moment pour les renouveler ou de mettre en place un processus de renouvellement automatique via IaC.
1.4 Récupérer l’ID client et l’ID de locataire
Accédez à la page de présentation et récupérez l’ID client et l’ID de locataire (également appelé ID de répertoire). Vous disposez maintenant des trois chaînes dont nous aurons besoin pour nous connecter à Azure.
Étape 2 : Installer les dépendances avec pip
Très bien, maintenant, configurons notre projet. Commencez par créer un fichier requirements.txt
avec le contenu suivant :
fastapi
httpx
python-dotenv
python-jose
msal # This is for azure authentification
uvicorn
Ensuite, installez-les en utilisant pip :
pip install -r requirements.txt
Étape 3 : Mise en œuvre de l’application FastAPI
Il est temps de coder ! Nous allons créer un seul fichier main.py
pour ce tutoriel. En pratique, vous pourriez vouloir séparer le code d’authentification et les routes dans un fichier différent en utilisant la fonctionnalité de routeur de FastAPI, mais cela dépasse le cadre de cet article.
3.1 Importations et initialisations importantes
Tout d’abord, nous allons devoir importer un certain nombre d’éléments :
import httpx
import secrets
import os
from jose import jwt, JWTError
from typing import Optional, Dict, Any, List
from datetime import datetime, timedelta
from fastapi import FastAPI, Depends, HTTPException, status, Request
from fastapi.responses import RedirectResponse, JSONResponse
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from dotenv import load_dotenv
import msal
from starlette.middleware.session import SessionMiddleware
Ensuite, nous devrons définir quelques éléments, comme nous pouvons le voir dans le code ci-dessous. Ce qui importe le plus est le msal_client, qui représentera l’enregistrement de l’application dans le code. Notez également que nous ajoutons SessionMiddleware aux middlewares de FastAPI. Cela nous sera utile par la suite.
AZURE_CLIENT_ID = # Retrieved from previous step
AZURE_CLIENT_SECRET = # Retrieved from previous step
AZURE_TENANT_ID = # Retrieved from previous step
AZURE_REDIRECT_URI = # The redirect URL you defined in the app registration
SECRET_KEY = # Random value you choose for securing the session
AUTHORITY = f"https://login.microsoftonline.com/{AZURE_TENANT_ID}"
SCOPE = ["User.Read"] # This scope will be used to say ( we want to access user info)
app = FastAPI()
# Add session middleware
# NOTE: In production, ensure 'https_only=True' and 'samesite="none"' for cross-site SSO redirects.
app.add_middleware(
SessionMiddleware,
secret_key=SECRET_KEY,
https_only=True,
samesite="none"
)
# Initialize MSAL Confidential Client
msal_client = msal.ConfidentialClientApplication(
client_id=AZURE_CLIENT_ID,
authority=AUTHORITY,
client_credential=AZURE_CLIENT_SECRET,
)
3.2 Points de terminaison de connexion et de rappel
Écrivons maintenant les points de terminaison d’autorisation de base qui permettront aux utilisateurs de se connecter en utilisant Microsoft Entra ID (Azure AD) et de gérer le rappel OAuth.
L’itinéraire /login redirigera l’utilisateur vers la page de connexion Microsoft. Après s’être connecté à son compte Microsoft, l’utilisateur sera redirigé vers /login/callback. Le lien exact de rappel a été fourni dans /login avec la variable AZURE_REDIRECT_URI. Si l’utilisateur est déjà connecté à Microsoft, il ne verra même pas la redirection côté front-end.
Dans /login/callback, nous échangeons notre code contre un jeton utilisateur. Encore une fois, il s’agit d’une mesure de sécurité pour éviter d’envoyer le jeton sur Internet. Remarquez que nous stockons ensuite notre jeton dans la session utilisateur. C’est essentiel ; sinon, le jeton n’existera que jusqu’à la prochaine redirection. Sans cela, nous pouvons entrer dans une boucle de redirections infinie.
À la fin, la route de rappel redirige l’utilisateur vers la route protégée. Il s’agit d’une implémentation simplifiée. Une approche plus flexible consiste à enregistrer dans la session l’adresse que l’utilisateur a tenté d’atteindre. Ensuite, il suffit de la récupérer dans le rappel afin de s’assurer que l’on puisse revenir à l’endroit d’où l’on vient.
# --- API Endpoints ---
@app.get("/login")
async def login(request: Request):
"""
Initiate the Microsoft Entra ID login flow.
Stores the state in the session.
"""
state = secrets.token_urlsafe(32)
request.session["state"] = state
authorization_url = msal_client.get_authorization_request_url(
scopes=SCOPE,
state=state,
redirect_uri=AZURE_REDIRECT_URI
)
return RedirectResponse(url=authorization_url)
@app.get("/login/callback")
async def callback(code: str, state: str, request: Request):
"""
Handle the OAuth callback from Microsoft Entra ID.
Stores the user's token and info in the session.
"""
# Verify the state to prevent CSRF attacks
if state != request.session.get("state"):
raise HTTPException(status_code=400, detail="Invalid state parameter")
request.session.pop("state", None)
token_response = msal_client.acquire_token_by_authorization_code(
code=code,
scopes=SCOPE,
redirect_uri=AZURE_REDIRECT_URI
)
if "error" in token_response:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail=token_response.get("error_description", "Failed to acquire token")
)
# The id_token contains user claims
id_token_claims = jwt.decode(
token_response['id_token'],
options={"verify_signature": False} # Signature already verified by MSAL/Entra ID
)
# Store user information in the session
request.session["user"] = {
"id": id_token_claims.get("oid"),
"name": id_token_claims.get("name"),
"email": id_token_claims.get("preferred_username"),
"roles": id_token_claims.get("roles", []),
}
return RedirectResponse(url="/protected")
3.3 Créer des dépendances
Créons quelques fonctions utilitaires. Nous les utiliserons comme dépendances avec la fonctionnalité Depends de FastAPI. Cela permet à FastAPI de résoudre et d’injecter automatiquement les résultats de ces utilitaires là où c’est nécessaire, rendant ainsi votre code plus modulaire et plus propre.
Ces fonctions vont simplement essayer d’obtenir l’objet utilisateur ou les rôles à partir de la session en cours. Si cela n’existe pas, elles lèveront un drapeau d’erreur sous forme d’exception HTTP 302. Celle-ci sera envoyée au navigateur web, qui comprendra qu’il doit effectuer une redirection. Dans ce cas, vers le point de terminaison /login.
# --- Authentication Logic ---
# (We don't need manual token verification with sessions, but this can be useful for other purposes)
# --- Dependencies ---
def require_auth(request: Request):
"""
Dependency to protect an endpoint.
Raises an exception if the user is not authenticated.
"""
user = request.session.get("user")
if not user:
response = RedirectResponse(url="/login", status_code=302)
raise HTTPException(
status_code=response.status_code,
headers=response.headers
)
return user
def require_roles(required_roles: List[str]):
"""
Dependency factory to check for required roles in the session.
"""
def role_checker(
user: Dict[str, Any] = Depends(require_auth)
):
user_roles = user.get("roles", [])
if not any(role in user_roles for role in required_roles):
response = RedirectResponse(url="/login", status_code=302)
raise HTTPException(
status_code=response.status_code,
headers=response.headers
)
return user
return role_checker
3.4 Créons quelques routes réelles
Parfait, maintenant que nous avons géré la logique d’autorisation, nous pouvons l’utiliser pour proposer des points de terminaison utiles dans nos applications. Voici quelques exemples qui nécessitent un jeton utilisateur, un rôle spécifique, ou aucune connexion du tout. Remarquez comment nous utilisons la fonctionnalité Depends() de FastAPI pour intégrer de manière transparente l’authentification dans nos points de terminaison.
@app.get("/protected")
async def protected_endpoint(
user = Depends(require_auth)
):
"""
A protected endpoint that requires authentication via session.
"""
return {
"message": f"Hello, {user.get('name')}! This is protected data.",
"user_details": user
}
@app.get("/roleProtected", dependencies=[Depends(require_roles(["Admin"]))])
async def role_protected_endpoint(
user = Depends(require_auth)
):
"""
An endpoint protected by role 'Admin'.
"""
return {
"message": f"Welcome, Admin {user.get('name')}!",
"detail": "You have access to this role-protected data."
}
@app.get("/unprotected")
async def unprotected_endpoint():
"""
An unprotected endpoint that anyone can access.
"""
return {"message": "This is an unprotected endpoint."}
if __name__ == "__main__":
import uvicorn
# This is for development only. In production, use a proper ASGI server.
uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)
Une note importante sur les cookies de session et l’authentification unique (SSO)
Nous utilisons le SessionMiddleware
de Starlette pour la gestion des sessions. Lorsqu’un utilisateur se connecte, ses informations d’identité sont stockées dans un cookie sécurisé et signé.
Au cours du processus SSO, l’utilisateur est redirigé de votre application vers la page de connexion de Microsoft, puis de retour. Du point de vue du navigateur, il s’agit d’une requête intersite. Pour que le cookie de session soit correctement géré après cette redirection, il doit être configuré avec SameSite=None
et https_only=True
. Cela indique au navigateur que le cookie peut être envoyé dans des contextes cross-origin, mais uniquement via HTTPS.
Astuce 1 : Lorsque SameSite=None
est utilisé, les navigateurs refuseront silencieusement de définir le cookie si la connexion n’est pas sécurisée (c’est-à-dire, non HTTPS). Cela peut être très difficile à déboguer car votre flux d’authentification échouera simplement sans erreur évidente. Lors du déploiement sur Azure ou dans tout autre environnement de production, assurez-vous d’utiliser HTTPS.
Astuce 2 : Cela peut rendre le travail en local difficile ; vous devrez également utiliser une URL HTTPS pour le développement local. Dans certains cas, certains navigateurs vous permettront de désactiver cette sécurité à des fins de développement.
Astuce 3 : Soyez prudent lors de la construction de vos objets de réponse dans FastAPI. Si vous créez un nouvel objet Response
au lieu de laisser FastAPI le gérer, vous risquez d’effacer accidentellement l’en-tête Set-Cookie
ajouté par le SessionMiddleware
, ce qui déconnectera effectivement l’utilisateur. Il est préférable de modifier request.session
et de laisser le middleware gérer la gestion des cookies.
Étape 4 : Tester votre implémentation
Maintenant que tout est en place, testons le flux d’authentification. Démarrez votre application FastAPI :
python main.py
Ou en utilisant directement uvicorn :
uvicorn main:app --reload
Votre application devrait maintenant être en cours d’exécution. Vous pouvez tester le processus d’authentification :
- Accédez à l’adresse dans votre navigateur
- Vous serez redirigé vers la page de connexion de Microsoft
- Connectez-vous avec vos identifiants Microsoft Entra ID
- Après une authentification réussie, vous serez redirigé vers votre point de terminaison de rappel
- Le rappel renverra vos informations utilisateur et vos jetons
- Vous devriez maintenant avoir accès à votre application
Pièges courants
- Réinitialisation des cookies : Faites attention à ce que votre navigateur ne réinitialise pas vos cookies. Assurez-vous d’utiliser les bons paramètres lors de la création des cookies, comme expliqué ci-dessus.
- Test sur http, pas https : Si vous effectuez des tests sur une URL locale http://localhost, vos cookies ne seront pas enregistrés. Cela est dû au fait qu’il ne s’agit pas d’une URL HTTPS.
- Expiration des jetons : Les jetons ont une date d’expiration. N’utilisez pas le même jeton trop longtemps lors des tests.
- Comment configurer l’authentification SSO Azure avec FastAPI : Guide complet - 18 octobre 2025
- Pourquoi la révolution de l’IA est-elle si lente ? (Elle ne l’est pas.) - 18 septembre 2025
- Comment les LLMs stockent l’information? La Superposition des Charactérisques (Expliqué Simplement) - 15 août 2025