﻿
{"id":25671,"date":"2022-10-14T18:07:14","date_gmt":"2022-10-14T18:07:14","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=25671"},"modified":"2022-10-14T18:07:14","modified_gmt":"2022-10-14T18:07:14","slug":"openiddict-3-authorization-code-flow","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/openiddict-3-authorization-code-flow\/","title":{"rendered":"OpenIddict #3 &#8211; Authorization Code Flow"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>Bu i\u00e7eri\u011fimizde OpenIddict k\u00fct\u00fcphanesi ile iki a\u015famal\u0131 do\u011frulama ger\u00e7ekle\u015ftirmemizi gereki k\u0131lan <em>Authorization Code Flow<\/em>&#8216;un nas\u0131l uygulanabilece\u011fini ele al\u0131yor olaca\u011f\u0131z. Hadi buyurun ba\u015flayal\u0131m.<\/p>\n<h4>Authorization Code Nedir?<\/h4>\n<p>Tabi \u00f6ncelikle Authorization Code&#8217;un ne oldu\u011funu ele alarak ba\u015flamakta fayda oldu\u011fu kanaatindeyim. Bunun i\u00e7in zaman\u0131nda <a href=\"https:\/\/www.gencayyildiz.com\/blog\/identityserver4-yazi-serisi-8-authorization-code-grantflow\/\" rel=\"noopener\" target=\"_blank\">Authorization Code Grant(Flow)<\/a> ba\u015fl\u0131\u011f\u0131ndaki makalede Authorization Code&#8217;u IdentityServer4 k\u00fct\u00fcphanesi e\u015fli\u011finde tam teferruatl\u0131 klavyeye alm\u0131\u015f bulunmaktay\u0131m. \u00d6ncelikle ilgili i\u00e7eri\u011fi okuyarak soluklanman\u0131z\u0131 ve ard\u0131ndan buradan devam etmenizi \u00f6neririm.<\/p>\n<p><em>Authorization Code<\/em>; client kullan\u0131c\u0131s\u0131n\u0131n Authorization Server \u00fczerinden authorize olmas\u0131 esnas\u0131nda, client taraf\u0131ndan \u00f6\u011frenilmek ve elde edilmek istenen bilgilerin kullan\u0131c\u0131 taraf\u0131ndan onaylanarak verilmesi neticesinde \u00fcretilen bir kodu temsil etmektedir. Kullan\u0131c\u0131 i\u00e7in kritik olan bu kod, authorization server taraf\u0131ndan client&#8217;a verildi\u011fi taktirde client bu kod e\u015fli\u011finde authorization server&#8217;dan ilgili kullan\u0131c\u0131ya ait yetkilerde access token ve refresh token&#8217;\u0131 elde edebilecektir.<\/p>\n<p>Konuyu daha iyi anlayabilmek i\u00e7in a\u015fa\u011f\u0131daki g\u00f6rseli inceleyebilirsiniz.<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/IdentityServer4-Yazi-Serisi-8-Authorization-Code-GrantFlow.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/IdentityServer4-Yazi-Serisi-8-Authorization-Code-GrantFlow.png\" alt=\"OpenIddict #3 - Authorization Code Flow\" width=\"442\" height=\"322\" class=\"alignleft size-full wp-image-18601\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/IdentityServer4-Yazi-Serisi-8-Authorization-Code-GrantFlow.png 442w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2020\/10\/IdentityServer4-Yazi-Serisi-8-Authorization-Code-GrantFlow-300x219.png 300w\" sizes=\"auto, (max-width: 442px) 100vw, 442px\" \/><\/a><br \/>\nKullan\u0131c\u0131, client taraf\u0131ndan yetkilerine sahip olunabilmesi i\u00e7in client identifier, username ve password bilgileri e\u015fli\u011finde authorization server&#8217;a y\u00f6nlendirilir. Kullan\u0131c\u0131, client&#8217;\u0131n belli ba\u015fl\u0131 bilgilerine olan eri\u015fim talebini bu bilgilerle onaylar veya reddeder. Onay verildi\u011fi taktirde authorization code \u00fcretilir. Neticede tekrar kullan\u0131c\u0131 client&#8217;a geri y\u00f6nlendirilir.<\/p>\n<p>B\u00f6ylece authorization code&#8217;a sahip olan client, bu kodu kullanarak authorization server&#8217;dan access token talebinde bulunur. Authorization server ise client&#8217;tan gelen bu talep neticesinde hem authorization code&#8217;u hem de client credential bilgilerini do\u011frular ve kullan\u0131c\u0131 yetkilerine sahip olan bir access token \u00fcretip client&#8217;a d\u00f6nd\u00fcr\u00fcr. Ve nihai olarak bu access token ile client art\u0131k yetkilendirilmi\u015f olur ve art\u0131k istedi\u011fi resource server&#8217;lara(API resource&#8217;lara) isteklerde bulunabilir.<\/p>\n<p>\u0130\u015fte t\u00fcm bu s\u00fcre\u00e7te client&#8217;\u0131 yetkilendirebilmek i\u00e7in \u00f6nce authorization code&#8217;a ard\u0131ndan da access token&#8217;a ihtiya\u00e7 duyuldu\u011fu i\u00e7in iki a\u015famal\u0131 do\u011frulama s\u00f6z konusudur.<\/p>\n<p>Bu girizg\u00e2h sonra art\u0131k OpenIddict ile Authorization Code Flow&#8217;un yap\u0131land\u0131rmas\u0131na ge\u00e7ebiliriz.<\/p>\n<h4>OpendIddict ile Authorization Code Flow Yap\u0131land\u0131rmas\u0131<\/h4>\n<p><span style=\"font-size:12px;\">Not : Buradaki yap\u0131land\u0131rma s\u00fcrecinde kullan\u0131lan proje temelleri yaz\u0131 serisi boyunca olu\u015fturulup geli\u015ftirilen <a href=\"https:\/\/github.com\/gncyyldz\/OpenIddict-Authorization-Server-Example\" rel=\"noopener\" target=\"_blank\">\u015fu adresteki<\/a> github reposundan \u00e7ekilmi\u015ftir.<\/span><br \/>\n\u0130lk olarak authorization code flow&#8217;u etkinle\u015ftirebilmek i\u00e7in a\u015fa\u011f\u0131daki konfig\u00fcrasyonlar\u0131n yap\u0131lmas\u0131 gerekmektedir;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n\/\/OpenIddict servisini uygulamaya ekliyoruz.\r\nbuilder.Services.AddOpenIddict()\r\n    .AddCore(options =&gt;\r\n    {\r\n        .\r\n        .\r\n        .\r\n    })\r\n    .AddServer(options =&gt;\r\n    {\r\n        options.SetTokenEndpointUris(&quot;\/connect\/token&quot;)\r\n               \/\/Authorization Code talebinde bulunulacak endpoint'i set ediyoruz.\r\n               .SetAuthorizationEndpointUris(&quot;\/connect\/authorize&quot;);\r\n        \r\n        options.AllowClientCredentialsFlow()\r\n               \/\/Authorization Code Flow'u etkile\u015ftiriyoruz.\r\n               .AllowAuthorizationCodeFlow()\r\n               .RequireProofKeyForCodeExchange();\r\n        .\r\n        .\r\n        .\r\n        options.UseAspNetCore()\r\n               .EnableTokenEndpointPassthrough()\r\n               \/\/EnableAuthorizationEndpointPassthrough: OpenID Connect request'lerinin Authorization Endpoint i\u00e7in aktifle\u015ftirilmesini sa\u011flar.\r\n               .EnableAuthorizationEndpointPassthrough();\r\n       .\r\n       .\r\n       .\r\n    });\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki konfig\u00fcrasyonel kodlar\u0131 incelersek e\u011fer; <strong>13.<\/strong> sat\u0131rda <code style=\"color:red;\">SetAuthorizationEndpointUris<\/code> metodu ile authorization code talebi i\u00e7in endpoint tan\u0131mlamas\u0131nda bulunuyoruz. <strong>17.<\/strong> sat\u0131rda ise <code style=\"color:red;\">AllowAuthorizationCodeFlow<\/code> metodu ile authorization code flow&#8217;u etkinle\u015ftiriyor ve hemen ard\u0131ndan <strong>18.<\/strong> sat\u0131rda <code style=\"color:red;\">RequireProofKeyForCodeExchange<\/code> metodu ile de t\u00fcm bu client&#8217;lar\u0131n <a href=\"https:\/\/www.gencayyildiz.com\/blog\/identityserver4-yazi-serisi-20-pkceproof-key-for-code-exchange\/\" rel=\"noopener\" target=\"_blank\">PKCE<\/a> kullanmas\u0131 gerekti\u011fini ifade ediyoruz. <strong>25.<\/strong> sat\u0131rda ise <code style=\"color:red;\">EnableAuthorizationEndpointPassthrough<\/code> metodu ile gelen request&#8217;leri authorization endpoint&#8217;i ile kar\u015f\u0131l\u0131yoruz.<\/p>\n<h4>Authorization Endpoint&#8217;inin Yap\u0131land\u0131r\u0131lmas\u0131<\/h4>\n<p>\u015eimdi, authorization code talebinde bulunulabilmesi i\u00e7in &#8216;AuthorizationController&#8217; i\u00e7erisinde a\u015fa\u011f\u0131daki authorization endpoint g\u00f6revini g\u00f6recek olan &#8216;Authorize&#8217; action metodunu in\u015fa edelim.<\/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;), Produces(&quot;application\/json&quot;)]\r\n        public async Task&lt;IActionResult&gt; Exchange()\r\n        {\r\n            .\r\n            .\r\n            .\r\n        }\r\n\r\n        &#x5B;HttpGet(&quot;~\/connect\/authorize&quot;), HttpPost(&quot;~\/connect\/authorize&quot;)]\r\n        public async Task&lt;IActionResult&gt; Authorize(string accept, string deny)\r\n        {\r\n            var request = HttpContext.GetOpenIddictServerRequest() ?? throw new InvalidOperationException(&quot;The OpenID Connect request cannot be retrieved.&quot;);\r\n\r\n            \/\/Cookie'de authentication i\u00e7in tutulan veriden kullan\u0131c\u0131 bilgisini al\u0131yoruz.\r\n            var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);\r\n            \/\/E\u011fer kullan\u0131c\u0131 bilgisi yoksa kullan\u0131c\u0131y\u0131 login sayfas\u0131na y\u00f6nlendiriyoruz.\r\n            if (!result.Succeeded)\r\n                return Challenge(\r\n                    authenticationSchemes: CookieAuthenticationDefaults.AuthenticationScheme,\r\n                    properties: new AuthenticationProperties()\r\n                    {\r\n                        RedirectUri = $&quot;{Request.PathBase}{Request.Path}{(QueryString.Create(Request.HasFormContentType ? Request.Form.ToList() : Request.Query.ToList()))}&quot;\r\n                    });\r\n\r\n            var identity = new ClaimsIdentity(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);\r\n            identity.AddClaim(OpenIddictConstants.Claims.Subject, result.Principal.Identity.Name, Destinations.AccessToken);\r\n            identity.AddClaim(JwtRegisteredClaimNames.Aud, &quot;Example-OpenIddict&quot;, Destinations.AccessToken, Destinations.IdentityToken);\r\n            identity.AddClaim(&quot;ornek-claim&quot;, &quot;ornek claim value&quot;, Destinations.AccessToken);\r\n\r\n            var application = await _applicationManager.FindByClientIdAsync(request.ClientId);\r\n            if (HttpContext.Request.Method == &quot;GET&quot;)\r\n                return View(new AuthorizeVM\r\n                {\r\n                    ApplicationName = await _applicationManager.GetLocalizedDisplayNameAsync(application),\r\n                    Scopes = request.Scope\r\n                });\r\n            else if (!string.IsNullOrEmpty(accept))\r\n            {\r\n                var claimsPrincipal = new ClaimsPrincipal(identity);\r\n                claimsPrincipal.SetScopes(request.GetScopes());\r\n\r\n                return SignIn(claimsPrincipal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);\r\n            }\r\n\r\n            return Forbid(authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme,\r\n                properties: new AuthenticationProperties(new Dictionary&lt;string, string&gt;\r\n                {\r\n                    &#x5B;OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidScope\r\n                }));\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>\u0130lgili metodun i\u00e7eri\u011fini incelerseniz e\u011fer; <a href=\"https:\/\/www.gencayyildiz.com\/blog\/openiddict-2-client-credentials-flow\/\" rel=\"noopener\" target=\"_blank\">Client Credentials Flow<\/a>&#8216;dan farkl\u0131 olarak authorization code, onay i\u00e7in kullan\u0131c\u0131 bilgisine odaklanmaktad\u0131r. Her ne kadar client authorization server&#8217;dan kullan\u0131c\u0131 bilgilerini talep ediyor olsa da bizler kullan\u0131c\u0131n\u0131n \u00f6nceden oturum a\u00e7\u0131p a\u00e7mad\u0131\u011f\u0131n\u0131 <strong>25.<\/strong> sat\u0131rda denetliyor, gerekirse <strong>27<\/strong> ile <strong>33.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda oldu\u011fu gibi login sayfas\u0131na y\u00f6nlendiriyoruz.<\/p>\n<p>Kullan\u0131c\u0131 kimli\u011fi do\u011frulanm\u0131\u015fsa e\u011fer client&#8217;a kullan\u0131c\u0131ya dair verilecek bilgiler <strong>35<\/strong> ile <strong>38.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda claim olarak haz\u0131rlanmaktad\u0131r. <strong>41<\/strong> ile <strong>53.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda ise client&#8217;\u0131n, authorization server&#8217;dan kullan\u0131c\u0131ya dair isteyece\u011fi yetkilerin kullan\u0131c\u0131 tarafl\u0131 onay\u0131n\u0131 sunmakta ve bu onay\u0131n verilip verilmedi\u011fi kontrol edilmektedir. <strong>42<\/strong> ile <strong>46.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda onay sayfas\u0131na y\u00f6nlendirme ger\u00e7ekle\u015ftirilmekte, <strong>48<\/strong> ile <strong>53.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda ise onay verildiyse <code style=\"color:red;\">SignIn<\/code> fonksiyonunu kullanarak authorization code&#8217;a kar\u015f\u0131l\u0131k access token d\u00f6nd\u00fcrebilmesi i\u00e7in OpenIddict middleware&#8217;i tetiklemektedir. Ve son olarak <strong>55<\/strong> ile <strong>59.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda ise onay verilmedi\u011fi taktirde <code style=\"color:red;\">Forbid<\/code> metodu ile yetkilendirmeye engel olunmaktad\u0131r.<\/p>\n<p>Burada onay sayfas\u0131 taraf\u0131m\u0131zca a\u015fa\u011f\u0131daki gibi tasarlanm\u0131\u015ft\u0131r.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n@using Microsoft.Extensions.Primitives\r\n@using OpenIddict.AuthorizationServer.ViewModels\r\n@model AuthorizeVM\r\n&lt;div class=&quot;jumbotron&quot;&gt;\r\n    &lt;h1&gt;Yetki Onaylama&lt;\/h1&gt;\r\n\r\n    &lt;p class=&quot;lead text-left&quot;&gt;&lt;strong&gt;@Model.ApplicationName&lt;\/strong&gt; uygulamas\u0131na eri\u015fim yetkisi vermek istiyor musunuz? (Beklenen yetkiler: @Model.Scopes)&lt;\/p&gt;\r\n\r\n    &lt;form asp-controller=&quot;Authorization&quot; asp-action=&quot;Authorize&quot; method=&quot;post&quot;&gt;\r\n        @foreach (var parameter in Context.Request.HasFormContentType ?\r\n        (IEnumerable&lt;KeyValuePair&lt;string, StringValues&gt;&gt;)Context.Request.Form : Context.Request.Query)\r\n        {\r\n            &lt;input type=&quot;hidden&quot; name=&quot;@parameter.Key&quot; value=&quot;@parameter.Value&quot; \/&gt;\r\n        }\r\n\r\n        &lt;input class=&quot;btn btn-lg btn-success&quot; name=&quot;accept&quot; type=&quot;submit&quot; value=&quot;Yes&quot; \/&gt;\r\n        &lt;input class=&quot;btn btn-lg btn-danger&quot; name=&quot;deny&quot; type=&quot;submit&quot; value=&quot;No&quot; \/&gt;\r\n    &lt;\/form&gt;\r\n&lt;\/div&gt;\r\n<\/pre>\n<\/div>\n<p>Ve kullan\u0131lan viewmodel&#8217;\u0131n i\u00e7eri\u011fini de payla\u015fmam\u0131z gerekirse e\u011fer;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class AuthorizeVM\r\n    {\r\n        public string ApplicationName { get; set; }\r\n        public string Scopes { get; set; }\r\n        public string Button { get; set; }\r\n    }\r\n<\/pre>\n<\/div>\n<h4>Token Endpoint&#8217;inin Yap\u0131land\u0131r\u0131lmas\u0131<\/h4>\n<p>Art\u0131k authorization code flow&#8217;u desteklendi\u011fimiz i\u00e7in token endpoint&#8217;i ona g\u00f6re yap\u0131land\u0131rmam\u0131z gerekmektedir.<\/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;), Produces(&quot;application\/json&quot;)]\r\n        public async Task&lt;IActionResult&gt; Exchange()\r\n        {\r\n            var request = HttpContext.GetOpenIddictServerRequest();\r\n\r\n\r\n            if (request?.IsAuthorizationCodeGrantType() is not null)\r\n            {\r\n                \/\/Authorization Code'da store edilen request sorumlusunu elde ediyoruz.\r\n                var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal;\r\n\r\n                \/\/Principal'\u0131 yani kullan\u0131c\u0131y\u0131 do\u011frula\r\n                \/\/if ((await _userManager.GetUserAsnyc(principal)) != null)\r\n                \/\/{\r\n\r\n                \/\/}\r\n\r\n                return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);\r\n\r\n            }\r\n            else if (request?.IsClientCredentialsGrantType() is not null)\r\n            {\r\n                .\r\n                .\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        &#x5B;HttpGet(&quot;~\/connect\/authorize&quot;), HttpPost(&quot;~\/connect\/authorize&quot;)]\r\n        public async Task&lt;IActionResult&gt; Authorize(string accept, string deny)\r\n        {\r\n            .\r\n            .\r\n            .\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki kod blo\u011funu incelerseniz e\u011fer <strong>17<\/strong> ile <strong>30.<\/strong> sat\u0131r aral\u0131\u011f\u0131n\u0131 ekstradan eklemi\u015f ve <code style=\"color:red;\">IsAuthorizationCodeGrantType<\/code> fonksiyonu ile ilgili ak\u0131\u015fa g\u00f6re bir \u00e7al\u0131\u015fma ger\u00e7ekle\u015ftirmi\u015f bulunuyoruz.<\/p>\n<h4>Client&#8217;a Redirect Urls Bilgisinin Verilmesi<\/h4>\n<p>Authorization server&#8217;dan, authorization code i\u00e7in talepte bulunan client geri d\u00f6n\u00fc\u015f url&#8217;i olarak hangi adreste kar\u015f\u0131lama yapaca\u011f\u0131n\u0131 bildirmek mecburiyetindedir. Haliyle bizler postman uygulamas\u0131n\u0131 test ama\u00e7l\u0131 kullanaca\u011f\u0131m\u0131zdan dolay\u0131 postman client g\u00f6revi g\u00f6recektir ve bundan dolay\u0131 authorization code flow ile yap\u0131lan talepler neticesinde authorization server&#8217;dan postman&#8217;e geri d\u00f6n\u00fc\u015f yap\u0131labilmesi i\u00e7in postman&#8217;in bizlere sunmu\u015f oldu\u011fu \u015fu:<span style=\"font-size:12px;\">https:\/\/oauth.pstmn.io\/v1\/callback<\/span> adresi kullan\u0131l\u0131yor olacakt\u0131r.<\/p>\n<p>Bunun i\u00e7in client&#8217;lar\u0131n tan\u0131mland\u0131\u011f\u0131 veya bir ba\u015fka deyi\u015fle kay\u0131t edildi\u011fi &#8216;ClientsController&#8217; s\u0131n\u0131f\u0131n\u0131n i\u00e7erisindeki &#8216;CreateClient&#8217; metodunda a\u015fa\u011f\u0131daki gibi \u00e7al\u0131\u015fman\u0131n yap\u0131lmas\u0131 gerekmektedir.<\/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        .\r\n        .\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                    RedirectUris = { new(&quot;https:\/\/oauth.pstmn.io\/v1\/callback&quot;) },\r\n                    Permissions =\r\n                    {\r\n                        OpenIddictConstants.Permissions.Endpoints.Token,\r\n                        OpenIddictConstants.Permissions.Endpoints.Authorization,\r\n\r\n                        OpenIddictConstants.Permissions.GrantTypes.ClientCredentials,\r\n                        OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode,\r\n\r\n                        OpenIddictConstants.Permissions.Prefixes.Scope + &quot;read&quot;,\r\n                        OpenIddictConstants.Permissions.Prefixes.Scope + &quot;write&quot;,\r\n\r\n                        OpenIddictConstants.Permissions.ResponseTypes.Code,\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>Ya da client olarak postman yerine farkl\u0131 bir uygulama kullan\u0131lacaksa e\u011fer yukar\u0131daki kod blo\u011funun <strong>25.<\/strong> sat\u0131r\u0131 o uygulaman\u0131n redirect url&#8217;ine g\u00f6re ayarlanmas\u0131 gerekmektedir.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n        .\r\n        .\r\n        RedirectUris = { new(&quot;https:\/\/filanca.com\/...&quot;) },\r\n<\/pre>\n<\/div>\n<p>Ek olarak client&#8217;\u0131n izinleri olarak da &#8216;Permissions&#8217; property&#8217;sine &#8216;Authorization&#8217;, &#8216;AuthorizationCode&#8217; ve &#8216;Code&#8217; yetkilerinin de verildi\u011fine dikkatinizi \u00e7ekerim.<\/p>\n<p>Ayr\u0131ca burada isterseniz redirect url&#8217;i yine client&#8217;tan talep edebilirsiniz. Tabi bu sefer bahsedilen client eklenecek olan de\u011fil, bu ekleme i\u015flemini yapacak olan client&#8217;t\u0131r \ud83d\ude42<\/p>\n<p>Client&#8217;lar\u0131n redirect url&#8217;lerini bu \u015fekilde belirledikten sonra yeni gelecek olan client kay\u0131tlar\u0131nda verilerin a\u015fa\u011f\u0131daki gibi veritaban\u0131na yans\u0131t\u0131ld\u0131\u011f\u0131n\u0131 g\u00f6zlemliyor olaca\u011f\u0131z.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow.png\" alt=\"OpenIddict #3 - Authorization Code Flow\" width=\"1616\" height=\"116\" class=\"aligncenter size-full wp-image-25701\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow.png 1616w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-300x22.png 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-1024x74.png 1024w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-768x55.png 768w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-1536x110.png 1536w\" sizes=\"auto, (max-width: 1616px) 100vw, 1616px\" \/><\/a><\/p>\n<h4>Postman \u00dczerinden Test Edilmesi<\/h4>\n<p>Art\u0131k yapt\u0131\u011f\u0131m\u0131z \u00e7al\u0131\u015fmay\u0131 test edip, g\u00f6zlemleyebiliriz. Bunun i\u00e7in ilk olarak postman&#8217;in &#8216;OAuth 2.0&#8217; t\u00fcr\u00fc \u00fczerinden bir token talebinde bulunacak ard\u0131ndan kendi geli\u015ftirece\u011fimiz custom bir client \u00fczerinden de testimizi ger\u00e7ekle\u015ftiriyor olaca\u011f\u0131z.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-1.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-1.png\" alt=\"OpenIddict #3 - Authorization Code Flow\" width=\"1078\" height=\"791\" class=\"aligncenter size-full wp-image-25703\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-1.png 1078w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-1-300x220.png 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-1-1024x751.png 1024w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-1-768x564.png 768w\" sizes=\"auto, (max-width: 1078px) 100vw, 1078px\" \/><\/a><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-2.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-2.png\" alt=\"OpenIddict #3 - Authorization Code Flow\" width=\"445\" height=\"224\" class=\"alignleft size-full wp-image-25705\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-2.png 445w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-2-300x151.png 300w\" sizes=\"auto, (max-width: 445px) 100vw, 445px\" \/><\/a>Yukar\u0131daki ekran g\u00f6r\u00fcnt\u00fcs\u00fcnde g\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere gerekli bilgileri postman aray\u00fcz\u00fcne i\u015fledikten sonra a\u015fa\u011f\u0131daki &#8216;Get New Access Token&#8217; butonuna t\u0131klad\u0131\u011f\u0131m\u0131zda yandaki gibi onay sayfas\u0131na y\u00f6nlendirildi\u011fimizi g\u00f6rece\u011fiz. Burada &#8216;Yes&#8217; ya da &#8216;No&#8217; butonlar\u0131 i\u015flevlerine g\u00f6re authorization code&#8217;un \u00fcretilmesi s\u00fcrecini ya ba\u015flatacakt\u0131r ya da ba\u015flamadan iptal edecektir. &#8216;Yes&#8217; butonuna t\u0131kland\u0131\u011f\u0131 vakit \u00f6nceki sat\u0131rlarda geli\u015ftirdi\u011fimiz &#8216;AuthorizationController&#8217; i\u00e7erisindeki &#8216;Authorize&#8217; action&#8217;\u0131na bir <code>POST<\/code> at\u0131lacak ve burada authorization code ile gerekli access token&#8217;\u0131n \u00fcretilebilmesi i\u00e7in <code style=\"color:red;\">SignIn<\/code> metodu e\u015fli\u011finde OpenIddict middleware&#8217;i devreye sokulacakt\u0131r. Ard\u0131ndan bu i\u015flemden sonra authorization code \u00fcretilecek ve ilgili client&#8217;\u0131n redirect url&#8217;ine &#8216;code&#8217; query string&#8217;i e\u015fli\u011finde g\u00f6nderilecektir.<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-3.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-3.png\" alt=\"OpenIddict #3 - Authorization Code Flow\" width=\"1273\" height=\"314\" class=\"aligncenter size-full wp-image-25706\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-3.png 1273w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-3-300x74.png 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-3-1024x253.png 1024w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-3-768x189.png 768w\" sizes=\"auto, (max-width: 1273px) 100vw, 1273px\" \/><\/a>\u0130\u015fte postman&#8217;de ilgili redirect url&#8217;in ekran g\u00f6r\u00fcnt\u00fcs\u00fc yukar\u0131daki gibidir ve daha da \u00f6nemlisi \u00fcretilmi\u015f olan authorization code &#8216;code&#8217; query string parametresinde oldu\u011fu gibi client taraf\u0131ndan elde edilmektedir.<\/p>\n<p>Bu sayfa a\u00e7\u0131ld\u0131\u011f\u0131 taktirde elde edilen authorization code ile &#8216;AuthorizationController&#8217; i\u00e7erisindeki &#8216;Exchange&#8217; action&#8217;\u0131na authorization code grant t\u00fcr\u00fcnde istek g\u00f6nderilmekte ve ilgili authorization code&#8217;a nazaran access token \u00fcretilerek geri d\u00f6nd\u00fcr\u00fclmektedir.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-4.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-4.png\" alt=\"OpenIddict #3 - Authorization Code Flow\" width=\"562\" height=\"383\" class=\"aligncenter size-full wp-image-25709\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-4.png 562w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-4-300x204.png 300w\" sizes=\"auto, (max-width: 562px) 100vw, 562px\" \/><\/a>Bu a\u015famadan sonra ilgili access token&#8217;\u0131 kullanarak Resource Server&#8217;lara(ya da API Server&#8217;lara) yap\u0131lan t\u00fcm istekler ba\u015far\u0131l\u0131 \u015fekilde sonu\u00e7lanacakt\u0131rlar.<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-5.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-5.png\" alt=\"OpenIddict #3 - Authorization Code Flow\" width=\"93\" height=\"29\" class=\"aligncenter size-full wp-image-25712\" \/><\/a><\/p>\n<h4>Access Token&#8217;\u0131n <a href=\"https:\/\/jwt.io\/\" rel=\"noopener\" target=\"_blank\">jwt.io<\/a>&#8216;da Decode Edilmesi<\/h4>\n<p>\u00dcretilen access token de\u011ferini decode edip incelememiz gerekirse e\u011fer bunun i\u00e7in <a href=\"https:\/\/jwt.io\/\" rel=\"noopener\" target=\"_blank\">jwt.io<\/a>&#8216;dan istifade edebiliriz.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-6.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-6.png\" alt=\"OpenIddict #3 - Authorization Code Flow\" width=\"875\" height=\"467\" class=\"aligncenter size-full wp-image-25727\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-6.png 875w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-6-300x160.png 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-6-768x410.png 768w\" sizes=\"auto, (max-width: 875px) 100vw, 875px\" \/><\/a><\/p>\n<h4>Custom Geli\u015ftirilen Asp.NET Core MVC Temelli Client \u00dczerinden Test Edilmesi<\/h4>\n<p>\u015eimdide yapt\u0131\u011f\u0131m\u0131z \u00e7al\u0131\u015fmay\u0131 custom geli\u015ftirece\u011fimiz uygulama \u00fczerinden test edelim. Bunun i\u00e7in &#8216;Client&#8217; ad\u0131nda bir Asp.NET Core MVC uygulamas\u0131 olu\u015fturarak i\u00e7erisine a\u015fa\u011f\u0131daki k\u00fct\u00fcphaneleri y\u00fckleyerek ba\u015flayabiliriz.<\/p>\n<div style=\"text-align:center;color:red;font-size:15px;\">\n<code><a href=\"https:\/\/www.nuget.org\/packages\/OpenIddict\/4.0.0-preview3.22422.72\" rel=\"noopener\" target=\"_blank\">dotnet add package OpenIddict --version 4.0.0-preview3.22422.72<\/a><\/code><br \/>\n<code><a href=\"https:\/\/www.nuget.org\/packages\/OpenIddict.EntityFrameworkCore\/4.0.0-preview3.22422.72\" rel=\"noopener\" target=\"_blank\">dotnet add package OpenIddict.EntityFrameworkCore --version 4.0.0-preview3.22422.72<\/a><\/code><br \/>\n<code><a href=\"https:\/\/www.nuget.org\/packages\/OpenIddict.AspNetCore\/4.0.0-preview3.22422.72\" rel=\"noopener\" target=\"_blank\">dotnet add package OpenIddict.AspNetCore --version 4.0.0-preview3.22422.72<\/a><\/code>\n<\/div>\n<p>Bu k\u00fct\u00fcphanelerle Asp.NET Core uygulamas\u0131n\u0131 client olarak tasarlayabilecek ve gerekli konfig\u00fcrasyonlar\u0131 sa\u011flayabilece\u011fiz.<\/p>\n<p>Temel k\u00fct\u00fcphaneleri y\u00fckledikten sonra &#8216;Program.cs&#8217; dosyas\u0131nda a\u015fa\u011f\u0131daki yap\u0131land\u0131rmalarda bulunal\u0131m;<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nusing Client.Models;\r\nusing Microsoft.AspNetCore.Authentication.Cookies;\r\nusing Microsoft.AspNetCore.Authentication.OpenIdConnect;\r\nusing Microsoft.EntityFrameworkCore;\r\nusing Microsoft.IdentityModel.Protocols.OpenIdConnect;\r\nusing OpenIddict.Client;\r\nusing static OpenIddict.Abstractions.OpenIddictConstants;\r\n\r\nvar builder = WebApplication.CreateBuilder(args);\r\n\r\nbuilder.Services.AddControllersWithViews();\r\n\r\nbuilder.Services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;\r\n{\r\n    options.UseSqlServer(builder.Configuration.GetConnectionString(&quot;SQLServer&quot;));\r\n    options.UseOpenIddict();\r\n});\r\n\r\nbuilder.Services.AddAuthentication(options =&gt; options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme)\r\n    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =&gt;\r\n    {\r\n        options.LoginPath = &quot;\/login&quot;;\r\n        options.ExpireTimeSpan = TimeSpan.FromMinutes(15);\r\n    });\r\n\r\nbuilder.Services.AddOpenIddict()\r\n    .AddCore(options =&gt;\r\n    {\r\n        options.UseEntityFrameworkCore()\r\n        .UseDbContext&lt;ApplicationDbContext&gt;();\r\n\r\n        \/\/Burada MongoDB kullanmak isterseniz a\u015fa\u011f\u0131daki yap\u0131land\u0131rma kodlar\u0131ndan istifade edebilirsiniz.\r\n        \/\/ options.UseMongoDb()\r\n        \/\/        .UseDatabase(new MongoClient().GetDatabase(&quot;openiddict&quot;));\r\n    })\r\n    \/\/OpenIddict client componentinin yap\u0131land\u0131rmas\u0131.\r\n    .AddClient(options =&gt;\r\n    {\r\n        options.SetRedirectionEndpointUris(&quot;\/callback\/login\/local&quot;);\r\n        options.SetPostLogoutRedirectionEndpointUris(&quot;\/callback\/logout\/local&quot;);\r\n\r\n        options.AddDevelopmentEncryptionCertificate()\r\n               .AddDevelopmentSigningCertificate();\r\n\r\n        options.UseAspNetCore()\r\n                      .EnableStatusCodePagesIntegration()\r\n                      .EnableRedirectionEndpointPassthrough()\r\n                      .EnablePostLogoutRedirectionEndpointPassthrough();\r\n\r\n        options.UseSystemNetHttp();\r\n\r\n        options.AddRegistration(new OpenIddictClientRegistration\r\n        {\r\n            Issuer = new Uri(&quot;https:\/\/localhost:7047&quot;, UriKind.Absolute),\r\n\r\n            ClientId = &quot;my-client&quot;,\r\n            ClientSecret = &quot;my-client-secret&quot;,\r\n            Scopes = { &quot;read&quot;, &quot;write&quot; },\r\n\r\n            RedirectUri = new Uri(&quot;https:\/\/localhost:7226\/callback\/login\/local&quot;, UriKind.Absolute),\r\n            PostLogoutRedirectUri = new Uri(&quot;https:\/\/localhost:7226\/callback\/logout\/local&quot;, UriKind.Absolute),\r\n        });\r\n    });\r\n\r\nbuilder.Services.AddHttpClient();\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\r\n<\/pre>\n<\/div>\n<p>Burada \u00f6zellikle <strong>37<\/strong> ile <strong>63.<\/strong> sat\u0131r aral\u0131\u011f\u0131na g\u00f6z atarsan\u0131z e\u011fer OpenIddict i\u00e7in gerekli client yap\u0131land\u0131rmalar\u0131 sa\u011flanmaktad\u0131r. <code style=\"color:red;\">SetRedirectionEndpointUris<\/code> ve <code style=\"color:red;\">SetPostLogoutRedirectionEndpointUris<\/code> fonksiyonlar\u0131 ile authorization server&#8217;a yap\u0131lan authorization code yahut logout talepleri i\u00e7in uygulamadaki y\u00f6nlendirme adresleri bildirilmektedir. \u00d6zellikle <strong>52<\/strong> ile <strong>62.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda ise <code style=\"color:red;\">AddRegistration<\/code> fonksiyonu e\u015fli\u011finde client bilgileri tan\u0131mlanmaktad\u0131r. Tabi buradaki client bilgilerini esas\u0131nda authorization server&#8217;a gidip tan\u0131mlaman\u0131z gerekti\u011fini hat\u0131rlatmakta fayda g\u00f6rmekteyim.<\/p>\n<p>Bu tan\u0131mlamalar\u0131 yapt\u0131ktan sonra olu\u015fturdu\u011fumuz bu client uygulamas\u0131nda &#8216;AuthenticationController.cs&#8217; isminde bir controller s\u0131n\u0131f\u0131 olu\u015ftural\u0131m ve i\u00e7eri\u011fini 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 AuthenticationController : Controller\r\n    {\r\n        &#x5B;HttpGet(&quot;~\/login&quot;)]\r\n        public IActionResult LogIn(string returnUrl)\r\n        {\r\n            var properties = new AuthenticationProperties(new Dictionary&lt;string, string?&gt;\r\n            {\r\n                &#x5B;OpenIddictClientAspNetCoreConstants.Properties.Issuer] = &quot;https:\/\/localhost:7047&quot;\r\n            });\r\n            properties.RedirectUri = Url.IsLocalUrl(returnUrl) ? returnUrl : &quot;\/&quot;;\r\n\r\n            \/\/Challenge metodu ile OpenIddict middleware'\u0131 sayesinde ilgili Issuer'a kar\u015f\u0131l\u0131k gelen client bilgilerini authorization server'a y\u00f6nlendiriyoruz.\r\n            return Challenge(properties, OpenIddictClientAspNetCoreDefaults.AuthenticationScheme);\r\n        }\r\n\r\n        &#x5B;HttpPost(&quot;~\/logout&quot;), ValidateAntiForgeryToken]\r\n        public async Task&lt;ActionResult&gt; LogOut(string returnUrl)\r\n        {\r\n            \/\/Elde bulunan authentication cookie bilgilerini elde ediyoruz. E\u011fer yoksa zaten kullan\u0131c\u0131n\u0131n hen\u00fcz oturum a\u00e7mad\u0131\u011f\u0131n\u0131 anl\u0131yoruz.\r\n            var result = await HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);\r\n            if (result is not { Succeeded: true })\r\n                return Redirect(Url.IsLocalUrl(returnUrl) ? returnUrl : &quot;\/&quot;);\r\n\r\n            \/\/SignOut yaparak mevcut authentication cookie bilgilerini temizliyoruz.\r\n            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);\r\n\r\n            var properties = new AuthenticationProperties(new Dictionary&lt;string, string?&gt;\r\n            {\r\n                &#x5B;OpenIddictClientAspNetCoreConstants.Properties.Issuer] = &quot;https:\/\/localhost:7047&quot;,\r\n                &#x5B;OpenIddictClientAspNetCoreConstants.Properties.IdentityTokenHint] = result.Properties.GetTokenValue(OpenIddictClientAspNetCoreConstants.Tokens.BackchannelIdentityToken)\r\n            });\r\n            properties.RedirectUri = Url.IsLocalUrl(returnUrl) ? returnUrl : &quot;\/&quot;;\r\n\r\n            return SignOut(properties, OpenIddictClientAspNetCoreDefaults.AuthenticationScheme);\r\n        }\r\n\r\n        &#x5B;HttpGet(&quot;~\/callback\/login\/{provider}&quot;), HttpPost(&quot;~\/callback\/login\/{provider}&quot;), IgnoreAntiforgeryToken]\r\n        public async Task&lt;ActionResult&gt; LogInCallback()\r\n        {\r\n            \/\/ OpenIddict taraf\u0131ndan do\u011frulanan yetkilendirme verilerini elde ediyoruz.\r\n            var result = await HttpContext.AuthenticateAsync(OpenIddictClientAspNetCoreDefaults.AuthenticationScheme);\r\n\r\n            if (result.Principal.Identity is not ClaimsIdentity { IsAuthenticated: true })\r\n            {\r\n                throw new InvalidOperationException(&quot;The external authorization data cannot be used for authentication.&quot;);\r\n            }\r\n\r\n            var claims = new List&lt;Claim&gt;(result.Principal.Claims\r\n                .Select(claim =&gt; claim switch\r\n                {\r\n                    { Type: Claims.Subject }\r\n                        =&gt; new Claim(ClaimTypes.NameIdentifier, claim.Value, claim.ValueType, claim.Issuer),\r\n                    { Type: Claims.Name }\r\n                        =&gt; new Claim(ClaimTypes.Name, claim.Value, claim.ValueType, claim.Issuer),\r\n                    _ =&gt; claim\r\n                })\r\n                .Where(claim =&gt; claim switch\r\n                {\r\n                    { Type: ClaimTypes.NameIdentifier or ClaimTypes.Name } =&gt; true,\r\n                    _ =&gt; false\r\n                }));\r\n\r\n            var identity = new ClaimsIdentity(claims,\r\n                authenticationType: CookieAuthenticationDefaults.AuthenticationScheme,\r\n                nameType: ClaimTypes.Name,\r\n                roleType: ClaimTypes.Role);\r\n\r\n            var properties = new AuthenticationProperties(result.Properties.Items);\r\n\r\n            \/\/ Gerekirse authorization server taraf\u0131ndan d\u00f6nd\u00fcr\u00fclen tokenlar authentication cookie'de de saklanabilir.\r\n            properties.StoreTokens(result.Properties.GetTokens().Where(token =&gt; token switch\r\n            {\r\n                {\r\n                    Name: OpenIddictClientAspNetCoreConstants.Tokens.BackchannelAccessToken or\r\n                          OpenIddictClientAspNetCoreConstants.Tokens.BackchannelIdentityToken or\r\n                          OpenIddictClientAspNetCoreConstants.Tokens.RefreshToken\r\n                } =&gt; true,\r\n                _ =&gt; false\r\n            }));\r\n\r\n            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity), properties);\r\n\r\n            return Redirect(properties.RedirectUri);\r\n        }\r\n\r\n        &#x5B;HttpGet(&quot;~\/callback\/logout\/{provider}&quot;), HttpPost(&quot;~\/callback\/logout\/{provider}&quot;), IgnoreAntiforgeryToken]\r\n        public async Task&lt;ActionResult&gt; LogOutCallback()\r\n        {\r\n            var result = await HttpContext.AuthenticateAsync(OpenIddictClientAspNetCoreDefaults.AuthenticationScheme);\r\n            return Redirect(result!.Properties!.RedirectUri);\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<p>Yukar\u0131daki kod blo\u011funa g\u00f6z atarsan\u0131z e\u011fer; <strong>4<\/strong> ile <strong>14.<\/strong> sat\u0131r aral\u0131\u011f\u0131ndaki <code style=\"color:red;\">LogIn<\/code> metodu i\u00e7erisinde kullan\u0131c\u0131 taraf\u0131ndan onay istenecek \u015fekilde authorization server \u00fczerinden login i\u015flemleri ger\u00e7ekle\u015ftirilmektedir.<\/p>\n<p><strong>17<\/strong> ile <strong>35.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda ise <code style=\"color:red;\">LogOut<\/code> action&#8217;\u0131 i\u00e7erisinde logout operasyonlar\u0131 ger\u00e7ekle\u015ftirilmektedir. Tabi bu operasyonlar\u0131n sa\u011fl\u0131kl\u0131 bir \u015fekilde ger\u00e7ekle\u015febilmesi i\u00e7in authorization server&#8217;da bir ka\u00e7 konfig\u00fcrasyona ihtiya\u00e7 olacakt\u0131r. Bunlardan ilki client eklerken <code style=\"color:red;\">PostLogoutRedirectUris<\/code> property&#8217;sine logout an\u0131nda geri d\u00f6n\u00fc\u015f de\u011ferinin verilmesi, bir di\u011feri ise &#8216;Program.cs&#8217;de  <code style=\"color:red;\">SetLogoutEndpointUris(\"\/connect\/logout\")<\/code> metodu ile logout endpoint url&#8217;inin set edilmesidir.<\/p>\n<p><strong>38<\/strong> ile <strong>84.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda ise login yap\u0131ld\u0131ktan sonra authorization server&#8217;dan gelecek olan authorization code&#8217;u kar\u015f\u0131lay\u0131p gerekli signin i\u015flemleri y\u00fcr\u00fct\u00fclmektedir. Ayn\u0131 \u015fekilde <strong>81<\/strong> ile <strong>91.<\/strong> sat\u0131r aral\u0131\u011f\u0131nda da logout neticesinde authentication cookie&#8217;leri temizlenmektedir.<\/p>\n<p>Bu i\u015flemlerden sonra art\u0131k client taraf\u0131ndan edinilen kullan\u0131c\u0131 yetkilerini deneyimleyebilece\u011fimiz bir \u00e7al\u0131\u015fma yapmam\u0131z yeterli olacakt\u0131r. Bunun i\u00e7in &#8216;HomeController&#8217; i\u00e7erisinde a\u015fa\u011f\u0131daki gibi in\u015fada bulunabiliriz.<\/p>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class HomeController : Controller\r\n    {\r\n        readonly IHttpClientFactory _httpClientFactory;\r\n\r\n        public HomeController(IHttpClientFactory httpClientFactory)\r\n            =&gt; _httpClientFactory = httpClientFactory;\r\n\r\n        public IActionResult Index()\r\n            =&gt; View();\r\n\r\n        &#x5B;HttpPost]\r\n        &#x5B;Authorize]\r\n        public async Task&lt;IActionResult&gt; Index(CancellationToken cancellationToken)\r\n        {\r\n            string? token = await HttpContext.GetTokenAsync(CookieAuthenticationDefaults.AuthenticationScheme, OpenIddictClientAspNetCoreConstants.Tokens.BackchannelAccessToken);\r\n\r\n            using HttpClient httpClient = _httpClientFactory.CreateClient();\r\n            using HttpRequestMessage httpRequestMessage = new(HttpMethod.Get, &quot;https:\/\/localhost:7056\/api\/values\/a&quot;);\r\n            httpRequestMessage.Headers.Authorization = new(&quot;Bearer&quot;, token);\r\n\r\n            using HttpResponseMessage httpResponseMessage = await httpClient.SendAsync(httpRequestMessage, cancellationToken);\r\n\r\n            return View(model: await httpResponseMessage.Content.ReadAsStringAsync(cancellationToken));\r\n        }\r\n    }\r\n<\/pre>\n<\/div>\n<div style=\"font-size:12px;\">\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n@model string\r\n\r\n@{\r\n    ViewData&#x5B;&quot;Title&quot;] = &quot;Home Page&quot;;\r\n}\r\n\r\n&lt;div class=&quot;text-center&quot;&gt;\r\n    &lt;h1 class=&quot;display-4&quot;&gt;Welcome&lt;\/h1&gt;\r\n    &lt;p&gt;Learn about &lt;a href=&quot;https:\/\/docs.microsoft.com\/aspnet\/core&quot;&gt;building Web apps with ASP.NET Core&lt;\/a&gt;.&lt;\/p&gt;\r\n&lt;\/div&gt;\r\n\r\n&lt;form asp-action=&quot;Index&quot; asp-controller=&quot;Home&quot;&gt;\r\n    &lt;button&gt;\u0130stek Yap&lt;\/button&gt;\r\n&lt;\/form&gt;\r\n&lt;form asp-action=&quot;Logout&quot; asp-controller=&quot;Authentication&quot; method=&quot;post&quot;&gt;\r\n    &lt;button class=&quot;btn btn-lg btn-danger&quot; type=&quot;submit&quot;&gt;Sign out&lt;\/button&gt;\r\n&lt;\/form&gt;\r\n\r\n&lt;p&gt;\r\n    @Model\r\n&lt;\/p&gt;\r\n<\/pre>\n<\/div>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere &#8216;Index&#8217; action&#8217;\u0131n\u0131n post versiyonu authorize edilmi\u015f vaziyettedir. Yani yetkilendirme beklemektedir. Uygulamay\u0131 aya\u011fa kald\u0131r\u0131p, login olduktan sonra istek yap butonuna t\u0131kland\u0131\u011f\u0131 taktirde requestin API Resource&#8217;a iste\u011fin ba\u015far\u0131yla gidip geldi\u011fini yani client&#8217;\u0131n ba\u015far\u0131yla kullan\u0131c\u0131 izinleriyle yetkilendirildi\u011fini g\u00f6zlemliyor olaca\u011f\u0131z.<\/p>\n<h4>OpenIddict K\u00fct\u00fcphanesi \u0130le Authorization Code S\u00fcre\u00e7lerindeki Veritaban\u0131nda Olu\u015fan Hareketlili\u011fi \u0130nceleyelim<\/h4>\n<p>Client uygulamas\u0131 ile authorization server \u00fczerinden yap\u0131lan her login talebinde &#8216;OpenIddictTokens&#8217; tablosuna bir kay\u0131t at\u0131lmaktad\u0131r.<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-7.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-7.png\" alt=\"OpenIddict #3 - Authorization Code Flow\" width=\"942\" height=\"105\" class=\"aligncenter size-full wp-image-25729\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-7.png 942w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-7-300x33.png 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-7-768x86.png 768w\" sizes=\"auto, (max-width: 942px) 100vw, 942px\" \/><\/a>At\u0131lan kay\u0131t bu iste\u011fin ilk s\u00fcreci oldu\u011fu i\u00e7in <code>state_token<\/code> type de\u011ferinde tutulmaktad\u0131r. Kullan\u0131c\u0131 taraf\u0131ndan onay verilip authorization code elde edildi\u011fi taktirde ilgili tabloya bu token de\u011ferleri de i\u015fleniyor olacakt\u0131r.<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-8.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-8.png\" alt=\"OpenIddict #3 - Authorization Code Flow\" width=\"1038\" height=\"236\" class=\"aligncenter size-full wp-image-25730\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-8.png 1038w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-8-300x68.png 300w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-8-1024x233.png 1024w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2022\/10\/OpenIddict-3-Authorization-Code-Flow-8-768x175.png 768w\" sizes=\"auto, (max-width: 1038px) 100vw, 1038px\" \/><\/a>Ve dikkat ederseniz e\u011fer &#8216;OpenIddictAuthorizations&#8217; tablosunda da ilgili client&#8217;a dair hangi tarihler aras\u0131nda bir authorization i\u015flemi ger\u00e7ekle\u015ftirildi\u011fi tutulmaktad\u0131r. Anlayaca\u011f\u0131n\u0131z, authorization server \u00fczerinden yap\u0131lan t\u00fcm talep s\u00fcre\u00e7lerinde ilgili tablolara kay\u0131tlar\u0131n bu seyirde i\u015flenmesi devam edecektir&#8230;<\/p>\n<p>Evet, b\u00f6ylece OpenIddict k\u00fct\u00fcphanesi ile Authorization Code Flow&#8217;un nas\u0131l uygulanabilece\u011fini incelemi\u015f olduk. Normalde custom uygulamaya \u00f6rnek olarak console projesini de sunmak isterdim lakin i\u00e7eri\u011fin hacmini haddinden fazla \u015fi\u015firmemek i\u00e7in yorumlarda payla\u015fmak \u00fczere makalemizi burada noktal\u0131yorum.<\/p>\n<p>Okuyarak e\u015flik etti\u011finiz i\u00e7in te\u015fekk\u00fcr ederim.<\/p>\n<p>\u0130lgilenenlerin faydalanmas\u0131 dile\u011fiyle&#8230;<br \/>\nSonraki yaz\u0131lar\u0131mda g\u00f6r\u00fc\u015fmek \u00fczere&#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 OpenIddict k\u00fct\u00fcphanesi ile iki a\u015famal\u0131 do\u011frulama ger\u00e7ekle\u015ftirmemizi gereki k\u0131lan Authorization Code Flow&#8216;un nas\u0131l uygulanabilece\u011fini ele al\u0131yor olaca\u011f\u0131z. Hadi buyurun ba\u015flayal\u0131m. Authorization Code Nedir? Tabi \u00f6ncelikle Authorization Code&#8217;un ne oldu\u011funu ele alarak&#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":[3874,3872,4666,4684,4683],"class_list":["post-25671","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-openiddict","tag-authorization-code","tag-authorization-code-flow","tag-openiddict","tag-openiddict-authorization-code","tag-openiddict-authorization-code-flow"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/25671","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=25671"}],"version-history":[{"count":52,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/25671\/revisions"}],"predecessor-version":[{"id":25733,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/25671\/revisions\/25733"}],"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=25671"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=25671"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=25671"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}