{"id":838,"date":"2024-08-22T19:35:14","date_gmt":"2024-08-22T19:35:14","guid":{"rendered":"https:\/\/oussamasaidi.com\/?p=838"},"modified":"2025-12-20T11:14:44","modified_gmt":"2025-12-20T11:14:44","slug":"comment-implementer-authentification-cle-api-aspnet-core","status":"publish","type":"post","link":"https:\/\/oussamasaidi.com\/en\/comment-implementer-authentification-cle-api-aspnet-core\/","title":{"rendered":".NET Core : impl\u00e9menter l\u2019authentification par cl\u00e9 API en C#"},"content":{"rendered":"<ul><li><a class=\"aioseo-toc-item\" href=\"#aioseo-arriere-plan\">Contexte<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#aioseo-etape-1-creer-un-attribut-de-cle-api\">Cr\u00e9ation de l&#039;attribut de cl\u00e9 API<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#aioseo-etape-n2-implementer-le-filtre-dautorisation-apikey\">Impl\u00e9menter du filtre d&#039;autorisation ApiKey<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#aioseo-etape-n3-implementer-apikeyvalidator\">impl\u00e9mentation de l&#039;ApiKeyValidator<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#aioseo-test-des-points-de-terminaison-de-lapi\">Tester l&#039;API<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#aioseo-bonus-utilisez-le-middleware\">Utilisez le middleware<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#aioseo-conclusion\">Conclusion<\/a><\/li><li><a class=\"aioseo-toc-item\" href=\"#aioseo-derniers-articles\">Derniers Articles<\/a><\/li><\/ul>\n\n\n<p>Vous pouvez trouver le code source complet sur <a href=\"https:\/\/github.com\/oussama-saidi\/net-api-key-authentication\" target=\"_blank\" rel=\"noopener\" title=\"\">github<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"aioseo-arriere-plan\">Contexte<\/h2>\n\n\n\n<p>Alors, qu\u2019est-ce que l\u2019authentification par cl\u00e9 API dans ASP.NET Core ?<\/p>\n\n\n\n<p>Prenons un exemple concret.<\/p>\n\n\n\n<p>Imaginez que vous ayez d\u00e9velopp\u00e9 un tableau de bord m\u00e9t\u00e9o qui r\u00e9cup\u00e8re les donn\u00e9es de votre propre API m\u00e9t\u00e9o.<br>Ce tableau de bord affiche des donn\u00e9es m\u00e9t\u00e9orologiques, des pr\u00e9visions et d&rsquo;autres informations en temps r\u00e9el.<\/p>\n\n\n\n<p>Cependant, vous souhaitez :<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">Limiter l&rsquo;acc\u00e8s<\/mark><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\"> <\/mark><\/strong>: vous ne voulez pas que n&rsquo;importe qui puisse acc\u00e9der \u00e0 votre API et commencer \u00e0 en extraire des donn\u00e9es.<\/li>\n\n\n\n<li><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">Suivre l&rsquo;utilisation<\/mark><\/strong> : vous souhaitez savoir quels clients utilisent votre API, \u00e0 quelle fr\u00e9quence et \u00e0 quelles fins.<\/li>\n\n\n\n<li><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><strong>Pr\u00e9venir les abus<\/strong> <\/mark>: sans une certaine sorte d&rsquo;authentification, quelqu&rsquo;un pourrait spammer votre API avec des requ\u00eates, consommant des ressources et potentiellement vous co\u00fbtant de l&rsquo;argent.<\/li>\n\n\n\n<li><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><strong>Commercialisation<\/strong> <\/mark>: Si votre API fournit des donn\u00e9es pr\u00e9cieuses, vous souhaiterez peut-\u00eatre les mon\u00e9tiser. Avoir une cl\u00e9 API pour chaque client vous permet de mettre en \u0153uvre facilement diff\u00e9rents niveaux de tarification.<\/li>\n<\/ul>\n\n\n\n<p>De cette fa\u00e7on, vous pouvez vous assurer que seuls les clients autoris\u00e9s acc\u00e8dent \u00e0 vos donn\u00e9es, savoir qui y acc\u00e8de et potentiellement m\u00eame \u00e0 quelle quantit\u00e9 ils y acc\u00e8dent. Ainsi, en impl\u00e9mentant l&rsquo;authentification par cl\u00e9 API comme dans l&rsquo;exemple, vous pouvez s\u00e9curiser votre API pour vous assurer qu&rsquo;elle est utilis\u00e9e uniquement de la mani\u00e8re que vous avez explicitement autoris\u00e9e.<\/p>\n\n\n\n<p>Vraiment sympa, non ?<\/p>\n\n\n\n<p>Voyons comment impl\u00e9menter l&rsquo;authentification par cl\u00e9 API dans ASP.NET Core \u00e0 l&rsquo;aide de C#.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"aioseo-etape-1-creer-un-attribut-de-cle-api\">Cr\u00e9ation de l&rsquo;attribut de cl\u00e9 API<\/h2>\n\n\n\n<p>Pourquoi as-tu besoin de \u00e7a ?<\/p>\n\n\n\n<p>La classe <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ApiKeyAttribute <\/mark><\/strong>d\u00e9rive de <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ServiceFilterAttribute <\/mark><\/strong>et est utilis\u00e9e pour d\u00e9corer les contr\u00f4leurs ou les actions o\u00f9 vous souhaitez que cette autorisation sp\u00e9cifique ait lieu.<\/p>\n\n\n\n<p>Par exemple, vous souhaitez d\u00e9corer ce point de terminaison :<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[ApiKey]\n[HttpGet(Name = \"GetAllUsers\")]\npublic List&lt;string> GetAll()\n{\n    return new List&lt;string> { \"Stefan\" };\n}<\/pre>\n\n\n\n<p>Pour y parvenir, vous devez proc\u00e9der comme suit :<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public class ApiKeyAttribute : ServiceFilterAttribute\n{\n    public ApiKeyAttribute() : base(typeof(ApiKeyAuthorizationFilter))\n}<\/pre>\n\n\n\n<p>Le constructeur appelle le constructeur de base avec typeof( <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ApiKeyAuthorizationFilter <\/mark><\/strong>), ce qui signifie qu&rsquo;il attache le <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ApiKeyAuthorizationFilter <\/mark><\/strong>aux actions d\u00e9cor\u00e9es avec cet attribut.<\/p>\n\n\n\n<p>Dans la classe <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ApiKeyAttribute<\/mark><\/strong>, la ligne : <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">base(typeof(ApiKeyAuthorizationFilter))<\/mark><\/strong> signifie que cet attribut est essentiellement un wrapper autour de <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ApiKeyAuthorizationFilter<\/mark><\/strong>.<\/p>\n\n\n\n<p>Lorsque vous d\u00e9corez un contr\u00f4leur ou une m\u00e9thode d&rsquo;action avec <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">[ApiKey]<\/mark><\/strong> , cela d\u00e9clenchera la m\u00e9thode <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">OnAuthorization <\/mark><\/strong>d&rsquo;<strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ApiKeyAuthorizationFilter<\/mark><\/strong> pour ce contr\u00f4leur ou cette action sp\u00e9cifique.<\/p>\n\n\n\n<p>Nous avons donc besoin d&rsquo;<strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ApiKeyAuthorizationFilter <\/mark><\/strong>avec la m\u00e9thode <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">OnAuthorization <\/mark><\/strong>&#8211; cr\u00e9ons-le \u00e0 l&rsquo;\u00e9tape suivante.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"aioseo-etape-n2-implementer-le-filtre-dautorisation-apikey\">Impl\u00e9menter du filtre d&rsquo;autorisation ApiKey<\/h2>\n\n\n\n<p>La classe <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ApiKeyAuthorizationFilter <\/mark><\/strong>impl\u00e9mente <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">IAuthorizationFilter <\/mark><\/strong>, ce qui signifie qu&rsquo;elle contient une logique \u00e0 ex\u00e9cuter lorsqu&rsquo;une requ\u00eate n\u00e9cessite une autorisation. Ce filtre v\u00e9rifie si une cl\u00e9 API est pr\u00e9sente et si elle est valide.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public class ApiKeyAuthorizationFilter : IAuthorizationFilter\n{\n    private const string ApiKeyHeaderName = \"x-api-key\";\n    private readonly IApiKeyValidator _apiKeyValidator;\n\n    public ApiKeyAuthorizationFilter(IApiKeyValidatior apiKeyValidator)\n    {\n        _apiKeyValidator = apiKeyValidator;\n    }\n\n    public void OnAuthorization(AuthorizationFilterContext context)\n    {\n        string apiKey = context.HttpContext.Request.Headers[ApiKeyHeaderName];\n\n        if(!_apiKeyValidator.IsValid(apiKey))\n        {\n            context.Result = new UnauthorizedResult();\n        }\n    }\n}<\/pre>\n\n\n\n<p>M\u00e9thode <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">OnAuthorization <\/mark><\/strong>:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Cette m\u00e9thode est appel\u00e9e lorsque la demande est autoris\u00e9e. Il extrait la cl\u00e9 API de l&rsquo;en-t\u00eate de la requ\u00eate<\/li>\n<\/ul>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">var apiKey = context.HttpContext.Request.Headers[ApiKeyHeaderName];<\/pre>\n\n\n\n<p>Ensuite, il utilise la m\u00e9thode _<strong>apiKeyValidator.IsValid(apiKey)<\/strong> pour v\u00e9rifier si la cl\u00e9 API est valide.<\/p>\n\n\n\n<p>Si la cl\u00e9 API n&rsquo;est pas valide, <strong>context.Result = new UnauthorizedResult();<\/strong> d\u00e9finit la r\u00e9ponse sur non autoris\u00e9, rejetant ainsi la demande.<\/p>\n\n\n\n<p>Super. Mais vous n&rsquo;avez pas <strong>_apiKeyValidator<\/strong>, n&rsquo;est-ce pas ?<\/p>\n\n\n\n<p>Aucun probl\u00e8me. Mettons-le en \u0153uvre.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"aioseo-etape-n3-implementer-apikeyvalidator\">impl\u00e9mentation de l&rsquo;ApiKeyValidator<\/h2>\n\n\n\n<p>Votre classe <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ApiKeyAuthorizationFilter <\/mark><\/strong>s&rsquo;appuie sur une instance d&rsquo;une classe qui impl\u00e9mente <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">IApiKeyValidator <\/mark><\/strong>pour valider les cl\u00e9s API. La m\u00e9thode <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">IsValid <\/mark><\/strong>de cette instance sera appel\u00e9e pour v\u00e9rifier si une cl\u00e9 API est valide ou non. Actuellement, puisque <strong>IsValid <\/strong>renvoie false, toutes les demandes seraient consid\u00e9r\u00e9es comme non autoris\u00e9es.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public class ApiKeyValidator : IApiKeyValidator\n{\n    public bool IsValid(string apiKey)\n    {\n        \/\/Change logic for validation api key\n        return false;\n    }\n}\n\npublic interface IApiKeyValidator\n{\n    bool IsValid(string apiKey);\n}<\/pre>\n\n\n\n<p>Bien s\u00fbr, rien de tout cela ne fonctionnerait sans l\u2019injection de d\u00e9pendances, enregistrons donc les services n\u00e9cessaires.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">builder.Services.AddSingleton&lt;ApiKeyAuthorizationFilter>();\nbuilder.Services.AddSingleton&lt;IApiKeyValidator, ApiKeyValidator>();<\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"aioseo-test-des-points-de-terminaison-de-lapi\">Tester l&rsquo;API<\/h2>\n\n\n\n<p>Et c&rsquo;est tout. Vous avez impl\u00e9ment\u00e9 l&rsquo;authentification par cl\u00e9 API.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"aioseo-bonus-utilisez-le-middleware\">Utilisez le middleware<\/h2>\n\n\n\n<p>Vous pouvez obtenir absolument le m\u00eame effet en utilisant un middleware.<\/p>\n\n\n\n<p>Voici comment proc\u00e9der :<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"539\" src=\"https:\/\/oussamasaidi.com\/wp-content\/uploads\/2024\/08\/image-1-1024x539.png\" alt=\"Sch\u00e9ma de authentification par cl\u00e9 API ASP.NET Core\" class=\"wp-image-860\" srcset=\"https:\/\/oussamasaidi.com\/wp-content\/uploads\/2024\/08\/image-1-1024x539.png 1024w, https:\/\/oussamasaidi.com\/wp-content\/uploads\/2024\/08\/image-1-300x158.png 300w, https:\/\/oussamasaidi.com\/wp-content\/uploads\/2024\/08\/image-1-768x404.png 768w, https:\/\/oussamasaidi.com\/wp-content\/uploads\/2024\/08\/image-1-1536x808.png 1536w, https:\/\/oussamasaidi.com\/wp-content\/uploads\/2024\/08\/image-1-2048x1078.png 2048w, https:\/\/oussamasaidi.com\/wp-content\/uploads\/2024\/08\/image-1-18x9.png 18w, https:\/\/oussamasaidi.com\/wp-content\/uploads\/2024\/08\/image-1-256x135.png 256w, https:\/\/oussamasaidi.com\/wp-content\/uploads\/2024\/08\/image-1-950x500.png 950w, https:\/\/oussamasaidi.com\/wp-content\/uploads\/2024\/08\/image-1-1920x1011.png 1920w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">public class ApiKeyMiddleware\n{\n    private readonly RequestDelegate _next;\n    private const string ApiKeyHeaderName = \"x-api-key\";\n\n    public ApiKeyMiddleware(RequestDelegate next)\n    {\n        _next = next;\n    }\n\n    public async Task InvokeAsync(HttpContext context)\n    {\n        if(!context.Request.Headers.TryGetValue(ApiKeyHeaderName, out var extractedApiKey))\n        {\n            context.Response.StatusCode = 401;\n            await context.Response.WriteAsync(\"Api Key was not provided.\");\n            return;\n        }\n\n        if(extractedApiKey != \"API_KEY\")\n        {\n            context.Response.StatusCode = 401;\n            await context.Response.WriteAsync(\"Unauthorized.\");\n            return;\n        }\n\n        await _next(context);\n    }\n}<\/pre>\n\n\n\n<p>Et c&rsquo;est tout.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"aioseo-conclusion\">Conclusion<\/h2>\n\n\n\n<p>Dans l&rsquo;article d&rsquo;aujourd&rsquo;hui, je vous ai montr\u00e9 comment impl\u00e9menter l&rsquo;authentification par cl\u00e9 API dans ASP.NET Core en un petit nombre d&rsquo;\u00e9tapes et en peu de temps.<\/p>\n\n\n\n<p>Il faut mettre en \u0153uvre 3 choses :<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ApiKeyAttribute <\/mark><\/strong>&#8211; Vous permet de d\u00e9corer les contr\u00f4leurs et les points de terminaison avec <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">[ApiKey]<\/mark><\/strong>.<\/li>\n\n\n\n<li><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ApiKeyAuthoizationFilter <\/mark><\/strong>&#8211; Ex\u00e9cute la m\u00e9thode <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">OnAuthorization <\/mark><\/strong>\u00e0 chaque requ\u00eate. C\u2019est l\u00e0 que vous mettez r\u00e9ellement la logique compl\u00e8te de votre authentification.<\/li>\n\n\n\n<li><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><strong>ApiKeyValidator <\/strong><\/mark>&#8211; Uniquement la logique encapsul\u00e9e de la fa\u00e7on dont vous validerez la cl\u00e9 API que vous recevez dans la demande.<\/li>\n<\/ol>\n\n\n\n<p>Vous pouvez acc\u00e9der au <a href=\"https:\/\/github.com\/oussama-saidi\/net-api-key-authentication\" target=\"_blank\" rel=\"noopener\" title=\"\">r\u00e9f\u00e9rentiel GitHub <\/a>du projet et vous familiariser avec les d\u00e9tails.<\/p>\n\n\n\n<p>C&rsquo;est tout pour moi aujourd&rsquo;hui.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"aioseo-derniers-articles\">Derniers Articles<\/h2>\n\n\n\n<ul id=\"block-957e2f94-bcbc-4609-b8f3-4ca3d686660e\" class=\"wp-block-list\">\n<li><a href=\"https:\/\/oussamasaidi.com\/en\/hangfire-avec-asp-net-core\/\">Hangfire avec ASP.NET Core<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/oussamasaidi.com\/en\/automapper-net-core\/\">Premiers pas avec AutoMapper dans ASP.NET Core<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/oussamasaidi.com\/en\/serilog-in-aspnet-core-3-1\/\">Serilog dans ASP.NET Core 3.1-La journalisation structur\u00e9e simplifi\u00e9e<\/a><\/li>\n<\/ul>\n\n\n\n<div class=\"wp-container-6 wp-block-columns alignwide\">\n<div class=\"wp-container-5 wp-elements-e1ba0e3d9d30b7fec5c25e47c471e6ef wp-block-column has-text-color has-background has-link-color\" style=\"background-color:#c0ebf1;color:#000000;padding-top:2em;padding-right:2em;padding-bottom:2em;padding-left:2em\">\n<h2 id=\"patron\" style=\"font-size:40px\"><strong>Vous aimez le contenu&nbsp;?<\/strong><\/h2>\n\n\n\n<p class=\"has-normal-font-size\"><strong>Si vous aimez mes articles, pensez \u00e0 m\u2019acheter quelques caf\u00e9s !<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-css-opacity is-style-wide\">\n\n\n\n<div class=\"wp-container-4 is-horizontal is-content-justification-center wp-block-buttons alignfull\">\n<div class=\"wp-block-button has-custom-width wp-block-button__width-100\"><a class=\"wp-block-button__link has-white-color has-text-color has-background no-border-radius\" href=\"https:\/\/www.buymeacoffee.com\/oussamasaiI\" style=\"background-color:#000000\" target=\"_blank\" rel=\"noreferrer noopener\">Achetez-moi un caf\u00e9<\/a><\/div>\n<\/div>\n<\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>Vous pouvez trouver le code source complet sur github Contexte Alors, qu\u2019est-ce que l\u2019authentification par cl\u00e9 API dans ASP.NET Core&#8230; <\/p>\n<div class=\"art-el-more\"><a href=\"https:\/\/oussamasaidi.com\/en\/comment-implementer-authentification-cle-api-aspnet-core\/\" class=\"art-link art-color-link art-w-chevron\">Read more<\/a><\/div>","protected":false},"author":1,"featured_media":839,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[40,68,45,41,56,61],"tags":[47,69,81,48,49,54,53,70],"ppma_author":[286],"class_list":["post-838","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-netcore","category-api","category-asp-net","category-c","category-c-2","category-web-api","tag-net-core","tag-api","tag-api-key","tag-asp-net","tag-c-sharp","tag-c","tag-dot-net-core","tag-web-api"],"acf":[],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/oussamasaidi.com\/wp-content\/uploads\/2024\/07\/Capture00.png","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":1714,"url":"https:\/\/oussamasaidi.com\/en\/https-oussamasaidi-com-restful-api-mastery-best-practices-with-asp-net-core-part-2\/","url_meta":{"origin":838,"position":0},"title":"RESTful API best practices\u00a0with ASP.NET Core Part 2","author":"Saidi Oussama","date":"December 20, 2025","format":false,"excerpt":"Testing, Performance, Security, Microservices & Deployment Introduction: From Solid Foundations to Production Excellence In Part 1 of RESTful API Mastery, we established the architectural and technical foundations required to build reliable, evolvable RESTful APIs with ASP.NET Core. However, a well-designed API only becomes truly valuable when it is tested, observable,\u2026","rel":"","context":"In &quot;.Net Core&quot;","block_context":{"text":".Net Core","link":"https:\/\/oussamasaidi.com\/en\/category\/netcore\/"},"img":{"alt_text":"RESTful API Mastery","src":"https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/12\/restful-api-mastery-best-practices-with-asp-net-core-2r.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/12\/restful-api-mastery-best-practices-with-asp-net-core-2r.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/12\/restful-api-mastery-best-practices-with-asp-net-core-2r.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/12\/restful-api-mastery-best-practices-with-asp-net-core-2r.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/12\/restful-api-mastery-best-practices-with-asp-net-core-2r.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/12\/restful-api-mastery-best-practices-with-asp-net-core-2r.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":1639,"url":"https:\/\/oussamasaidi.com\/en\/restful-api-mastery-best-practices-with-asp-net-core\/","url_meta":{"origin":838,"position":1},"title":"RESTful API Best Practices with ASP.NET Core","author":"Saidi Oussama","date":"December 16, 2025","format":false,"excerpt":"Professional Best Practices, Versioning Strategies & Advanced Serialization (Part 1) In this blog Introduction: Building Enterprise-Grade RESTful APIs with ASP.NET Core1. RESTful APIs in the Modern ASP.NET Core EcosystemWhy REST Still Dominates2. REST Architectural Constraints Every ASP.NET Core API Must EnforceClient\u2013Server SeparationStatelessnessUniform Interface3. Establishing a Clean and Scalable ASP.NET Core\u2026","rel":"","context":"In &quot;.Net Core&quot;","block_context":{"text":".Net Core","link":"https:\/\/oussamasaidi.com\/en\/category\/netcore\/"},"img":{"alt_text":"RESTful API Mastery","src":"https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/12\/restful-api-mastery-best-practices-with-asp-net-core-cover-scaled.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/12\/restful-api-mastery-best-practices-with-asp-net-core-cover-scaled.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/12\/restful-api-mastery-best-practices-with-asp-net-core-cover-scaled.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/12\/restful-api-mastery-best-practices-with-asp-net-core-cover-scaled.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/12\/restful-api-mastery-best-practices-with-asp-net-core-cover-scaled.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/12\/restful-api-mastery-best-practices-with-asp-net-core-cover-scaled.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":1325,"url":"https:\/\/oussamasaidi.com\/en\/building-professional-modern-api-documentation-in-net-core-with-scalar\/","url_meta":{"origin":838,"position":2},"title":"Building Professional, Modern API Documentation in .NET Core with Scalar","author":"Saidi Oussama","date":"November 19, 2025","format":false,"excerpt":"Introduction In today\u2019s software ecosystem, APIs are everywhere. Whether you are building a mobile application, a microservices architecture, or an internal company platform, your API is often the backbone of the system. But even the best API becomes useless if developers cannot understand how to consume it. This is why\u2026","rel":"","context":"In &quot;.Net Core&quot;","block_context":{"text":".Net Core","link":"https:\/\/oussamasaidi.com\/en\/category\/netcore\/"},"img":{"alt_text":"Building Professional, Modern API Documentation in .NET Core with Scalar","src":"https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/11\/Building-Professional-Modern-API-Documentation-in-.NET-Core-with-Scalar.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/11\/Building-Professional-Modern-API-Documentation-in-.NET-Core-with-Scalar.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/11\/Building-Professional-Modern-API-Documentation-in-.NET-Core-with-Scalar.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/11\/Building-Professional-Modern-API-Documentation-in-.NET-Core-with-Scalar.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/11\/Building-Professional-Modern-API-Documentation-in-.NET-Core-with-Scalar.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/11\/Building-Professional-Modern-API-Documentation-in-.NET-Core-with-Scalar.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":1035,"url":"https:\/\/oussamasaidi.com\/en\/creer-un-chatbot-avec-deepseek-et-net-9-tutoriel-complet\/","url_meta":{"origin":838,"position":3},"title":"Cr\u00e9er un Chatbot avec DeepSeek et .NET 9 : Tutoriel Complet","author":"Saidi Oussama","date":"April 6, 2025","format":false,"excerpt":"Ce tutoriel vous guidera pas \u00e0 pas pour construire un chatbot utilisant l'API de DeepSeek avec .NET 9. Nous allons cr\u00e9er une application web de chatbot avec ASP.NET Core. Pr\u00e9requis\u00c9tape 1 : Cr\u00e9er une nouvelle application Web ASP.NET Core\u00c9tape 2 : Ajouter les packages n\u00e9cessaires\u00c9tape 3 : Cr\u00e9er les mod\u00e8les\u2026","rel":"","context":"In &quot;.Net Core&quot;","block_context":{"text":".Net Core","link":"https:\/\/oussamasaidi.com\/en\/category\/netcore\/"},"img":{"alt_text":"AI Chatbot with .net core","src":"https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/04\/https___dev-to-uploads.s3.amazonaws.com_uploads_articles_w4yx4rdp1ohuvcb96ypg.webp?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/04\/https___dev-to-uploads.s3.amazonaws.com_uploads_articles_w4yx4rdp1ohuvcb96ypg.webp?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/04\/https___dev-to-uploads.s3.amazonaws.com_uploads_articles_w4yx4rdp1ohuvcb96ypg.webp?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/04\/https___dev-to-uploads.s3.amazonaws.com_uploads_articles_w4yx4rdp1ohuvcb96ypg.webp?resize=700%2C400&ssl=1 2x"},"classes":[]},{"id":1254,"url":"https:\/\/oussamasaidi.com\/en\/how-to-build-an-idempotent-api-with-net-9-ef-core-9-and-polly-v8\/","url_meta":{"origin":838,"position":4},"title":"How to Build an Idempotent API with .NET 9, EF Core 9 and Polly v8","author":"Saidi Oussama","date":"November 6, 2025","format":false,"excerpt":"Introduction Have you ever hit \u201cPay\u201d on a checkout page, the page froze, and you clicked again \u2014 only to be charged twice?That\u2019s exactly what idempotency prevents. In distributed and cloud-native architectures, duplicate requests happen often: client-side retries (mobile poor signal), API Gateway or load-balancer retries, users refreshing a browser\u2026","rel":"","context":"In &quot;.Net Core&quot;","block_context":{"text":".Net Core","link":"https:\/\/oussamasaidi.com\/en\/category\/netcore\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/11\/oussama-saidi-tuto-net-core-rest-api-Idempotent-1.png?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/11\/oussama-saidi-tuto-net-core-rest-api-Idempotent-1.png?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/11\/oussama-saidi-tuto-net-core-rest-api-Idempotent-1.png?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/11\/oussama-saidi-tuto-net-core-rest-api-Idempotent-1.png?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/11\/oussama-saidi-tuto-net-core-rest-api-Idempotent-1.png?resize=1050%2C600&ssl=1 3x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2025\/11\/oussama-saidi-tuto-net-core-rest-api-Idempotent-1.png?resize=1400%2C800&ssl=1 4x"},"classes":[]},{"id":748,"url":"https:\/\/oussamasaidi.com\/en\/swagger-ui-asp-net-core-web-api\/","url_meta":{"origin":838,"position":5},"title":"Configuration et utilisation de Swagger UI dans ASP.NET Core Web API","author":"Saidi Oussama","date":"January 17, 2023","format":false,"excerpt":"Dans cet article, nous allons apprendre \u00e0 int\u00e9grer l'interface utilisateur Swagger UI dans une application API Web ASP.NET Core.\u00a0 Pour t\u00e9l\u00e9charger le code source de cet article, vous pouvez visiter notre d\u00e9p\u00f4t GitHub . Plongeons dedans. Pourquoi devrions-nous documenter notre APISwagger UI\/OpenAPIInt\u00e9gration de Swagger UI dans nos applicationsInstallation du paquetConfiguration\u2026","rel":"","context":"In &quot;.Net Core&quot;","block_context":{"text":".Net Core","link":"https:\/\/oussamasaidi.com\/en\/category\/netcore\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2023\/01\/swaggeruidotnetcore.jpg?resize=350%2C200&ssl=1","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2023\/01\/swaggeruidotnetcore.jpg?resize=350%2C200&ssl=1 1x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2023\/01\/swaggeruidotnetcore.jpg?resize=525%2C300&ssl=1 1.5x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2023\/01\/swaggeruidotnetcore.jpg?resize=700%2C400&ssl=1 2x, https:\/\/i0.wp.com\/oussamasaidi.com\/wp-content\/uploads\/2023\/01\/swaggeruidotnetcore.jpg?resize=1050%2C600&ssl=1 3x"},"classes":[]}],"authors":[{"term_id":286,"user_id":1,"is_guest":0,"slug":"oussama_sa","display_name":"Saidi Oussama","avatar_url":{"url":"https:\/\/oussamasaidi.com\/wp-content\/uploads\/2022\/02\/001_001_cv1.jpg","url2x":"https:\/\/oussamasaidi.com\/wp-content\/uploads\/2022\/02\/001_001_cv1.jpg"},"author_category":"1","first_name":"Oussama","last_name":"SAIDI","user_url":"https:\/\/oussamasaidi.com","job_title":"Senior Fullstack .NET Developer","description":"I\u2019m a Senior Fullstack .NET Developer specializing in building scalable, high-performance web applications with .NET, C#, and modern frontend frameworks like React.js. I\u2019m passionate about clean architecture, automated testing, and sharing knowledge through blogs and tutorials."}],"_links":{"self":[{"href":"https:\/\/oussamasaidi.com\/en\/wp-json\/wp\/v2\/posts\/838","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/oussamasaidi.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/oussamasaidi.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/oussamasaidi.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/oussamasaidi.com\/en\/wp-json\/wp\/v2\/comments?post=838"}],"version-history":[{"count":12,"href":"https:\/\/oussamasaidi.com\/en\/wp-json\/wp\/v2\/posts\/838\/revisions"}],"predecessor-version":[{"id":1280,"href":"https:\/\/oussamasaidi.com\/en\/wp-json\/wp\/v2\/posts\/838\/revisions\/1280"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/oussamasaidi.com\/en\/wp-json\/wp\/v2\/media\/839"}],"wp:attachment":[{"href":"https:\/\/oussamasaidi.com\/en\/wp-json\/wp\/v2\/media?parent=838"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/oussamasaidi.com\/en\/wp-json\/wp\/v2\/categories?post=838"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/oussamasaidi.com\/en\/wp-json\/wp\/v2\/tags?post=838"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/oussamasaidi.com\/en\/wp-json\/wp\/v2\/ppma_author?post=838"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}