﻿
{"id":25607,"date":"2022-09-22T20:35:01","date_gmt":"2022-09-22T20:35:01","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=25607"},"modified":"2022-10-05T23:04:57","modified_gmt":"2022-10-05T23:04:57","slug":"openiddict-2-client-credentials-flow","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/openiddict-2-client-credentials-flow\/","title":{"rendered":"OpenIddict #2 &#8211; Client Credentials Flow"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>Bu i\u00e7eri\u011fimizde machine to machine kimliklendirme dedi\u011fimiz iki uygulama aras\u0131ndaki etkile\u015fime istinaden kullan\u0131lan bir ak\u0131\u015f t\u00fcr\u00fc olan Client Credential&#8217;\u0131 OpenIddict k\u00fct\u00fcphanesi ile nas\u0131l uygulayabilece\u011fimizi inceliyor olaca\u011f\u0131z.<\/p>\n<h4>Client Credentials Flow Nedir?<\/h4>\n<p>Sistemde kullan\u0131c\u0131lardan ziyade client&#8217;lara eri\u015fim yetkisi vermemizi sa\u011flayan bir ak\u0131\u015f t\u00fcr\u00fcd\u00fcr. Bir ba\u015fka deyi\u015fle, kullan\u0131c\u0131dan ziyade client do\u011frulamas\u0131n\u0131 baz almaktad\u0131r.<\/p>\n<h4>\u00d6rnek \u00c7al\u0131\u015fma<\/h4>\n<p>\u0130\u00e7eri\u011fin teorisini fazla uzatmaks\u0131z\u0131n konuya h\u0131zl\u0131ca pratiksel a\u00e7\u0131dan devam etmek istiyorum. \u015eimdi OpenIddict k\u00fct\u00fcphanesi ile Client Credentials Flow&#8217;u teknik olarak ad\u0131m ad\u0131m \u00f6rneklendiriyor olaca\u011f\u0131z. Bunun i\u00e7in \u00f6nceki makalemizde(<span style=\"font-size:12px;\">bknz : <a href=\"https:\/\/www.gencayyildiz.com\/blog\/openiddict-1-openiddict-nedir-ve-authorization-server-nasil-kurulur\/\" rel=\"noopener\" target=\"_blank\">OpenIddict Nedir? ve Authorization Server Nas\u0131l Kurulur?<\/a><\/span>) olu\u015fturmu\u015f oldu\u011fumuz Authorization Server uygulamas\u0131n\u0131 <a href=\"https:\/\/github.com\/gncyyldz\/OpenIddict-Authorization-Server-Example\" rel=\"noopener\" target=\"_blank\">github<\/a> adresinden \u00e7ekip, a\u015fa\u011f\u0131daki \u00f6nergeleri s\u0131ras\u0131yla tatbik edebilecek temelleri haz\u0131r k\u0131ta bir vaziyette olu\u015fturman\u0131z\u0131 tavsiye ederiz.<\/p>\n<ul>\n<li><strong>Ad\u0131m 1 | <span style=\"color:green;font-size:12px;\">(OpenIddict Paketlerinin Y\u00fcklenmesi)<\/span><\/strong><br \/>\n\u0130lk olarak Authorization Server&#8217;a OpenIddict k\u00fct\u00fcphanelerini y\u00fckleyerek ba\u015flamam\u0131z gerekmektedir. Bu k\u00fct\u00fcphaneler;<\/p>\n<ul>\n<li><a href=\"https:\/\/www.nuget.org\/packages\/OpenIddict\/3.1.1\" rel=\"noopener\" target=\"_blank\">OpenIddict<\/a><\/li>\n<li><a href=\"https:\/\/www.nuget.org\/packages\/OpenIddict.AspNetCore\/4.0.0-preview3.22422.72\" rel=\"noopener\" target=\"_blank\">OpenIddict.AspNetCore<\/a><\/li>\n<li><a href=\"https:\/\/www.nuget.org\/packages\/OpenIddict.EntityFrameworkCore\/4.0.0-preview3.22422.72\" rel=\"noopener\" target=\"_blank\">OpenIddict.EntityFrameworkCore<\/a><\/li>\n<\/ul>\n<p>olmak \u00fczere \u00fc\u00e7 tanedirler.<\/p>\n<p>K\u00fct\u00fcphaneleri y\u00fckleyebilmek i\u00e7in Nuget&#8217;ten destek alabilir ya da isterseniz a\u015fa\u011f\u0131daki CLI komutlar\u0131 \u00fczerinden de talimatlar\u0131n\u0131z\u0131 verebilirsiniz.<\/p>\n<div style=\"text-align:center;\">\n<code style=\"color:green;\">dotnet add package OpenIddict<\/code><br \/>\n<code style=\"color:green;\">dotnet add package OpenIddict.AspNetCore<\/code><br \/>\n<code style=\"color:green;\">dotnet add package OpenIddict.EntityFrameworkCore<\/code>\n<\/div>\n<p>Ayr\u0131ca haz\u0131r el atm\u0131\u015fken uygulama s\u00fcrecinde SQL Server ba\u011flant\u0131s\u0131 ve migration yap\u0131lanmalar\u0131 i\u00e7in kullanaca\u011f\u0131m\u0131z \u015fu k\u00fct\u00fcphaneleri de y\u00fcklemekte fayda vard\u0131r;<\/p>\n<ul>\n<li><a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.EntityFrameworkCore.SqlServer\/7.0.0-rc.1.22426.7\" rel=\"noopener\" target=\"_blank\">Microsoft.EntityFrameworkCore.SqlServer<\/a><\/li>\n<li><a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.EntityFrameworkCore.Tools\/7.0.0-rc.1.22426.7\" rel=\"noopener\" target=\"_blank\">Microsoft.EntityFrameworkCore.Tools<\/a><\/li>\n<\/ul>\n<div style=\"text-align:center;\">\n<code style=\"color:green;\">dotnet add package Microsoft.EntityFrameworkCore.SqlServer<\/code><br \/>\n<code style=\"color:green;\">dotnet add package Microsoft.EntityFrameworkCore.Tools<\/code>\n<\/div>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow.png\" alt=\"OpenIddict #2 \u2013 Client Credentials Flow\" width=\"416\" height=\"233\" class=\"aligncenter size-full wp-image-25617\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow.png 416w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-300x168.png 300w\" sizes=\"auto, (max-width: 416px) 100vw, 416px\" \/><\/a>\n<\/li>\n<li><strong>Ad\u0131m 2 | <span style=\"color:green;font-size:12px;\">(OpenIddict Konfig\u00fcrasyonunun Yap\u0131lmas\u0131)<\/span><\/strong><br \/>\nUygulamada OpenIddict i\u015flevselli\u011finden istifade edebilmek i\u00e7in \u00f6ncelikle temel bir yap\u0131land\u0131rmada bulunmam\u0131z gerekmektedir. Bu yap\u0131land\u0131rma s\u00fcrecinde OAuth 2.0 ve OpenID Connect ak\u0131\u015flar\u0131 etkinle\u015ftirilmelidir. Tabi burada kullanaca\u011f\u0131m\u0131z ak\u0131\u015f\u0131n machine to machine olan Client Credentials oldu\u011funu biliyoruz. \u015eimdi uygulaman\u0131n &#8216;Program.cs&#8217; dosyas\u0131na gelelim ve a\u015fa\u011f\u0131daki konfig\u00fcrasyonlar\u0131 ger\u00e7ekle\u015ftirelim.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nusing Microsoft.AspNetCore.Authentication.Cookies;\r\nusing Microsoft.EntityFrameworkCore;\r\nusing OpenIddict.AuthorizationServer.Models;\r\n\r\nvar builder = WebApplication.CreateBuilder(args);\r\n\r\nbuilder.Services.AddControllersWithViews();\r\nbuilder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)\r\n    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =&gt; options.LoginPath = &quot;\/account\/login&quot;);\r\n\r\n\/\/OpenIddict servisini uygulamaya ekliyoruz.\r\nbuilder.Services.AddOpenIddict()\r\n    \/\/OpenIddict core\/\u00e7ekirdek yap\u0131land\u0131rmalar\u0131 ger\u00e7ekle\u015ftiriliyor.\r\n    .AddCore(options =&gt;\r\n    {\r\n        \/\/Entity Framework Core kullan\u0131laca\u011f\u0131 bildiriliyor.\r\n        options.UseEntityFrameworkCore()\r\n               \/\/Kullan\u0131lacak context nesnesi bildiriliyor.\r\n               .UseDbContext&lt;ApplicationDbContext&gt;();\r\n    })\r\n    \/\/OpenIddict server yap\u0131land\u0131rmalar\u0131 ger\u00e7ekle\u015ftiriliyor.\r\n    .AddServer(options =&gt;\r\n    {\r\n        \/\/Token talebinde bulunulacak endpoint'i set ediyoruz.\r\n        options.SetTokenEndpointUris(&quot;\/connect\/token&quot;);\r\n        \/\/Ak\u0131\u015f t\u00fcr\u00fc olarak Client Credentials Flow'u etkinle\u015ftiriyoruz.\r\n        options.AllowClientCredentialsFlow();\r\n        \/\/Signing ve encryption sertifikalar\u0131n\u0131 ekliyoruz.\r\n        options.AddEphemeralEncryptionKey()\r\n               .AddEphemeralSigningKey()\r\n               \/\/Normalde OpenIddict \u00fcretilecek token'\u0131 g\u00fcvenlik amac\u0131yla \u015fifreli bir \u015fekilde bizlere sunmaktad\u0131r.\r\n               \/\/Haliyle jwt.io sayfas\u0131nda bu token'\u0131 \u00e7\u00f6z\u00fcmleyip g\u00f6rmek istedi\u011fimizde \u015fifresinden dolay\u0131\r\n               \/\/incelemede bulunamay\u0131z. Bu DisableAccessTokenEncryption \u00f6zelli\u011fi sayesinde \u00fcretilen access token'\u0131n\r\n               \/\/\u015fifrelenmesini iptal ediyoruz.\r\n               .DisableAccessTokenEncryption();\r\n        \/\/OpenIddict Server servislerini IoC Container'a ekliyoruz.\r\n        options.UseAspNetCore()\r\n               \/\/EnableTokenEndpointPassthrough : OpenID Connect request'lerinin OpenIddict taraf\u0131ndan i\u015flenmesi i\u00e7in gerekli konfig\u00fcrasyonu sa\u011flar.\r\n               .EnableTokenEndpointPassthrough();\r\n        \/\/Yetkileri(scope) belirliyoruz.\r\n        options.RegisterScopes(&quot;read&quot;, &quot;write&quot;);\r\n    });\r\n\r\n\/\/OpenIddict'i SQL Server'\u0131 kullanacak \u015fekilde yap\u0131land\u0131r\u0131yoruz.\r\nbuilder.Services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;\r\n{\r\n    options.UseSqlServer(builder.Configuration.GetConnectionString(&quot;SQLServer&quot;));\r\n    \/\/OpenIddict taraf\u0131ndan ihtiya\u00e7 duyulan Entity s\u0131n\u0131flar\u0131n\u0131 kaydediyoruz.\r\n    options.UseOpenIddict();\r\n});\r\n\r\nvar app = builder.Build();\r\n\r\nif (!app.Environment.IsDevelopment())\r\n{\r\n    app.UseExceptionHandler(&quot;\/Home\/Error&quot;);\r\n    app.UseHsts();\r\n}\r\n\r\napp.UseHttpsRedirection();\r\napp.UseStaticFiles();\r\n\r\napp.UseRouting();\r\n\r\napp.UseAuthentication();\r\napp.UseAuthorization();\r\n\r\napp.MapControllerRoute(\r\n    name: &quot;default&quot;,\r\n    pattern: &quot;{controller=Home}\/{action=Index}\/{id?}&quot;);\r\n\r\napp.Run();\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki kod blo\u011funu incelersek e\u011fer; <strong>12<\/strong> ile <strong>42.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda OpenIddict i\u00e7in temel konfig\u00fcrasyonlar\u0131n yap\u0131ld\u0131\u011f\u0131n\u0131 g\u00f6rmekteyiz. Bu konfig\u00fcrasyonlar\u0131n a\u00e7\u0131klamas\u0131 kod i\u00e7erisinde yap\u0131lm\u0131\u015f olsa da bizler yine de \u00fczerinden az bir \u015fey ge\u00e7elim isterim.<\/p>\n<p>\u0130lk olarak OpenIddict k\u00fct\u00fcphanesinin Entity Framework Core arac\u0131l\u0131\u011f\u0131yla SQL Server veritaban\u0131nda \u00e7al\u0131\u015faca\u011f\u0131n\u0131 g\u00f6r\u00fcyoruz. Burada isterseniz EF Core d\u0131\u015f\u0131nda, standart EF yahut direkt MongoDB yap\u0131land\u0131rmas\u0131n\u0131 kullanabilirsiniz. Yap\u0131lan veritaban\u0131 konfig\u00fcrasyonundan sonra <strong>49.<\/strong> sat\u0131rdaki &#8216;UseOpenIddict&#8217; metodu sayesinde OpenIddict taraf\u0131ndan kullan\u0131lacak entity&#8217;ler ilgili veritaban\u0131na eklenmektedirler. Tabi bunun i\u00e7in birazdan migration olu\u015fturmam\u0131z ve migrate etmemiz gerekmektedir.<\/p>\n<p><strong>12.<\/strong> sat\u0131rdaki &#8216;AddOpenIddict&#8217; metodundan sonra <strong>14<\/strong> ile <strong>20.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda OpenIddict i\u00e7in gerekli core\/\u00e7ekirdek bile\u015fenler yap\u0131land\u0131r\u0131l\u0131rken ard\u0131ndan <strong>22<\/strong> ile <strong>42.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda ise server ile ilgili bile\u015fenler yap\u0131land\u0131r\u0131lmaktad\u0131r. \u00d6zellikle bu noktada tasarlanan ak\u0131\u015f\u0131n Client Credentials oldu\u011fu belirlenmekte ve olu\u015fturulacak token&#8217;\u0131n \u015fifrelenebilmesi ve imzalanabilmesi i\u00e7in gerekli konfig\u00fcrasyonlar ger\u00e7ekle\u015ftirilmektedir.<\/p>\n<p><strong>35.<\/strong> sat\u0131rdaki &#8216;DisableAccessTokenEncryption&#8217; metodu bizim i\u00e7in olduk\u00e7a \u00f6nem arz etmektedir. \u00c7\u00fcnk\u00fc, OpenIddict taraf\u0131ndan olu\u015fturulacak access token sadece imzalanmakla  kalmamakta ayn\u0131 zamanda \u015fifrelenmektedir. Bu \u015fifreleme neticesinde ilgili token de\u011ferini <a href=\"https:\/\/jwt.io\/\" rel=\"noopener\" target=\"_blank\">jwt.io<\/a> gibi bir \u00e7\u00f6z\u00fcmleyici taraf\u0131ndan a\u00e7\u0131p, inceleyememekteyiz. \u0130\u015fte bu durumdan dolay\u0131 ilgili metot ile \u015fifrelemeyi devre d\u0131\u015f\u0131 b\u0131rakabilmekteyiz.<\/p>\n<p><strong>41.<\/strong> sat\u0131rdaki &#8216;RegisterScopes&#8217; metoduna g\u00f6z atarsan\u0131z e\u011fer uygulama baz\u0131nda yetkilendirme s\u00fcrecinde kullan\u0131lacak izinlerin tan\u0131mland\u0131\u011f\u0131n\u0131 g\u00f6receksiniz.\n<\/li>\n<li><strong>Ad\u0131m 3 | <span style=\"color:green;font-size:12px;\">(Migration Olu\u015fturma ve Migrate Etme)<\/span><\/strong><br \/>\nYap\u0131lan bu konfig\u00fcrasyonlar neticesinde art\u0131k migration olu\u015fturarak OpenIddict i\u00e7in gerekli olan entity&#8217;lerin tablo modellemesini veritaban\u0131na migrate edebilirsiniz.<\/p>\n<div style=\"text-align:center;\">\n<code>add-migration mig_1<\/code><br \/>\n<code>update-database<\/code>\n<\/div>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-2.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-2.png\" alt=\"OpenIddict #2 \u2013 Client Credentials Flow\" width=\"221\" height=\"219\" class=\"alignleft size-full wp-image-25623\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-2.png 221w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-2-150x150.png 150w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-2-80x80.png 80w\" sizes=\"auto, (max-width: 221px) 100vw, 221px\" \/><\/a>Generate edilen veritaban\u0131n\u0131 merak ediyorsan\u0131z e\u011fer yandaki g\u00f6rseli inceleyebilirsiniz. G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere <em>OpenIddictApplications<\/em>, <em>OpenIddictAuthorizations<\/em>, <em>OpenIddictScopes<\/em> ve <em>OpenIddictTokens<\/em> isimlerinde tablolar olu\u015fturulmu\u015ftur. Bu tablolar\u0131n i\u015flevselli\u011fini izah etmemiz gerekirse e\u011fer;<\/p>\n<ul>\n<li><em>OpenIddictApplications<\/em>, uygulamadaki client bilgilerinin tutuldu\u011fu tablodur.<\/li>\n<li><em>OpenIddictAuthorizations<\/em>, uygulamadaki client&#8217;lar\u0131n yetki durumlar\u0131n\u0131n tutuldu\u011fu tablodur.<\/li>\n<li><em>OpenIddictScopes<\/em>, uygulamadaki scope&#8217;lar\u0131n tutuldu\u011fu tablodur.<\/li>\n<li><em>OpenIddictTokens<\/em>, uygulamada client&#8217;lar i\u00e7in \u00fcretilen token&#8217;lar\u0131n expire, type vs. gibi bilgilerinin tutuldu\u011fu tablodur.<\/li>\n<\/ul>\n<\/li>\n<li><strong>Ad\u0131m 4 | <span style=\"color:green;font-size:12px;\">(Yap\u0131land\u0131rman\u0131n Sa\u011fl\u0131kl\u0131 Olup Olmad\u0131\u011f\u0131n\u0131 Kontrol Etme)<\/span><\/strong><br \/>\nOpenIddict&#8217;in d\u00fczg\u00fcn yap\u0131land\u0131r\u0131l\u0131p yap\u0131land\u0131r\u0131lmad\u0131\u011f\u0131n\u0131 kontrol etmek i\u00e7in uygulamay\u0131 aya\u011fa kald\u0131r\u0131p a\u015fa\u011f\u0131daki endpoint&#8217;e istek yapabilirsiniz.<\/p>\n<div style=\"text-align:center;\">\n<code style=\"color:red;\">GET  ...\/.well-known\/openid-configuration<\/code>\n<\/div>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-1.png\" alt=\"OpenIddict #2 \u2013 Client Credentials Flow\" width=\"448\" height=\"596\" class=\"alignleft size-full wp-image-25620\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-1.png 448w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-1-226x300.png 226w\" sizes=\"auto, (max-width: 448px) 100vw, 448px\" \/><\/a><br \/>\nE\u011fer ki ilgili endpoint&#8217;e yap\u0131lan istek neticesinde yandaki g\u00f6rseldeki gibi verilerle kar\u015f\u0131la\u015f\u0131yorsan\u0131z yap\u0131land\u0131rman\u0131n gayet ba\u015far\u0131l\u0131 oldu\u011funu s\u00f6yleyebiliriz.<\/p>\n<p>Gelen verilere g\u00f6z atarsan\u0131z e\u011fer; token endpoint&#8217;inden tutun da, desteklenen grant type&#8217;\u0131na ve scope&#8217;lara kadar t\u00fcm bilgileri bizlerle payla\u015fmaktad\u0131r.<\/p>\n<p>Ayr\u0131ca desteklenen claim&#8217;lerin vs. nas\u0131l belirlenebilece\u011fini yaz\u0131m\u0131z\u0131n devam\u0131nda inceliyor olaca\u011f\u0131z. Ad\u0131m ad\u0131m, sab\u0131rla tatbik ederek okumaya devam ediniz.<\/p>\n<\/li>\n<li><strong>Ad\u0131m 5 | <span style=\"color:green;font-size:12px;\">(Client Ekleme Sayfas\u0131n\u0131n Tasarlanmas\u0131 ve \u0130\u015flemin Ger\u00e7ekle\u015ftirilmesi)<\/span><\/strong><br \/>\n\u015eimdi, Authorization Server&#8217;a client ekleme i\u015flemlerini ger\u00e7ekle\u015ftiriyor olaca\u011f\u0131z. Bunun i\u00e7in \u00f6ncelikle kullan\u0131c\u0131dan client bilgilerini edinecek olan &#8216;ClientCreateVM&#8217; isimli viewmodel&#8217;\u0131 olu\u015fturarak ba\u015flayal\u0131m.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class ClientCreateVM\r\n    {\r\n        public string ClientId { get; set; }\r\n        public string ClientSecret { get; set; }\r\n        public string DisplayName { get; set; }\r\n    }\r\n<\/pre>\n<\/div>\n<p>Ard\u0131ndan &#8216;ClientsController&#8217; s\u0131n\u0131f\u0131n\u0131 olu\u015fturarak i\u00e7erisini a\u015fa\u011f\u0131daki gibi doldural\u0131m.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class ClientsController : Controller\r\n    {\r\n        readonly IOpenIddictApplicationManager _openIddictApplicationManager;\r\n\r\n        public ClientsController(IOpenIddictApplicationManager openIddictApplicationManager)\r\n        {\r\n            _openIddictApplicationManager = openIddictApplicationManager;\r\n        }\r\n\r\n        &#x5B;HttpGet]\r\n        public async Task&lt;IActionResult&gt; CreateClient()\r\n        {\r\n            return View();\r\n        }\r\n\r\n        &#x5B;HttpPost]\r\n        public async Task&lt;IActionResult&gt; CreateClient(ClientCreateVM model)\r\n        {\r\n            var client = await _openIddictApplicationManager.FindByClientIdAsync(model.ClientId);\r\n            if (client is null)\r\n            {\r\n                await _openIddictApplicationManager.CreateAsync(new OpenIddictApplicationDescriptor\r\n                {\r\n                    ClientId = model.ClientId,\r\n                    ClientSecret = model.ClientSecret,\r\n                    DisplayName = model.DisplayName,\r\n                    Permissions =\r\n                    {\r\n                        OpenIddictConstants.Permissions.Endpoints.Token,\r\n                        OpenIddictConstants.Permissions.GrantTypes.ClientCredentials,\r\n                        OpenIddictConstants.Permissions.Prefixes.Scope + &quot;read&quot;,\r\n                        OpenIddictConstants.Permissions.Prefixes.Scope + &quot;write&quot;\r\n                    }\r\n                });\r\n                ViewBag.Message = &quot;Client ba\u015far\u0131yla olu\u015fturulmu\u015ftur.&quot;;\r\n                return View();\r\n            }\r\n            ViewBag.Message = &quot;Client zaten mevcuttur.&quot;;\r\n            return View();\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>Burada client ile ilgili i\u015flemleri ger\u00e7ekle\u015ftirebilmek i\u00e7in <strong>3.<\/strong> sat\u0131rda g\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere &#8216;IOpenIddictApplicationManager&#8217; s\u0131n\u0131f\u0131ndan istifade edilmektedir. Bu s\u0131n\u0131f arac\u0131l\u0131\u011f\u0131yla silme, g\u00fcncelleme, adet(count) vs. gibi i\u015flemleri y\u00fcr\u00fctmekteyiz. <strong>18<\/strong> ile <strong>39.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda ger\u00e7ekle\u015ftirilen client ekleme i\u015fleminde \u00f6ncelikle kullan\u0131c\u0131dan gelen client-id bilgisine kar\u015f\u0131l\u0131k bir client&#8217;\u0131n olup olmad\u0131\u011f\u0131 kontrol edilmekte, e\u011fer yoksa client \u00fcretilmekte yok e\u011fer varsa hi\u00e7bir i\u015flem ger\u00e7ekle\u015ftirilmemektedir. Tabi ki de ben denizin sade tutmaya \u00e7al\u0131\u015ft\u0131\u011f\u0131 bu noktay\u0131 sizler uygulaman\u0131z\u0131n davran\u0131\u015f\u0131na g\u00f6re \u00f6zelle\u015ftirebilirsiniz.<\/p>\n<p><strong>27<\/strong> ile <strong>33.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda ise bu eklenecek olan client&#8217;lar\u0131n hangi izinlere sahip olaca\u011f\u0131 belirlenmektedir. Dikkat ederseniz, \u00f6nceki sat\u0131rlarda <code>RegisterScopes<\/code> metodu ile belirledi\u011fimiz izinleri burada da eklenen client&#8217;larla e\u015fle\u015ftirmekteyiz.<\/p>\n<p>Bu \u00e7al\u0131\u015fmadan sonra s\u0131rada &#8216;CreateClient&#8217; action&#8217;\u0131n\u0131n view&#8217;ini olu\u015fturmak vard\u0131r.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n@model OpenIddict.AuthorizationServer.ViewModels.ClientCreateVM\r\n@if (ViewBag.Message != null)\r\n{\r\n    &lt;div class=&quot;alert alert-success&quot; role=&quot;alert&quot;&gt;\r\n        @ViewBag.Message\r\n    &lt;\/div&gt;\r\n}\r\nelse\r\n{\r\n    &lt;form autocomplete=&quot;off&quot; asp-route=&quot;Clients&quot;&gt;\r\n        &lt;div class=&quot;card&quot;&gt;\r\n            &lt;input type=&quot;text&quot; class=&quot;form-control form-control-lg&quot; placeholder=&quot;Client ID&quot; asp-for=&quot;ClientId&quot; autofocus&gt;\r\n            &lt;input type=&quot;password&quot; class=&quot;form-control form-control-lg&quot; placeholder=&quot;Client Secret&quot; asp-for=&quot;ClientSecret&quot;&gt;\r\n            &lt;input type=&quot;text&quot; class=&quot;form-control form-control-lg form-control-last&quot; placeholder=&quot;Display Name&quot; asp-for=&quot;DisplayName&quot; autofocus&gt;\r\n        &lt;\/div&gt;\r\n        &lt;p&gt;\r\n            &lt;button type=&quot;submit&quot; class=&quot;btn btn-dark btn-block mt-3&quot;&gt;Create Client&lt;\/button&gt;\r\n        &lt;\/p&gt;\r\n    &lt;\/form&gt;\r\n}\r\n<\/pre>\n<\/div>\n<p>\u0130lgili sayfay\u0131 yukar\u0131daki gibi tasarlay\u0131p, uygulamay\u0131 derleyip, \u00e7al\u0131\u015ft\u0131rd\u0131\u011f\u0131m\u0131zda a\u015fa\u011f\u0131daki gibi bir sayfayla kar\u015f\u0131la\u015f\u0131yor olaca\u011f\u0131z.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-3.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-3.png\" alt=\"OpenIddict #2 \u2013 Client Credentials Flow\" width=\"587\" height=\"291\" class=\"aligncenter size-full wp-image-25626\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-3.png 587w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-3-300x149.png 300w\" sizes=\"auto, (max-width: 587px) 100vw, 587px\" \/><\/a><br \/>\nEkrandaki bilgiler e\u015fli\u011finde(<span style=\"font-size:12px;\">Client Secret : postman-client-secret<\/span>) &#8216;Create Client&#8217; butonuna t\u0131klarsan\u0131z e\u011fer a\u015fa\u011f\u0131daki gibi ba\u015far\u0131l\u0131 oldu\u011funa dair mesaj al\u0131yor olacaks\u0131n\u0131z.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-4.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-4.png\" alt=\"OpenIddict #2 \u2013 Client Credentials Flow\" width=\"465\" height=\"131\" class=\"aligncenter size-full wp-image-25628\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-4.png 465w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-4-300x85.png 300w\" sizes=\"auto, (max-width: 465px) 100vw, 465px\" \/><\/a><br \/>\nAyr\u0131ca veritaban\u0131na da g\u00f6z atarsak e\u011fer;<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-5.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-5.png\" alt=\"OpenIddict #2 \u2013 Client Credentials Flow\" width=\"1773\" height=\"104\" class=\"aligncenter size-full wp-image-25629\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-5.png 1773w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-5-300x18.png 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-5-1024x60.png 1024w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-5-768x45.png 768w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-5-1536x90.png 1536w\" sizes=\"auto, (max-width: 1773px) 100vw, 1773px\" \/><\/a>g\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere ba\u015far\u0131yla client&#8217;\u0131n eklendi\u011fini g\u00f6zlemlemekteyiz. Bu arada client-secret de\u011ferinin \u015fifrelenerek tutuldu\u011funa dikkatinizi \u00e7ekerim \ud83d\ude09<\/p>\n<\/li>\n<li><strong>Ad\u0131m 6 | <span style=\"color:green;font-size:12px;\">(Token Endpoint&#8217;inin Tasarlanmas\u0131)<\/span><\/strong><br \/>\n\u015eimdi s\u0131ra en \u00f6nemli yere geldi diyebiliriz, token endpoint&#8217;inin tasarlanmas\u0131na&#8230; Hat\u0131rlarsan\u0131z yukar\u0131daki sat\u0131rlarda, OpenIddict server yap\u0131land\u0131rmalar\u0131n\u0131 sa\u011flad\u0131\u011f\u0131m\u0131z noktalarda <code>SetTokenEndpointUris<\/code> fonksiyonu arac\u0131l\u0131\u011f\u0131yla token endpoint&#8217;inin <code>\/connect\/token<\/code> adresine kar\u015f\u0131l\u0131k gelece\u011fini belirtmi\u015ftik. \u015eimdi bu adrese kar\u015f\u0131l\u0131k controller \u00e7al\u0131\u015fmas\u0131 ger\u00e7ekle\u015ftirecek ve client&#8217;lar\u0131n token edinmesini sa\u011fl\u0131yor olaca\u011f\u0131z.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class AuthorizationController : Controller\r\n    {\r\n        readonly IOpenIddictApplicationManager _applicationManager;\r\n\r\n        public AuthorizationController(IOpenIddictApplicationManager applicationManager)\r\n        {\r\n            _applicationManager = applicationManager;\r\n        }\r\n\r\n        \/\/Bu action'\u0131n endpoint'ini token endpoint ile ayn\u0131 \u015fekilde ayarl\u0131yoruz.\r\n        &#x5B;HttpPost(&quot;~\/connect\/token&quot;)]\r\n        public async Task&lt;IActionResult&gt; Exchange()\r\n        {\r\n            var request = HttpContext.GetOpenIddictServerRequest();\r\n            if (request?.IsClientCredentialsGrantType() is not null)\r\n            {\r\n                \/\/Client credentials OpenIddict taraf\u0131ndan otomatik olarak do\u011frulan\u0131r.\r\n                \/\/E\u011fer ki gelen request'in body'sindeki client_id veya client_secret bilgileri ge\u00e7ersizse, buras\u0131 tetiklenmeyecektir.\r\n\r\n                var application = await _applicationManager.FindByClientIdAsync(request.ClientId);\r\n                if (application is null)\r\n                    throw new InvalidOperationException(&quot;This clientId was not found&quot;);\r\n\r\n                var identity = new ClaimsIdentity(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);\r\n\r\n                \/\/Token'a claim'leri ekleyelim. Subject'in eklenmesi zorunludur.\r\n                \/\/Destination'lar ile claim'lerin hangi token'a eklenece\u011fini belirtiyoruz. AccessToken m\u0131? Identity Token m\u0131? Yoksa her ikisi de mi?\r\n                identity.AddClaim(Claims.Subject, (await _applicationManager.GetClientIdAsync(application) ?? throw new InvalidOperationException()), Destinations.AccessToken, Destinations.IdentityToken);\r\n                identity.AddClaim(Claims.Name, (await _applicationManager.GetDisplayNameAsync(application) ?? throw new InvalidOperationException()), Destinations.AccessToken, Destinations.IdentityToken);\r\n                identity.AddClaim(&quot;ozel-claim&quot;, &quot;ozel-claim-value&quot;, Destinations.AccessToken, Destinations.IdentityToken);\r\n\r\n                identity.AddClaim(JwtRegisteredClaimNames.Aud, &quot;Example-OpenIddict&quot;, Destinations.AccessToken, Destinations.IdentityToken);\r\n\r\n                var claimsPrincipal = new ClaimsPrincipal(identity);\r\n                claimsPrincipal.SetScopes(request.GetScopes());\r\n\r\n                \/\/SignIn return etmek, biryandan OpenIddict'ten uygun access\/identity token talebinde bulunmakt\u0131r.\r\n                return SignIn(claimsPrincipal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);\r\n            }\r\n            throw new NotImplementedException(&quot;The specified grant type is not implemented.&quot;);\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki &#8216;AuthorizationController&#8217; isimli s\u0131n\u0131f\u0131 ve i\u00e7erisindeki &#8216;Exchange&#8217; ad\u0131n\u0131 verdi\u011fimiz action&#8217;\u0131n davran\u0131\u015f\u0131n\u0131 incelerseniz e\u011fer yine kod i\u00e7erisinde gerekli a\u00e7\u0131klamalar\u0131 yapm\u0131\u015f olsakta hafiften burada da izah ama\u00e7l\u0131 neler yapt\u0131\u011f\u0131m\u0131za temas etmekte fayda g\u00f6rmekteyim.<\/p>\n<p>Her\u015feyden \u00f6nce <strong>11.<\/strong> sat\u0131ra g\u00f6z atarsan\u0131z e\u011fer bu &#8216;Exchange&#8217; isimli action&#8217;\u0131 token endpoint&#8217;i ile ayn\u0131 olacak \u015fekilde &#8216;\/connect\/token&#8217; de\u011feriyle e\u015fle\u015ftirdi\u011fimize dikkatinizi \u00e7ekerim. Bu endpoint \u00fczerinden gelen token taleplerinde, request&#8217;in body&#8217;sinde bulunacak olan client-id ve client-secret gibi de\u011ferler do\u011frulanacak ve gerekli operasyonlar ger\u00e7ekle\u015ftirilecektir. Client&#8217;\u0131n kimlik bilgileri <strong>14.<\/strong> sat\u0131rdaki <code>GetOpenIddictServerRequest<\/code> fonksiyonu taraf\u0131ndan OpenIddict ile otomatik olarak do\u011frulanacak ve <strong>15.<\/strong> sat\u0131rda yap\u0131lan <code>IsClientCredentialsGrantType<\/code> kontrol\u00fc e\u015fli\u011finde e\u011fer ki do\u011frulama s\u00f6z konusu olmazsa bu iste\u011fe kar\u015f\u0131l\u0131k token \u00fcretilmeyecektir. Burada ekstradan \u015funu da s\u00f6ylemekte fayda vard\u0131r ki, bu action sadece client credential flow i\u00e7in de\u011fil t\u00fcm ak\u0131\u015flar i\u00e7in kullan\u0131labilir bir temele sahiptir.<\/p>\n<p><strong>20.<\/strong> sat\u0131rda, istemciden gelen client-id&#8217;ye kar\u015f\u0131l\u0131k client veritaban\u0131ndan sorgulanmakta ve ard\u0131ndan bu client&#8217;a \u00f6zel \u00fcretilecek olan token i\u00e7erisinde hangi claim&#8217;lerin olmas\u0131 gerekiyorsa <strong>24.<\/strong> sat\u0131rda olu\u015fturulan &#8216;ClaimsIdentity&#8217; nesnesine <strong>28<\/strong> ile <strong>30.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda oldu\u011fu gibi eklenmektedir. Tabi burada unutulmamas\u0131 gereken noktalardan birisi &#8216;Subject&#8217; claim&#8217;inin zaruri olmas\u0131d\u0131r. Ayr\u0131ca claim&#8217;lerin destination&#8217;lar\u0131 belirtilerek hangi token&#8217;a eklenecekleri bildirilmelidir. Aksi taktirde \u00fcretilecek token&#8217;a bu claim&#8217;ler eklenmeyecektir.<\/p>\n<p>\u00d6zellikle <strong>32.<\/strong> sat\u0131rdaki <code>JwtRegisteredClaimNames.Aud<\/code> claim&#8217;ine dikkatinizi \u00e7ekmek istiyorum. Bu claim, geli\u015ftirmi\u015f oldu\u011fumuz bu Authorization Server&#8217;\u0131n sorumlu oldu\u011fu resource server&#8217;lar\u0131m\u0131z\u0131n(<span style=\"font-size:12px;\">ya da bir ba\u015fka deyi\u015fle API Resource&#8217;lar\u0131n<\/span>) veya API&#8217;lar\u0131n, bu Authorization Server taraf\u0131ndan \u00fcretilen token&#8217;\u0131 do\u011frulayabilmesi i\u00e7in kullanaca\u011f\u0131 &#8216;Audience&#8217; verisiyle e\u015fde\u011fer olacakt\u0131r. Onun i\u00e7in \u00fcretilecek token i\u00e7erisinde claim olarak tan\u0131mlanmas\u0131na \u00f6zen g\u00f6sterilmelidir.<\/p>\n<p>Ve son olarak <strong>38.<\/strong> sat\u0131rda SignIn metodu ile yap\u0131lan return neticesinde OpenIddict k\u00fct\u00fcphanesinin devreye girmesi ve access token ile identity token de\u011ferlerinin \u00fcretiminin ger\u00e7ekle\u015ftirmesi sa\u011flanmakta ve bu de\u011ferler request yapan istemciye g\u00f6nderilmektedir.\n<\/li>\n<li><strong>Ad\u0131m 7 | <span style=\"color:green;font-size:12px;\">(Token Talebinde Bulunma &#8211; K\u00fc\u00e7\u00fck Bir Test Edelim)<\/span><\/strong><br \/>\nEvet, art\u0131k yapt\u0131\u011f\u0131m\u0131z bu in\u015fay\u0131 bir token talebinde bulunarak test edebiliriz. Bunun i\u00e7in 5. ad\u0131mda olu\u015fturdu\u011fumuz client bilgilerinden a\u015fa\u011f\u0131daki gibi istifade edece\u011fiz.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-6.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-6.png\" alt=\"OpenIddict #2 \u2013 Client Credentials Flow\" width=\"1014\" height=\"691\" class=\"aligncenter size-full wp-image-25631\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-6.png 1014w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-6-300x204.png 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-6-768x523.png 768w\" sizes=\"auto, (max-width: 1014px) 100vw, 1014px\" \/><\/a>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere Postman \u00fczerinden client bilgileri e\u015fli\u011finde yap\u0131lan istek neticesinde Authorization Server&#8217;dan bir token elde etmi\u015f bulunuyoruz. Bundan sonra art\u0131k bu token&#8217;\u0131 kullanarak API Resource&#8217;lara isteklerimizi g\u00f6nderiyor olaca\u011f\u0131z. Tabi bundan \u00f6nce \u00fcretilen bu token de\u011ferini \u00e7\u00f6z\u00fcmleyerek i\u00e7erisindeki bilgileri inceleyelim.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-7.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-7.png\" alt=\"OpenIddict #2 \u2013 Client Credentials Flow\" width=\"878\" height=\"457\" class=\"aligncenter size-full wp-image-25632\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-7.png 878w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-7-300x156.png 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-7-768x400.png 768w\" sizes=\"auto, (max-width: 878px) 100vw, 878px\" \/><\/a>Yukar\u0131daki ekran g\u00f6r\u00fcnt\u00fcs\u00fcnde g\u00f6r\u00fcld\u00fc\u011f\u00fc gibi <a href=\"https:\/\/jwt.io\/\" rel=\"noopener\" target=\"_blank\">jwt.io<\/a> \u00fczerinden token de\u011ferini \u00e7\u00f6z\u00fcmlemi\u015f bulunmaktay\u0131z. (<span style=\"font-size:12px;\">Ha e\u011fer ki sizde \u00e7\u00f6z\u00fcmleme ba\u015far\u0131l\u0131 de\u011filse \u00f6zellikle 2. ad\u0131mdaki <strong>35.<\/strong> sat\u0131ra tekrar odaklanman\u0131z\u0131 tavsiye ediyorum.<\/span>) Payload i\u00e7erisine g\u00f6z atarsak e\u011fer 6. ad\u0131mda token i\u00e7erisine koyulan &#8216;sub&#8217;, &#8216;name&#8217;, &#8216;ozel-claim&#8217; vs. gibi t\u00fcm claim&#8217;leri g\u00f6rmekteyiz. Ayr\u0131ca &#8216;Audience&#8217;e kar\u015f\u0131l\u0131k gelen &#8216;aud&#8217; bilgiside token i\u00e7erisinde gelmektedir.<\/p>\n<p>\u015eimdi s\u0131rada API Resource&#8217;lara Authorization Server&#8217;dan ald\u0131\u011f\u0131m\u0131z token ile istekte bulunmak var. Tabi bunun i\u00e7in \u00f6ncelikle bir ka\u00e7 \u00f6rnek API Resource olu\u015fturmam\u0131z gerekmektedir.\n<\/li>\n<li><strong>Ad\u0131m 8 | <span style=\"color:green;font-size:12px;\">(API Resource Olu\u015fturma ve Yap\u0131land\u0131rma)<\/span><\/strong><br \/>\nOpenIddict ile geli\u015ftirdi\u011fimiz client credentials flow \u00f6rne\u011fini test edebilmek i\u00e7in birka\u00e7 API Resource&#8217;a ihtiyac\u0131m\u0131z olacakt\u0131r. Tabi ki de bizler bu i\u00e7eri\u011fimizde bir tanesinin nas\u0131l yap\u0131land\u0131r\u0131laca\u011f\u0131n\u0131 ele al\u0131yor olaca\u011f\u0131z. Sonras\u0131nda ise sizler istedi\u011finiz kadar API Resource&#8217;u olu\u015fturabilirsiniz \ud83d\ude42<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-8.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow-8.png\" alt=\"OpenIddict #2 \u2013 Client Credentials Flow\" width=\"226\" height=\"172\" class=\"alignleft size-full wp-image-25633\" \/><\/a><br \/>\n\u00d6rnek API Resource&#8217;u ayn\u0131 solution i\u00e7erisinde ad\u0131 opsiyonel olacak \u015fekilde(<span style=\"font-size:12px;\">ben API1 ad\u0131n\u0131 veriyorum<\/span>) olu\u015ftural\u0131m.<\/p>\n<p>Bu API&#8217;\u0131 Authorization Server&#8217;dan yetki alacak \u015fekilde yap\u0131land\u0131rabilmek i\u00e7in &#8216;Program.cs&#8217; dosyas\u0131n\u0131 a\u00e7al\u0131m ve a\u015fa\u011f\u0131daki konfig\u00fcrasyonlar\u0131 sa\u011flayal\u0131m.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nusing Microsoft.AspNetCore.Authentication.JwtBearer;\r\nusing System.Security.Claims;\r\n\r\nvar builder = WebApplication.CreateBuilder(args);\r\n\r\nbuilder.Services.AddControllers();\r\nbuilder.Services.AddEndpointsApiExplorer();\r\nbuilder.Services.AddSwaggerGen();\r\n\r\nbuilder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)\r\n    .AddJwtBearer(options =&gt;\r\n    {\r\n        options.Authority = builder.Configuration&#x5B;&quot;AuthenticationSettings:Authority&quot;];\r\n        \/\/Token'daki 'JwtRegisteredClaimNames.Aud' kar\u015f\u0131l\u0131k verilen de\u011ferin ta kendisi...\r\n        options.Audience = builder.Configuration&#x5B;&quot;AuthenticationSettings:Audience&quot;];\r\n        options.RequireHttpsMetadata = false;\r\n\r\n        \/\/Gelen token'da 'scope' claim'i i\u00e7erisinde k\u00fcm\u00fclatif olarak yan yana yaz\u0131lm\u0131\u015f\r\n        \/\/yetkileri ay\u0131rarak tek tek scope claim'i olarak tekrardan ayarlayabilmek i\u00e7in\r\n        \/\/token'\u0131n do\u011frulanmas\u0131 ard\u0131ndan 'OnTokenValidated' event'inde a\u015fa\u011f\u0131daki \u00e7al\u0131\u015fmay\u0131\r\n        \/\/ger\u00e7ekle\u015ftirmemiz gerekmektedir.\r\n        options.Events = new()\r\n        {\r\n            OnTokenValidated = async context =&gt;\r\n            {\r\n                if (context.Principal?.Identity is ClaimsIdentity claimsIdentity)\r\n                {\r\n                    Claim? scopeClaim = claimsIdentity.FindFirst(&quot;scope&quot;);\r\n                    if (scopeClaim is not null)\r\n                    {\r\n                        claimsIdentity.RemoveClaim(scopeClaim);\r\n                        claimsIdentity.AddClaims(scopeClaim.Value.Split(&quot; &quot;).Select(s =&gt; new Claim(&quot;scope&quot;, s)).ToList());\r\n                    }\r\n                }\r\n\r\n                await Task.CompletedTask;\r\n            }\r\n        };\r\n    });\r\n\r\nbuilder.Services.AddAuthorization(options =&gt;\r\n{\r\n    options.AddPolicy(&quot;APolicy&quot;, policy =&gt; policy.RequireClaim(&quot;scope&quot;, &quot;read&quot;));\r\n    options.AddPolicy(&quot;BPolicy&quot;, policy =&gt; policy.RequireClaim(&quot;scope&quot;, &quot;write&quot;));\r\n    options.AddPolicy(&quot;CPolicy&quot;, policy =&gt; policy.RequireClaim(&quot;scope&quot;, &quot;read&quot;, &quot;write&quot;));\r\n    options.AddPolicy(&quot;DPolicy&quot;, policy =&gt; policy.RequireClaim(&quot;ozel-claim&quot;, &quot;ozel-claim-value&quot;));\r\n});\r\n\r\nvar app = builder.Build();\r\n\r\nif (app.Environment.IsDevelopment())\r\n{\r\n    app.UseSwagger();\r\n    app.UseSwaggerUI();\r\n}\r\n\r\napp.UseHttpsRedirection();\r\n\r\napp.UseAuthentication();\r\napp.UseAuthorization();\r\n\r\napp.MapControllers();\r\n\r\napp.Run();\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki \u00e7al\u0131\u015fmaya g\u00f6z atarsan\u0131z e\u011fer; <strong>10<\/strong> ile <strong>38.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda jwt yap\u0131land\u0131rmas\u0131 ger\u00e7ekle\u015ftirilirken, <strong>40<\/strong> ile <strong>46.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda ise uygulamada belli ba\u015fl\u0131 yetkilendirmeleri \u00f6rneklendirebilmek i\u00e7in politikalar olu\u015fturulmaktad\u0131r. Burada \u00f6zellikle dikkat edilmesi gereken husus <strong>15.<\/strong> sat\u0131rdaki &#8216;Audience&#8217; ayar\u0131d\u0131r. Bu token i\u00e7erisindeki de\u011ferle birebir ayn\u0131 \u015fekilde olmal\u0131d\u0131r. Aksi taktirde token do\u011frulanmayacak ve haliyle yetkilendirme ba\u015far\u0131s\u0131z olacakt\u0131r. Ayn\u0131 durum &#8216;Authority&#8217; i\u00e7inde ge\u00e7erlidir. &#8216;Authority&#8217;, token&#8217;\u0131 \u00fcreten Authorization Server&#8217;\u0131n adresiyle birebir ayn\u0131 olmal\u0131d\u0131r. Ayr\u0131ca <strong>24<\/strong> ile <strong>37.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda token&#8217;dan gelen b\u00fct\u00fcnle\u015fik &#8216;scope&#8217; claim&#8217;ini ayr\u0131 ayr\u0131 claim olarak ayarlamakta ve &#8216;ClaimsIdentity&#8217;e eklemekteyiz. B\u00f6ylece yetkilendirme s\u00fcrecinde ilgili token&#8217;\u0131n hangi izinlere sahip oldu\u011funu rahatl\u0131kla ay\u0131rt edebilmekteyiz.<\/p>\n<p>Yetkilendirme yap\u0131land\u0131rmas\u0131n\u0131 in\u015fa ettikten sonra <strong>59<\/strong> ve <strong>60.<\/strong> sat\u0131rda oldu\u011fu gibi <code>UseAuthentication<\/code> ve <code>UseAuthorization<\/code> middleware&#8217;lerini s\u0131ras\u0131yla \u00e7a\u011f\u0131rmay\u0131 unutmay\u0131n\u0131z.<\/p>\n<p><strong>41<\/strong> ile <strong>47.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda ise olu\u015fturulan politikalar &#8216;scope&#8217; ve &#8216;ozel-claim&#8217;e ba\u011fl\u0131 bir \u015fekilde yetki kontrolleri ger\u00e7ekle\u015ftirmektedirler. B\u00f6ylece bu politikalar\u0131 a\u015fa\u011f\u0131daki gibi API controller&#8217;lar\u0131nda kullanabilir ve eri\u015fimleri y\u00f6netebiliriz.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    &#x5B;Route(&quot;api\/&#x5B;controller]&quot;)]\r\n    &#x5B;ApiController]\r\n    public class ValuesController : ControllerBase\r\n    {\r\n        &#x5B;HttpGet(&quot;&#x5B;action]&quot;)]\r\n        &#x5B;Authorize(&quot;APolicy&quot;)]\r\n        public IActionResult A()\r\n        {\r\n            return Ok();\r\n        }\r\n\r\n        &#x5B;HttpGet(&quot;&#x5B;action]&quot;)]\r\n        &#x5B;Authorize(&quot;BPolicy&quot;)]\r\n        public IActionResult B()\r\n        {\r\n            return Ok();\r\n        }\r\n\r\n        &#x5B;HttpGet(&quot;&#x5B;action]&quot;)]\r\n        &#x5B;Authorize(&quot;CPolicy&quot;)]\r\n        public IActionResult C()\r\n        {\r\n            return Ok();\r\n        }\r\n\r\n        &#x5B;HttpGet(&quot;&#x5B;action]&quot;)]\r\n        &#x5B;Authorize(&quot;DPolicy&quot;)]\r\n        public IActionResult D()\r\n        {\r\n            return Ok();\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<\/li>\n<li><strong>Ad\u0131m 9 | <span style=\"color:green;font-size:12px;\">(Nihai Test)<\/span><\/strong><br \/>\nArt\u0131k her\u015fey haz\u0131r. Authorization Server e\u015fli\u011finde bir tane numunelik Resource API&#8217;\u0131n geli\u015ftirmesini tamamlam\u0131\u015f olduk. \u015eimdi postman \u00fczerinden client credentials flow ile token&#8217;\u0131m\u0131z\u0131 talep edelim ve bu token ile Resource API&#8217;daki yukar\u0131da olu\u015fturdu\u011fumuz endpoint&#8217;lere tek tek eri\u015fim g\u00f6stermeye \u00e7al\u0131\u015fal\u0131m.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/09\/OpenIddict-2-\u2013-Client-Credentials-Flow.gif\" alt=\"OpenIddict #2 \u2013 Client Credentials Flow\" width=\"800\" height=\"541\" class=\"alignleft size-full wp-image-25635\" \/><\/a>Vee tebrikler \ud83d\ude42 g\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere uygulamalar\u0131m\u0131z\u0131n kusursuz \u00e7al\u0131\u015ft\u0131\u011f\u0131n\u0131 ve client credentials flow&#8217;un OpenIddict ile ba\u015far\u0131yla uyguland\u0131\u011f\u0131n\u0131 g\u00f6rm\u00fc\u015f olduk.\n<\/li>\n<\/ul>\n<p>Bir sonraki i\u00e7eri\u011fimizde Single Page Application(SPA) uygulamalar\u0131 i\u00e7in \u00f6nerilen Authorization Code Flow&#8217;u inceliyor olaca\u011f\u0131z.<\/p>\n<p>O halde \u015fimdilik g\u00f6r\u00fc\u015fmek \u00fczere&#8230;<br \/>\n\u0130lgilenenlerin faydalanmas\u0131 dile\u011fiyle&#8230;<br \/>\n\u0130yi \u00e7al\u0131\u015fmalar&#8230;<\/p>\n<p>Not : \u00d6rnek uygulaman\u0131n kaynak kodlar\u0131na a\u015fa\u011f\u0131daki github adresinden eri\u015febilirsiniz.<br \/>\n<a href=\"https:\/\/github.com\/gncyyldz\/OpenIddict-Authorization-Server-Example\" rel=\"noopener\" target=\"_blank\">https:\/\/github.com\/gncyyldz\/OpenIddict-Authorization-Server-Example<\/a><\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>Merhaba, Bu i\u00e7eri\u011fimizde machine to machine kimliklendirme dedi\u011fimiz iki uygulama aras\u0131ndaki etkile\u015fime istinaden kullan\u0131lan bir ak\u0131\u015f t\u00fcr\u00fc olan Client Credential&#8217;\u0131 OpenIddict k\u00fct\u00fcphanesi ile nas\u0131l uygulayabilece\u011fimizi inceliyor olaca\u011f\u0131z. Client Credentials Flow Nedir? Sistemde kullan\u0131c\u0131lardan ziyade&#46;&#46;&#46;<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":3014,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4665],"tags":[4671,4670,4666,4673,4672],"class_list":["post-25607","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-openiddict","tag-client-credentials","tag-client-credentials-flow","tag-openiddict","tag-openiddict-client-credentials","tag-openiddict-client-credentials-flow"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/25607","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/comments?post=25607"}],"version-history":[{"count":21,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/25607\/revisions"}],"predecessor-version":[{"id":25672,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/25607\/revisions\/25672"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/3014"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=25607"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=25607"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=25607"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}