Tester Auth0 dans votre CI/CD : tests d'intégration et mocking
Comment tester votre intégration Auth0 dans un pipeline CI/CD ? Stratégies de mocking, tests d'intégration avec un tenant dédié et tests E2E avec Playwright.
Par Auth0.Expert · 2025-04-03 · 10 min de lecture
Tester Auth0 dans votre CI/CD
TL;DR
Tester l'authentification en CI/CD est complexe. Ce guide présente 3 niveaux : tests unitaires avec JWT mockés, tests d'intégration avec un tenant Auth0 dédié, et tests E2E avec Playwright.
---
Niveau 1 : Tests unitaires avec JWT mocké
Avant ce bloc de code, voici comment générer des JWT factices pour simuler l’authentification Auth0 dans vos tests unitaires Python. Cela permet de tester les règles de sécurité localement, sans dépendre d’Auth0.
# conftest.py (pytest)
import pytest
from datetime import datetime, timedelta
from jose import jwt
TEST_PRIVATE_KEY = """-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA... # Clé RSA de test uniquement
-----END RSA PRIVATE KEY-----"""
def create_test_token(
sub: str = "test_user_id",
email: str = "[email protected]",
roles: list = None,
plan: str = "pro",
expires_in: int = 3600,
) -> str:
"""Créer un JWT de test signé avec une clé privée de test."""
now = datetime.utcnow()
payload = {
"sub": sub,
"email": email,
"email_verified": True,
"iss": "https://test.auth0.com/",
"aud": "https://api.yourapp.com",
"iat": int(now.timestamp()),
"exp": int((now + timedelta(seconds=expires_in)).timestamp()),
"https://yourapp.com/roles": roles or ["user"],
"https://yourapp.com/plan": plan,
}
return jwt.encode(payload, TEST_PRIVATE_KEY, algorithm="RS256")
@pytest.fixture
def admin_token():
return create_test_token(roles=["admin"], plan="enterprise")
@pytest.fixture
def user_token():
return create_test_token(roles=["user"], plan="free")
@pytest.fixture
def expired_token():
return create_test_token(expires_in=-1)
Ce bloc crée plusieurs jetons adaptés à chaque scénario de test : admin, utilisateur simple, et expiration.
Voici comment utiliser les JWT mockés pour simuler l’accès à vos API, et valider que la logique d’autorisation côté backend fonctionne correctement.
# test_api.py
async def test_admin_can_delete_post(client, admin_token):
resp = await client.delete(
"/api/posts/123",
headers={"Authorization": f"Bearer {admin_token}"}
)
assert resp.status_code == 200
async def test_user_cannot_delete_post(client, user_token):
resp = await client.delete(
"/api/posts/123",
headers={"Authorization": f"Bearer {user_token}"}
)
assert resp.status_code == 403
async def test_expired_token_rejected(client, expired_token):
resp = await client.get(
"/api/data",
headers={"Authorization": f"Bearer {expired_token}"}
)
assert resp.status_code == 401
Ce code valide que chaque profil d’utilisateur obtient bien le comportement attendu sur les routes protégées : autorisé, refusé ou rejeté selon les cas.
---
Remplacer la validation Auth0 en test
Ce code permet de remplacer la validation réelle Auth0 par une version simulée, qui s’active en environnement de test. Idéal pour séparer les tests locaux de l’intégration Auth0 en production.
# Injecter une validation mockée en environnement de test
import os
from unittest.mock import AsyncMock
def get_token_validator():
if os.environ.get("TESTING"):
# En test : utiliser la clé publique de test
return validate_with_test_key
else:
# En prod : utiliser les JWKS Auth0
return validate_with_auth0_jwks
async def validate_with_test_key(token: str) -> dict:
"""Valide avec la clé publique RSA de test (pas Auth0)."""
TEST_PUBLIC_KEY = os.environ.get("TEST_PUBLIC_KEY")
return jwt.decode(
token,
TEST_PUBLIC_KEY,
algorithms=["RS256"],
audience="https://api.yourapp.com",
)
Ce système garantit que vos tests restent robustes en isolant la couche d’authentification Auth0.
---
Niveau 2 : Tests d'intégration avec tenant dédié
Cette section explique comment automatiser l’exécution de tests d’intégration via un tenant Auth0 isolé dans un pipeline CI/CD avec GitHub Actions. Cela permet de valider l’authentification réelle sur un environnement proche de la production, sans impacter les utilisateurs.
# GitHub Actions : tenant Auth0 de CI
name: Integration Tests
on: [push]
jobs:
integration-tests:
runs-on: ubuntu-latest
env:
AUTH0_DOMAIN: ${{ secrets.AUTH0_CI_DOMAIN }}
AUTH0_CLIENT_ID: ${{ secrets.AUTH0_CI_CLIENT_ID }}
AUTH0_CLIENT_SECRET: ${{ secrets.AUTH0_CI_CLIENT_SECRET }}
AUTH0_MGMT_TOKEN: ${{ secrets.AUTH0_CI_MGMT_TOKEN }}
AUTH0_TEST_USER_EMAIL: [email protected]
AUTH0_TEST_USER_PASSWORD: ${{ secrets.AUTH0_CI_TEST_PASSWORD }}
steps:
- uses: actions/checkout@v4
- name: Start services
run: docker compose -f docker-compose.test.yml up -d
- name: Get Auth0 token for tests
run: |
TOKEN=$(curl -s -X POST "https://$AUTH0_DOMAIN/oauth/token" -H "Content-Type: application/json" -d '{
"grant_type": "password",
"username": "'$AUTH0_TEST_USER_EMAIL'",
"password": "'$AUTH0_TEST_USER_PASSWORD'",
"client_id": "'$AUTH0_CLIENT_ID'",
"client_secret": "'$AUTH0_CLIENT_SECRET'",
"audience": "https://api.yourapp.com",
"scope": "openid email"
}' | jq -r '.access_token')
echo "AUTH0_TEST_TOKEN=$TOKEN" >> $GITHUB_ENV
- name: Run integration tests
run: pytest tests/integration/ -v
env:
AUTH0_TEST_TOKEN: ${{ env.AUTH0_TEST_TOKEN }}
Ce workflow obtient un vrai token Auth0, puis exécute les tests d’intégration avec les services montés — il couvre l’ensemble du parcours d’authentification.
---
Niveau 3 : Tests E2E avec Playwright
Ici, nous automatisons les parcours utilisateur authentifiés de bout en bout avec Playwright, en intégrant la page de login Auth0 Universal Login. Ceci permet de garantir l’expérience réelle depuis le navigateur.
// tests/e2e/auth.spec.ts
import { test, expect } from '@playwright/test';
const TEST_EMAIL = process.env.E2E_TEST_EMAIL!;
const TEST_PASSWORD = process.env.E2E_TEST_PASSWORD!;
test.describe('Authentication Flow', () => {
test('should login successfully with valid credentials', async ({ page }) => {
await page.goto('/');
await page.click('[data-testid="login-button"]');
// Auth0 Universal Login
await page.waitForURL(/auth0\.com/);
await page.fill('[name="email"]', TEST_EMAIL);
await page.fill('[name="password"]', TEST_PASSWORD);
await page.click('[name="submit"]');
// Callback + redirect
await page.waitForURL('/dashboard');
await expect(page.locator('[data-testid="user-menu"]')).toBeVisible();
});
test('should show error with invalid credentials', async ({ page }) => {
await page.goto('/');
await page.click('[data-testid="login-button"]');
await page.fill('[name="email"]', TEST_EMAIL);
await page.fill('[name="password"]', 'wrong-password');
await page.click('[name="submit"]');
await expect(page.locator('.error-message')).toBeVisible();
});
test('should protect authenticated routes', async ({ page }) => {
await page.goto('/dashboard');
await page.waitForURL(/auth0\.com/); // Redirect vers Auth0
});
});
// Fixture : se connecter une fois et réutiliser la session
test.beforeEach(async ({ page, context }) => {
// Stocker les tokens Auth0 en localStorage
await context.addInitScript(() => {
// Bypass Auth0 en environnement de test
window.E2E_BYPASS_AUTH = true;
});
});
Ce script E2E simule le login, la gestion d’erreur, et la protection des routes, pour une validation complète côté Front.
---
Mock Auth0 complet pour les tests locaux
Vous pouvez simuler complètement Auth0 en local avec ce serveur Express, ce qui permet d’avoir tous les endpoints principaux requis pour les tests (OpenID, token, JWKS).
// mock-auth0-server.js : serveur Auth0 minimal pour les tests locaux
const express = require('express');
const jwt = require('jsonwebtoken');
const { generateKeyPairSync } = require('crypto');
const { privateKey, publicKey } = generateKeyPairSync('rsa', { modulusLength: 2048 });
const app = express();
app.get('/.well-known/openid-configuration', (req, res) => {
res.json({
issuer: 'http://localhost:4444/',
authorization_endpoint: 'http://localhost:4444/authorize',
token_endpoint: 'http://localhost:4444/token',
jwks_uri: 'http://localhost:4444/.well-known/jwks.json',
});
});
app.post('/token', express.json(), (req, res) => {
const token = jwt.sign(
{
sub: 'test_user_id',
email: '[email protected]',
'https://yourapp.com/roles': ['admin'],
},
privateKey,
{ algorithm: 'RS256', expiresIn: '1h', audience: 'https://api.yourapp.com' }
);
res.json({ access_token: token, token_type: 'Bearer', expires_in: 3600 });
});
app.listen(4444, () => console.log('Mock Auth0 server running on port 4444'));
Ce serveur factice permet de remplacer Auth0 dans votre stack locale pour accélérer le développement et les tests.
---
> 🧪 Testing Auth0 : nos équipes mettent en place votre stratégie de tests d'authentification complète (unit, integration, E2E) en 1 semaine.
Autres articles
- Auth0 et OAuth 2.0 : architecture complète pour comprendre les flux d'autorisation
- OpenID Connect sur Auth0 : ID Token, UserInfo et discovery endpoint expliqués
- Configurer SAML 2.0 avec Auth0 : guide complet pour l'entreprise
- Migrer des Rules vers les Auth0 Actions : guide pas à pas
- Architecture multi-tenant avec Auth0 : organisations, isolation et bonnes pratiques
- Validation des JWT Auth0 : RS256 vs HS256, JWKS et pièges communs
- Concevoir son architecture de tenants Auth0 : dev, staging, prod
- Configurer un domaine personnalisé Auth0 : login.votredomaine.com étape par étape