Configurer la liaison de jeton avec la preuve de possession mTLS (mTLS PoP)

Note

Tous les clients ne sont pas autorisés à obtenir des certificats mTLS PoP, car cette fonctionnalité est actuellement en préversion privée.

La liaison de jeton de certificat (également appelée mTLS PoP - Preuve de possession TLS mutuelle) est une fonctionnalité de sécurité avancée qui lie par chiffrement les jetons d’accès à un certificat X.509 spécifique. RFC 8705 décrit cette liaison. La liaison garantit que même si un jeton est intercepté, un attaquant ne peut pas l’utiliser sans possession de la clé privée correspondante.

Comprendre le fonctionnement de la liaison des jetons

Les étapes suivantes décrivent le processus de liaison des jetons depuis l’acquisition jusqu’à la vérification.

  1. Token Acquisition : lors de la demande d'un jeton d'accès avec la liaison de jeton activée, Microsoft Identity Web inclut l'empreinte numérique du certificat dans la demande de jeton
  2. Liaison de jeton : le serveur d’autorisation incorpore une cnf revendication (confirmation) dans le jeton émis contenant l’empreinte SHA-256 du certificat (x5t#S256)
  3. Appel d’API : le client présente à la fois le jeton lié et le certificat lors de l’appel de l’API en aval
  4. Vérification : l’API valide que le certificat présenté correspond à la référence de certificat dans la revendication du cnf jeton
sequenceDiagram
    participant Client
    participant EntraID as Microsoft Entra ID
    participant API

    Client->>EntraID: Token request with certificate thumbprint
    EntraID->>Client: Token with cnf claim (bound to certificate)
    Client->>API: MTLS_POP token + Client certificate
    API->>API: Validate token and certificate binding
    API->>Client: Protected resource

Passer en revue les avantages de sécurité

La liaison de jeton offre les avantages suivants pour sécuriser vos applications.

  • Protection contre le vol de jeton : les jetons volés sont inutiles sans le certificat correspondant
  • Prévention des attaques par rejeu : les jetons ne peuvent pas être rejoués par différents clients
  • Authentification améliorée : combine « quelque chose que vous avez » (certificat) avec des flux OAuth2 traditionnels
  • architecture Confiance nulle : s’aligne sur les principes de zero trust en liant les informations d’identification à des appareils spécifiques

Configurer la liaison des jetons

Configurez l’application cliente et le serveur d’API pour activer la liaison de jeton PoP mTLS.

Configurer l’application cliente

Effectuez les étapes suivantes pour configurer l’application cliente pour la liaison de jetons.

1. Configurer les paramètres de Microsoft Entra ID

Dans votre appsettings.json, configurez vos paramètres de Microsoft Entra, y compris le certificat :

{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "ClientCredentials": [
      {
        "SourceType": "StoreWithDistinguishedName",
        "CertificateStorePath": "CurrentUser/My",
        "CertificateDistinguishedName": "CN=YourCertificate"
      }
    ],
    "SendX5c": true
  }
}

2. Configurer l'API en aval avec la Token Binding

Configurez votre section d'API en aval avec le schéma de protocole MTLS_POP :

{
  "DownstreamApi": {
    "BaseUrl": "https://api.contoso.com/",
    "RelativePath": "api/data",
    "ProtocolScheme": "MTLS_POP",
    "RequestAppToken": true,
    "Scopes": [ "api://your-api-scope/.default" ]
  }
}

Propriétés de configuration importantes :

  • ProtocolScheme: doit être défini à "MTLS_POP" pour activer la liaison de jeton
  • RequestAppToken: doit être true (la liaison de jeton prend actuellement en charge uniquement les jetons d’application)
  • Scopes: étendues d’API requises pour l’appel d’API en aval

3. Inscrire des services

Inscrivez le service d’API en aval dans le code de démarrage de votre application. L’exemple suivant montre à la fois les approches d’application console et de ASP.NET Core.

using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

// Option 1: Using TokenAcquirerFactory (for console apps, background services)
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();

tokenAcquirerFactory.Services.AddDownstreamApi(
    "DownstreamApi",
    tokenAcquirerFactory.Configuration.GetSection("DownstreamApi"));

var serviceProvider = tokenAcquirerFactory.Build();

// Option 2: Using ASP.NET Core DI (for web apps, web APIs)
builder.Services.AddAuthentication()
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));

builder.Services.AddDownstreamApi(
    "DownstreamApi",
    builder.Configuration.GetSection("DownstreamApi"));

Configurer le serveur d’API

L’API en aval doit valider le jeton et la liaison de certificat. Voici un exemple complet :

1. Inscrire des gestionnaires d’authentification

using Microsoft.Identity.Web;

var builder = WebApplication.CreateBuilder(args);

// Add standard JWT Bearer authentication
builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration);

// Add custom MTLS_POP authentication handler
builder.Services.AddAuthentication()
    .AddScheme<AuthenticationSchemeOptions, MtlsPopAuthenticationHandler>(
        "MTLS_POP",
        options => { });

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.Run();

2. Implémenter le gestionnaire d’authentification poP mTLS

using System.Security.Claims;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text.Encodings.Web;
using System.Text.Json;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;

public class MtlsPopAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    public const string ProtocolScheme = "MTLS_POP";

    public MtlsPopAuthenticationHandler(
        IOptionsMonitor<AuthenticationSchemeOptions> options,
        ILoggerFactory logger,
        UrlEncoder encoder)
        : base(options, logger, encoder)
    {
    }

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        // 1. Extract the MTLS_POP authorization header
        var authHeader = Request.Headers.Authorization.FirstOrDefault();
        if (string.IsNullOrEmpty(authHeader) ||
            !authHeader.StartsWith($"{ProtocolScheme} ", StringComparison.OrdinalIgnoreCase))
        {
            return AuthenticateResult.NoResult();
        }

        var authToken = authHeader.Substring($"{ProtocolScheme} ".Length).Trim();

        try
        {
            // 2. Parse the JWT token
            var handler = new JsonWebTokenHandler();
            var token = handler.ReadJsonWebToken(authToken);

            // 3. Extract the 'cnf' claim
            var cnfClaim = token.Claims.FirstOrDefault(c => c.Type == "cnf");
            if (cnfClaim == null)
            {
                return AuthenticateResult.Fail("Missing 'cnf' claim in MTLS_POP token");
            }

            // 4. Extract certificate thumbprint from cnf claim
            var cnfJson = JsonDocument.Parse(cnfClaim.Value);
            if (!cnfJson.RootElement.TryGetProperty("x5t#S256", out var x5tS256Element))
            {
                return AuthenticateResult.Fail("Missing 'x5t#S256' in cnf claim");
            }

            var expectedThumbprint = x5tS256Element.GetString();

            // 5. Get client certificate from TLS connection
            var clientCert = Context.Connection.ClientCertificate;
            if (clientCert != null)
            {
                var actualThumbprint = GetCertificateThumbprint(clientCert);

                // 6. Validate certificate binding
                if (!string.Equals(actualThumbprint, expectedThumbprint,
                    StringComparison.OrdinalIgnoreCase))
                {
                    return AuthenticateResult.Fail(
                        "Certificate thumbprint mismatch with cnf claim");
                }
            }

            // 7. Create claims principal
            var claims = token.Claims.Select(c => new Claim(c.Type, c.Value)).ToList();
            var identity = new ClaimsIdentity(claims, ProtocolScheme);
            var principal = new ClaimsPrincipal(identity);
            var ticket = new AuthenticationTicket(principal, ProtocolScheme);

            return AuthenticateResult.Success(ticket);
        }
        catch (Exception ex)
        {
            Logger.LogError(ex, "Error validating mTLS PoP token");
            return AuthenticateResult.Fail($"Validation error: {ex.Message}");
        }
    }

    private static string GetCertificateThumbprint(X509Certificate2 certificate)
    {
        using var sha256 = SHA256.Create();
        var hash = sha256.ComputeHash(certificate.RawData);
        return Base64UrlEncoder.Encode(hash);
    }
}

Utiliser la liaison de jetons dans les applications

Les exemples suivants montrent comment intégrer la liaison de jetons poP mTLS dans différents types d’application.

Appeler des API à partir d’une console ou d’une application démon

L'exemple suivant illustre une application console ou application démon qui appelle une API en aval avec la liaison de jeton PoP mTLS.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;

public class Program
{
    public static async Task Main(string[] args)
    {
        // Create and configure token acquirer
        var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();

        tokenAcquirerFactory.Services.AddDownstreamApi(
            "SecureApi",
            tokenAcquirerFactory.Configuration.GetSection("SecureApi"));

        var serviceProvider = tokenAcquirerFactory.Build();

        // Get IDownstreamApi instance
        var downstreamApi = serviceProvider.GetRequiredService<IDownstreamApi>();

        // Call API with mTLS PoP token
        var response = await downstreamApi.GetForAppAsync<ApiResponse>("SecureApi");

        Console.WriteLine($"Result: {response?.Data}");
    }
}

public class ApiResponse
{
    public string? Data { get; set; }
}

Appeler des API à partir d’une application web ASP.NET Core

L’exemple suivant montre un contrôleur qui appelle une API en aval avec une liaison de jeton PoP mTLS.

using Microsoft.AspNetCore.Mvc;
using Microsoft.Identity.Abstractions;

[ApiController]
[Route("api/[controller]")]
public class DataController : ControllerBase
{
    private readonly IDownstreamApi _downstreamApi;
    private readonly ILogger<DataController> _logger;

    public DataController(
        IDownstreamApi downstreamApi,
        ILogger<DataController> logger)
    {
        _downstreamApi = downstreamApi;
        _logger = logger;
    }

    [HttpGet]
    public async Task<IActionResult> GetSecureData()
    {
        try
        {
            // Call downstream API with mTLS PoP token binding
            var data = await _downstreamApi.GetForAppAsync<SecureData>(
                "SecureApi");

            return Ok(data);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to retrieve secure data");
            return StatusCode(500, "Failed to retrieve data");
        }
    }
}

public class SecureData
{
    public string? Id { get; set; }
    public string? Value { get; set; }
}

Configurer DownstreamApiOptions de manière programmatique

L’exemple suivant définit les options poP mTLS directement dans le code au lieu de fichiers de configuration.

using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;

public class SecureApiService
{
    private readonly IDownstreamApi _downstreamApi;

    public SecureApiService(IDownstreamApi downstreamApi)
    {
        _downstreamApi = downstreamApi;
    }

    public async Task<T?> CallSecureApiAsync<T>(string endpoint) where T : class
    {
        return await _downstreamApi.GetForAppAsync<T>(
            serviceName: null,
            downstreamApiOptionsOverride: options =>
            {
                options.BaseUrl = "https://api.secure.com";
                options.RelativePath = endpoint;
                options.ProtocolScheme = "MTLS_POP";
                options.RequestAppToken = true;
                options.Scopes = new[] { "api://secure-api/.default" };
            });
    }
}

Utiliser MicrosoftIdentityMessageHandler avec la liaison de jetons

MicrosoftIdentityMessageHandler prend en charge la liaison des jetons PoP mTLS via les méthodes d'extension AddMicrosoftIdentityMessageHandler. Lorsqu’il ProtocolScheme est défini sur "MTLS_POP", le gestionnaire acquiert automatiquement un jeton lié et envoie des requêtes via un client HTTP configuré avec mTLS.

Configurer les options en ligne

L’exemple suivant enregistre un client HTTP avec une configuration mTLS PoP inline et affiche son utilisation dans un service.

// Program.cs
services.AddHttpClient("MtlsPopClient", client =>
{
    client.BaseAddress = new Uri("https://api.contoso.com");
})
.AddMicrosoftIdentityMessageHandler(options =>
{
    options.Scopes.Add("api://contoso/.default");
    options.ProtocolScheme = "MTLS_POP";
    options.RequestAppToken = true;
});

// Usage in a service
public class SecureApiService
{
    private readonly HttpClient _httpClient;

    public SecureApiService(IHttpClientFactory factory)
    {
        _httpClient = factory.CreateClient("MtlsPopClient");
    }

    public async Task<string> GetSecureDataAsync()
    {
        // Authentication and mTLS certificate binding are automatic
        var response = await _httpClient.GetAsync("/api/secure-data");
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync();
    }
}

Charger la configuration à partir de appsettings.json

Vous pouvez également charger des paramètres de liaison de jeton à partir de votre fichier de configuration.

appsettings.json:

{
  "DownstreamApis": {
    "SecureApi": {
      "Scopes": ["api://secure-api/.default"],
      "ProtocolScheme": "MTLS_POP",
      "RequestAppToken": true
    }
  }
}

Program.cs : le code suivant inscrit le client HTTP à l’aide de la section de configuration.

services.AddHttpClient("SecureApiClient", client =>
{
    client.BaseAddress = new Uri("https://secure-api.example.com");
})
.AddMicrosoftIdentityMessageHandler(
    configuration.GetSection("DownstreamApis:SecureApi"),
    "SecureApi");

Appliquer un liage de jeton par requête

Utilisez des options par requête lorsque certaines requêtes nécessitent une liaison de jetons et que d'autres non.

services.AddHttpClient("FlexibleClient")
    .AddMicrosoftIdentityMessageHandler();

// In a service:
public async Task<string> CallWithTokenBindingAsync()
{
    var request = new HttpRequestMessage(HttpMethod.Get, "https://api.contoso.com/secure")
        .WithAuthenticationOptions(options =>
        {
            options.Scopes.Add("api://contoso/.default");
            options.ProtocolScheme = "MTLS_POP";
            options.RequestAppToken = true;
        });

    var response = await _httpClient.SendAsync(request);
    response.EnsureSuccessStatusCode();
    return await response.Content.ReadAsStringAsync();
}

Pour plus d’informations sur MicrosoftIdentityMessageHandlerles API personnalisées, consultez la documentation sur les API personnalisées.

Créer un HttpClient personnalisé avec le fournisseur d’en-tête d’autorisation

Utilisez cette approche pour les scénarios qui nécessitent davantage de contrôle sur les requêtes HTTP. L’exemple suivant acquiert un en-tête d’autorisation lié et crée un client HTTP configuré par mTLS.

using Microsoft.Identity.Abstractions;
using System.Net.Http.Headers;

public class CustomApiClient
{
    private readonly IAuthorizationHeaderProvider _authProvider;
    private readonly IHttpClientFactory _httpClientFactory;

    public CustomApiClient(
        IAuthorizationHeaderProvider authProvider,
        IHttpClientFactory httpClientFactory)
    {
        _authProvider = authProvider;
        _httpClientFactory = httpClientFactory;
    }

    public async Task<string> CallApiWithCustomLogicAsync()
    {
        // Create downstream API options for mTLS PoP
        var apiOptions = new DownstreamApiOptions
        {
            BaseUrl = "https://api.contoso.com",
            ProtocolScheme = "MTLS_POP",
            RequestAppToken = true,
            Scopes = new[] { "api://contoso/.default" }
        };

        // Get authorization header with binding certificate info
        var authResult = await (_authProvider as IBoundAuthorizationHeaderProvider)
            ?.CreateBoundAuthorizationHeaderAsync(apiOptions)!;

        if (authResult.IsSuccess)
        {
            // Create HTTP client with certificate binding
            var httpClient = authResult.Value.BindingCertificate != null
                ? CreateMtlsHttpClient(authResult.Value.BindingCertificate)
                : _httpClientFactory.CreateClient();

            // Set authorization header
            httpClient.DefaultRequestHeaders.Authorization =
                AuthenticationHeaderValue.Parse(authResult.Value.AuthorizationHeaderValue);

            // Make API call
            var response = await httpClient.GetAsync(
                $"{apiOptions.BaseUrl}/api/endpoint");

            return await response.Content.ReadAsStringAsync();
        }

        throw new InvalidOperationException("Failed to acquire token");
    }

    private HttpClient CreateMtlsHttpClient(X509Certificate2 certificate)
    {
        var handler = new HttpClientHandler();
        handler.ClientCertificates.Add(certificate);
        return new HttpClient(handler);
    }
}

Examiner la structure des jetons

Les exemples suivants montrent comment les jetons standard et liés diffèrent.

Comparer les jetons OAuth2 standard

Un jeton OAuth2 standard ne contient aucune information de liaison de certificat.

{
  "aud": "api://your-api",
  "iss": "https://login.microsoftonline.com/tenant-id/",
  "iat": 1234567890,
  "exp": 1234571490,
  "appid": "client-id",
  "tid": "tenant-id"
}

Passer en revue les jetons poP mTLS avec la liaison

Un jeton poP mTLS inclut la cnf revendication qui lie le jeton à un certificat spécifique.

{
  "aud": "api://your-api",
  "iss": "https://login.microsoftonline.com/tenant-id/",
  "iat": 1234567890,
  "exp": 1234571490,
  "appid": "client-id",
  "tid": "tenant-id",
  "cnf": {
    "x5t#S256": "buc7x2HxS_hPnVJb9J5mwPr6jCw8Y_2LHDz-gp_-6KM"
  }
}

La revendication cnf (confirmation) contient l'empreinte SHA-256 du certificat, encodée au format Base64Url.

Comprendre les limitations actuelles

Passez en revue les contraintes suivantes avant d’implémenter la liaison de jeton mTLS PoP.

Prendre en charge uniquement les jetons d’application

La liaison de jeton prend actuellement en charge les jetons d’application uniquement ("app-only"). Les jetons délégués (utilisateur) ne sont pas pris en charge.

Définir le schéma de protocole

La propriété ProtocolScheme doit être explicitement définie à "MTLS_POP" afin d’activer la liaison de jeton. S’il n’est pas défini, l’authentification du porteur standard est utilisée.

Répondre aux exigences de certificat

  • Le certificat doit être configuré dans ClientCredentials avec SendX5c défini sur true
  • Le certificat doit être accessible au moment de l’acquisition de jetons

Résoudre les problèmes courants

Utilisez les instructions suivantes pour diagnostiquer et résoudre les problèmes de liaison de jeton.

Résoudre les problèmes courants

1. « Revendication « cnf » manquante dans le jeton »

Cause : la liaison de jeton n’a pas été correctement configurée ou le jeton est un jeton porteur standard.

Solution : vérifiez que ProtocolScheme est définie sur "MTLS_POP" et que RequestAppToken est true.

{
  "DownstreamApi": {
    "ProtocolScheme": "MTLS_POP",  // ensure this is set
    "RequestAppToken": true
  }
}

2. « Incompatibilité de l’empreinte numérique du certificat »

Cause : le certificat présenté à l’API ne correspond pas à celui utilisé pour l’acquisition de jetons.

Solution:

  • Vérifiez que le même certificat est utilisé pour l’acquisition de jetons et les appels d’API
  • Vérifier la configuration du chargement du certificat dans ClientCredentials
  • Vérifier que le certificat n’a pas expiré ou renouvelé

3. « Un certificat, requis pour la liaison de jeton, est manquant »

Cause : aucun certificat n’est configuré dans les paramètres Microsoft Entra.

Solution : ajoutez un certificat à votre ClientCredentials configuration et définissez SendX5c sur true.

{
  "AzureAd": {
    "ClientCredentials": [
      {
        "SourceType": "StoreWithDistinguishedName",
        "CertificateStorePath": "CurrentUser/My",
        "CertificateDistinguishedName": "CN=YourCertificate"
      }
    ],
    "SendX5c": true  // required for token binding
  }
}

4. « La liaison de jeton nécessite une acquisition activée des jetons d'application »

Cause : RequestAppToken n’est pas définie sur true.

Solution : définissez RequestAppToken sur true dans vos options.

var options = new DownstreamApiOptions
{
    ProtocolScheme = "MTLS_POP",
    RequestAppToken = true,  // must be true
};

Liaison de jeton de débogage

Utilisez les techniques suivantes pour analyser les problèmes de liaison de jeton.

Activer la journalisation détaillée

Ajoutez la configuration suivante pour activer la journalisation au niveau du débogage pour Microsoft. Identity.Web.

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.Identity.Web": "Debug"
    }
  }
}

Inspecter les revendications de jeton

Utilisez le code suivant pour répertorier toutes les revendications dans un jeton et rechercher la cnf revendication.

var handler = new JsonWebTokenHandler();
var token = handler.ReadJsonWebToken(tokenString);

foreach (var claim in token.Claims)
{
    Console.WriteLine($"{claim.Type}: {claim.Value}");
}

// Look for 'cnf' claim with x5t#S256
var cnfClaim = token.Claims.FirstOrDefault(c => c.Type == "cnf");

Vérifier l’empreinte numérique du certificat

Utilisez le code suivant pour calculer et afficher l’empreinte NUMÉRIQUE SHA-256 d’un certificat pour la comparaison.

using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Microsoft.IdentityModel.Tokens;

var cert = new X509Certificate2("path/to/cert.pfx", "password");
using var sha256 = SHA256.Create();
var hash = sha256.ComputeHash(cert.RawData);
var thumbprint = Base64UrlEncoder.Encode(hash);
Console.WriteLine($"Certificate thumbprint: {thumbprint}");

Suivez les instructions de sécurité

Appliquez les pratiques de sécurité suivantes lorsque vous mettez en œuvre la liaison de jeton.

Gérer les certificats de manière sécurisée

  • Stockez de manière sécurisée : utilisez Azure Key Vault ou d'autres magasins de certificats sécurisés
  • Rotation régulière : Mettre en œuvre des procédures de rotation de certificats
  • Expiration du moniteur : configurer des alertes pour l’expiration du certificat
  • Restreindre l’accès : Limiter les personnes pouvant accéder aux clés privées de certificat

Sécuriser les connexions réseau

  • Exiger TLS 1.2+ : vérifiez que toutes les connexions utilisent des versions TLS modernes
  • Valider les certificats : Implémenter une validation de certificat appropriée sur le serveur
  • Utiliser des chiffrements forts : configurer des suites de chiffrement sécurisées

Gérer les jetons de manière sécurisée

  • Durées de vie courtes : Utiliser des jetons de courte durée (recommandé : 1 heure)
  • Stockage approprié : Ne jamais journaliser ou exposer des jetons
  • Valider soigneusement : vérifier toutes les réclamations, l’expiration et le liaisonnement

Suivre les bonnes pratiques

Gardez à l’esprit les recommandations suivantes lorsque vous déployez la liaison de jeton mTLS PoP.

  1. Toujours utiliser HTTPS : mTLS PoP nécessite un transport sécurisé
  2. Utilisez un certificat qui stocke le matériel de clé privée dans le matériel, par exemple, dans le TPM : privilégiez le matériel au logiciel pour une meilleure protection
  3. Implémenter une gestion appropriée des erreurs : gérer correctement les erreurs de certificat et de jeton
  4. Surveiller l’expiration du certificat : Automatiser le renouvellement des certificats
  5. Utiliser des certificats distincts par environnement : dev, préproduction et certificats de production
  6. Consigner les événements de sécurité : surveiller les échecs de liaison de jeton et les incompatibilités de certificat
  7. Tester la rotation des certificats : vérifiez que votre application gère les mises à jour des certificats
  8. Documenter votre configuration : conservez la documentation claire des exigences de certificat

Explorer un exemple de code

Des exemples de mise en œuvre complets illustrant la liaison de jeton PoP mTLS sont disponibles dans le référentiel.

Ces exemples illustrent :

  • Configuration complète du client et du serveur
  • Acquisition de jetons avec liaison de certificat
  • Implémentation de gestionnaire d’authentification personnalisée
  • Validation de certificat et vérification de l’empreinte numérique