{"id":36890,"date":"2017-04-06T08:45:05","date_gmt":"2017-04-06T15:45:05","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/?p=9615"},"modified":"2017-04-06T08:45:05","modified_gmt":"2017-04-06T15:45:05","slug":"jwt-validation-and-authorization-in-asp-net-core","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/jwt-validation-and-authorization-in-asp-net-core\/","title":{"rendered":"JWT Validation and Authorization in ASP.NET Core"},"content":{"rendered":"<p><em>This post was written and submitted by Michael Rousos<\/em><\/p>\n<p>In several <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/bearer-token-authentication-in-asp-net-core\/\">previous<\/a> <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/asp-net-core-authentication-with-identityserver4\/\">posts<\/a>, I discussed a customer scenario I ran into recently that required issuing bearer tokens from an ASP.NET Core authentication server and then validating those tokens in a separate ASP.NET Core web service which may not have access to the authentication server. The previous posts covered how to setup an authentication server for issuing bearer tokens in ASP.NET Core using libraries like <a href=\"https:\/\/github.com\/openiddict\/openiddict-core\">OpenIddict<\/a> or <a href=\"https:\/\/github.com\/IdentityServer\/IdentityServer4\">IdentityServer4<\/a>. In this post, I&#8217;m going to cover the other end of token use on ASP.NET Core &#8211; how to validate JWT tokens and use them to authenticate users.<\/p>\n<article class=\"markdown-body entry-content\">Although this post focuses on .NET Core scenarios, there are also many options for using and validating bearer tokens in the .NET Framework, including the code shown here (which works on both .NET Core and the .NET Framework) and Azure Active Directory packages like <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.Owin.Security.ActiveDirectory\/\">Microsoft.Owin.Security.ActiveDirectory<\/a>, which are covered in detail in <a href=\"https:\/\/azure.microsoft.com\/en-us\/documentation\/articles\/active-directory-authentication-scenarios\/#application-types-and-scenarios\">Azure documentation<\/a>.<\/p>\n<h2>JWT Authentication<\/h2>\n<p>The good news is that authenticating with JWT tokens in ASP.NET Core is straightforward. Middleware exists in the <a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.AspNetCore.Authentication.JwtBearer\/\">Microsoft.AspNetCore.Authentication.JwtBearer<\/a> package that does most of the work for us!<\/p>\n<p>To test this out, let&#8217;s create a new ASP.NET Core web API project. Unlike the web app in my previous post, you don&#8217;t need to add any authentication to this web app when creating the project. No identity or user information is managed by the app directly. Instead, it will get all the user information it needs directly from the JWT token that authenticates a caller.<\/p>\n<p>Once the web API is created, decorate some of its actions (like the default Values controller) with <code>[Authorize]<\/code> attributes. This will cause ASP.NET Core to only allow calls to the attributed APIs if the user is authenticated and logged in.<\/p>\n<p>To actually support JWT bearer authentication as a means of proving identity, all that&#8217;s needed is a call to the <code>UseJwtBearerAuthentication<\/code> extension method (from the <code>Microsoft.AspNetCore.Authentication.JwtBearer<\/code> package) in the app&#8217;s <code>Startup.Configure<\/code> method. Because ASP.NET Core middleware executes in the order it is added in <code>Startup<\/code>, it&#8217;s important that the <code>UseJwtBearerAuthentication<\/code> call comes before <code>UseMvc<\/code>.<\/p>\n<p><code>UseJwtBearerAuthentication<\/code> takes a <code>JwtBearerOptions<\/code> parameter which specifies how to handle incoming tokens. A typical, simple use of <code>UseJwtBearerAuthentication<\/code> might look like this:<\/p>\n<\/article>\n<pre><span class=\"pl-en\">app.UseJwtBearerAuthentication<\/span>(new <span class=\"pl-en\">JwtBearerOptions<\/span>()\n<\/pre>\n<article class=\"markdown-body entry-content\">\n<div class=\"highlight highlight-source-cs\">\n<pre>{\n    Audience = <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>http:\/\/localhost:5001\/<span class=\"pl-pds\">\"<\/span><\/span>, \n    Authority = <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>http:\/\/localhost:5000\/<span class=\"pl-pds\">\"<\/span><\/span>, \n    AutomaticAuthenticate = <span class=\"pl-c1\">true<\/span>\n});<\/pre>\n<\/div>\n<\/article>\n<p>The parameters in such a usage are:<\/p>\n<article class=\"markdown-body entry-content\">\n<ul>\n<li><strong>Audience<\/strong> represents the intended recipient of the incoming token or the resource that the token grants access to. If the value specified in this parameter doesn&#8217;t match the aud parameter in the token, the token will be rejected because it was meant to be used for accessing a different resource. Note that different security token providers have different behaviors regarding what is used as the &#8216;aud&#8217; claim (some use the URI of a resource a user wants to access, others use scope names). Be sure to use an audience that makes sense given the tokens you plan to accept.<\/li>\n<li><strong>Authority<\/strong> is the address of the token-issuing authentication server. The JWT bearer authentication middleware will use this URI to find and retrieve the public key that can be used to validate the token&#8217;s signature. It will also confirm that the iss parameter in the token matches this URI.<\/li>\n<li><strong>AutomaticAuthenticate<\/strong> is a boolean value indicating whether or not the user defined by the token should be automatically logged in or not.<\/li>\n<li><strong>RequireHttpsMetadata<\/strong> is not used in the code snippet above, but is useful for testing purposes. In real-world deployments, JWT bearer tokens should always be passed only over HTTPS.<\/li>\n<\/ul>\n<p>The scenario I worked on with a customer recently, though, was a little different than this typical JWT scenario. The customer wanted to be able to validate tokens without access to the issuing server. Instead, they wanted to use a public key that was already present locally to validate incoming tokens. Fortunately, <code>UseJWTBearerAuthentication<\/code> supports this use-case. It just requires a few adjustments to the parameters passed in.<\/p>\n<ol>\n<li>First, the <code>Authority<\/code> property should not be set on the <code>JwtBearerOptions<\/code>. If it&#8217;s set, the middleware assumes that it can go to that URI to get token validation information. In this scenario, the authority URI may not be available.<\/li>\n<li>A new property (<code>TokenValidationParameters<\/code>) must be set on the <code>JwtBearerOptions<\/code>. This object allows the caller to specify more advanced options for how JWT tokens will be validated.<\/li>\n<\/ol>\n<p>There are a number of interesting properties that can be set in a <code>TokenValidationParameters<\/code> object, but the ones that matter for this scenario are shown in this updated version of the previous code snippet:<\/p>\n<\/article>\n<pre><span class=\"pl-k\">var<\/span> <span class=\"pl-en\">tokenValidationParameters <\/span>= <span class=\"pl-k\">new<\/span> <span class=\"pl-en\">TokenValidationParameters<\/span>\n<\/pre>\n<article class=\"markdown-body entry-content\">\n<div class=\"highlight highlight-source-cs\">\n<pre>{\n    ValidateIssuerSigningKey = <span class=\"pl-c1\">true<\/span>,\n    ValidateIssuer = <span class=\"pl-c1\">true<\/span>,\n    ValidIssuer = <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>http:\/\/localhost:5000\/<span class=\"pl-pds\">\"<\/span><\/span>,\n    IssuerSigningKey = <span class=\"pl-k\">new<\/span> <span class=\"pl-en\">X509SecurityKey<\/span>(<span class=\"pl-k\">new<\/span> <span class=\"pl-en\">X509Certificate2<\/span>(<span class=\"pl-en\">certLocation<\/span>)),\n};\n\n<span class=\"pl-en\">app.UseJwtBearerAuthentication<\/span>(new <span class=\"pl-en\">JwtBearerOptions<\/span>()\n{\n    Audience = <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>http:\/\/localhost:5001\/<span class=\"pl-pds\">\"<\/span><\/span>, \n    AutomaticAuthenticate = <span class=\"pl-c1\">true<\/span>,\n    TokenValidationParameters = tokenValidationParameters\n});\n<\/pre>\n<\/div>\n<\/article>\n<div role=\"main\">\n<div>\n<div id=\"js-repo-pjax-container\">\n<div class=\"container new-discussion-timeline experiment-repo-nav\">\n<div class=\"repository-content\">\n<div class=\"file\">\n<div class=\"readme blob instapaper_body\" id=\"readme\">\n<article class=\"markdown-body entry-content\">The <code>ValidateIssuerSigningKey<\/code> and <code>ValdiateIssuer<\/code> properties indicate that the token&#8217;s signature should be validated and that the key&#8217;s property indicating it&#8217;s issuer must match an expected value. This is an alternate way to make sure the issuer is validated since we&#8217;re not using an <code>Authority<\/code> parameter in our <code>JwtBearerOptions<\/code> (which would have implicitly checked that the JWT&#8217;s issuer matched the authority). Instead, the JWT&#8217;s issuer is matched against custom values that are provided by the <code>ValidIssuer<\/code> or <code>ValidIssuers<\/code> properties of the <code>TokenValidationParameters<\/code> object.The <code>IssuerSigningKey<\/code> is the public key used for validating incoming JWT tokens. By specifying a key here, the token can be validated without any need for the issuing server. What is needed, instead, is the location of the public key. The <code>certLocation<\/code> parameter in the sample above is a string pointing to a .cer certificate file containing the public key corresponding to the private key used by the issuing authentication server. Of course, this certificate could just as easily (and more likely) come from a certificate store instead of a file.<\/p>\n<p>In my previous posts on the topic of issuing authentication tokens with ASP.NET Core, it was necessary to generate a certificate to use for token signing. As part of that process, a .cer file was generated which contained the public (but not private) key of the certificate. That certificate is what needs to be made available to apps (like this sample) that will be consuming the generated tokens.<\/p>\n<p>With <code>UseJwtBearerAuthentication<\/code> called in <code>Startup.Configure<\/code>, our web app should now respect identities sent as JWT bearer tokens in a request&#8217;s Authorization header.<\/p>\n<h2><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/b8e479f5c020ae7a0af7849abe380fca5952ce68\/2016\/09-Sep\/09-ASPNetCore-JWT-Validation\/post.md#authorizing-with-custom-values-from-jwt\" id=\"user-content-authorizing-with-custom-values-from-jwt\" class=\"anchor\"><\/a>Authorizing with Custom Values from JWT<\/h2>\n<p>To make the web app consuming tokens a little more interesting, we can also add some custom authorization that only allows access to APIs depending on specific claims in the JWT bearer token.<\/p>\n<h3><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/b8e479f5c020ae7a0af7849abe380fca5952ce68\/2016\/09-Sep\/09-ASPNetCore-JWT-Validation\/post.md#role-based-authorization\" id=\"user-content-role-based-authorization\" class=\"anchor\"><\/a>Role-based Authorization<\/h3>\n<p>Authorizing based on roles is available out-of-the-box with ASP.NET Identity. As long as the bearer token used for authentication contains a roles element, ASP.NET Core&#8217;s JWT bearer authentication middleware will use that data to populate roles for the user.<\/p>\n<p>So, a roles-based authorization attribute (like <code>[Authorize(Roles = \"Manager,Administrator\")]<\/code> to limit access to managers and admins) can be added to APIs and work immediately.<\/p>\n<h3><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/b8e479f5c020ae7a0af7849abe380fca5952ce68\/2016\/09-Sep\/09-ASPNetCore-JWT-Validation\/post.md#custom-authorization-policies\" id=\"user-content-custom-authorization-policies\" class=\"anchor\"><\/a>Custom Authorization Policies<\/h3>\n<p>Custom authorization in ASP.NET Core is done through custom authorization requirements and handlers. ASP.NET Core documentation has an <a href=\"https:\/\/docs.asp.net\/en\/latest\/security\/authorization\/policies.html\">excellent write-up<\/a> on how to use requirements and handlers to customize authorization. For a more in-depth look at ASP.NET Core authorization, check out this <a href=\"https:\/\/github.com\/blowdart\/AspNetAuthorizationWorkshop\">ASP.NET Authorization Workshop<\/a>.<\/p>\n<p>The important thing to know when working with JWT tokens is that in your <code>AuthorizationHandler<\/code>&#8216;s <code>HandleRequirementAsync<\/code> method, all the elements from the incoming token are available as claims on the <code>AuthorizationHandlerContext.User<\/code>. So, to validate that a custom claim is present from the JWT, you might confirm that the element exists in the JWT with a call to <code>context.User.HasClaim<\/code> and then confirm that the claim is valid by checking its value.<\/p>\n<p>Again, details on custom authorization policies can be found in <a href=\"https:\/\/docs.asp.net\/en\/latest\/security\/authorization\/policies.html\">ASP.NET Core documentation<\/a>, but here&#8217;s a code snippet demonstrating claim validation in an <code>AuthorizationHandler<\/code> that authorizes users based on the (admittedly strange) requirement that their office number claim be lower than some specified value. Notice that it&#8217;s necessary to parse the office number claim&#8217;s value from a string since (as mentioned in my previous post), ASP.NET Identity stores all claim values as strings.<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-c\">\/\/ A handler that can determine whether a MaximumOfficeNumberRequirement is satisfied<\/span>\n<span class=\"pl-k\">internal<\/span> <span class=\"pl-k\">class<\/span> <span class=\"pl-en\">MaximumOfficeNumberAuthorizationHandler<\/span> : <span class=\"pl-en\">AuthorizationHandler<\/span>&lt;<span class=\"pl-en\">MaximumOfficeNumberRequirement<\/span>&gt;\n{\n    <span class=\"pl-k\">protected<\/span> <span class=\"pl-k\">override<\/span> <span class=\"pl-en\">Task<\/span> <span class=\"pl-en\">HandleRequirementAsync<\/span>(<span class=\"pl-en\">AuthorizationHandlerContext<\/span> <span class=\"pl-smi\">context<\/span>, <span class=\"pl-en\">MaximumOfficeNumberRequirement<\/span> <span class=\"pl-smi\">requirement<\/span>)\n    {\n        <span class=\"pl-c\">\/\/ Bail out if the office number claim isn't present<\/span>\n        <span class=\"pl-k\">if<\/span> (!context.User.HasClaim(c =&gt; c.Issuer == <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>http:\/\/localhost:5000\/<span class=\"pl-pds\">\"<\/span><\/span> &amp;&amp; c.Type == <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>office<span class=\"pl-pds\">\"<\/span><\/span>))\n        {\n            <span class=\"pl-k\">return<\/span> Task.CompletedTask;\n        }\n\n        <span class=\"pl-c\">\/\/ Bail out if we can't read an int from the 'office' claim<\/span>\n        <span class=\"pl-k\">int<\/span> <span class=\"pl-en\">officeNumber<\/span>;\n        <span class=\"pl-k\">if<\/span> (!<span class=\"pl-k\">int<\/span>.TryParse(context.User.FindFirst(c =&gt; c.Issuer == <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>http:\/\/localhost:5000\/<span class=\"pl-pds\">\"<\/span><\/span> &amp;&amp; c.Type == <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>office<span class=\"pl-pds\">\"<\/span><\/span>).Value, out officeNumber))\n        {\n            <span class=\"pl-k\">return<\/span> Task.CompletedTask;\n        }\n\n        <span class=\"pl-c\">\/\/ Finally, validate that the office number from the claim is not greater<\/span>\n        <span class=\"pl-c\">\/\/ than the requirement's maximum<\/span>\n        <span class=\"pl-k\">if<\/span> (officeNumber &lt;= requirement.MaximumOfficeNumber)\n        {\n            <span class=\"pl-c\">\/\/ Mark the requirement as satisfied<\/span>\n            context.Succeed(requirement);\n        }\n\n        <span class=\"pl-k\">return<\/span> Task.CompletedTask;\n    }\n}\n\n<span class=\"pl-c\">\/\/ A custom authorization requirement which requires office number to be below a certain value<\/span>\n<span class=\"pl-k\">internal<\/span> <span class=\"pl-k\">class<\/span> <span class=\"pl-en\">MaximumOfficeNumberRequirement<\/span> : <span class=\"pl-en\">IAuthorizationRequirement<\/span>\n{\n    <span class=\"pl-k\">public<\/span> <span class=\"pl-en\">MaximumOfficeNumberRequirement<\/span>(int officeNumber)\n    {\n        MaximumOfficeNumber = officeNumber;\n    }\n\n    <span class=\"pl-k\">public <\/span><span class=\"pl-k\">int<\/span> <span class=\"pl-en\">MaximumOfficeNumber<\/span> { <span class=\"pl-k\">get<\/span>; <span class=\"pl-en\">private<\/span> <span class=\"pl-en\">set<\/span>; }\n}<\/pre>\n<\/div>\n<p>This authorization requirement can be registered in <code>Startup.ConfigureServices<\/code> with a call to <code>AddAuthorization<\/code> to add a requirement that an office number not exceed a particular value (200, in this example), and by adding the handler with a call to <code>AddSingleton<\/code>:<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-c\">\/\/ Add custom authorization handlers<\/span>\n<span class=\"pl-en\">services.AddAuthorization<\/span>(options =&gt;\n{\n    options.AddPolicy(<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>OfficeNumberUnder200<span class=\"pl-pds\">\"<\/span><\/span>, policy =&gt; policy.Requirements.Add(<span class=\"pl-k\">new<\/span> <span class=\"pl-en\">MaximumOfficeNumberRequirement<\/span>(200)));\n});\n\n<span class=\"pl-en\">services.AddSingleton<\/span>&lt;<span class=\"pl-en\">IAuthorizationHandler<\/span>, MaximumOfficeNumberAuthorizationHandler&gt;();<\/pre>\n<\/div>\n<p>Finally, this custom authorization policy can protect APIs by decorating actions (or controllers) with appropriate <code>Authorize<\/code> attributes with their policy argument set to the name used when defining the custom authorization requirement in startup.cs:<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre>[Authorize(Policy = <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>OfficeNumberUnder200<span class=\"pl-pds\">\"<\/span><\/span>)]<\/pre>\n<\/div>\n<h2><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/b8e479f5c020ae7a0af7849abe380fca5952ce68\/2016\/09-Sep\/09-ASPNetCore-JWT-Validation\/post.md#testing-it-all-together\" id=\"user-content-testing-it-all-together\" class=\"anchor\"><\/a>Testing it All Together<\/h2>\n<p>Now that we have a simple web API that can authenticate and authorize based on tokens, we can try out JWT bearer token authentication in ASP.NET Core end-to-end.<\/p>\n<p>The first step is to login with the authentication server we created in my <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/bearer-token-authentication-in-asp-net-core\/\">previous post<\/a>. Once that&#8217;s done, copy the token out of the server&#8217;s response.<\/p>\n<p>Now, shut down the authentication server just to be sure that our web API can authenticate without it being online.<\/p>\n<p>Then, launch our test web API and using a tool like <a href=\"https:\/\/www.getpostman.com\/\">Postman<\/a> or <a href=\"http:\/\/www.telerik.com\/fiddler\">Fiddler<\/a>, create a request to the web API. Initially, the request should fail with a 401 error because the APIs are protected with an <code>[Authorize]<\/code> attribute. To make the calls work, add an Authorization header with the value &#8220;bearer X&#8221; where &#8220;X&#8221; is the JWT bearer token returned from the authentication server. As long as the token hasn&#8217;t expired, its audience and authority match the expected values for this web API, and the user indicated by the token satisfies any custom authorization policies on the action called, a valid response should be served from our web API.<\/p>\n<p>Here are a sample request and response from testing out the sample created in this post:<\/p>\n<p>Request:<\/p>\n<pre><code>GET \/api\/values\/1 HTTP\/1.1\nHost: localhost:5001\nAuthorization: bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IkU1N0RBRTRBMzU5NDhGODhBQTg2NThFQkExMUZFOUIxMkI5Qzk5NjIiLCJ0eXAiOiJKV1QifQ.eyJ1bmlxdWVfbmFtZSI6IkJvYkBDb250b3NvLmNvbSIsIkFzcE5ldC5JZGVudGl0eS5TZWN1cml0eVN0YW1wIjoiM2M4OWIzZjYtNzE5Ni00NWM2LWE4ZWYtZjlmMzQyN2QxMGYyIiwib2ZmaWNlIjoiMjAiLCJqdGkiOiI0NTZjMzc4Ny00MDQwLTQ2NTMtODYxZi02MWJiM2FkZTdlOTUiLCJ1c2FnZSI6ImFjY2Vzc190b2tlbiIsInNjb3BlIjpbImVtYWlsIiwicHJvZmlsZSIsInJvbGVzIl0sInN1YiI6IjExODBhZjQ4LWU1M2ItNGFhNC1hZmZlLWNmZTZkMjU4YWU2MiIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMS8iLCJuYmYiOjE0Nzc1MDkyNTQsImV4cCI6MTQ3NzUxMTA1NCwiaWF0IjoxNDc3NTA5MjU0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjUwMDAvIn0.Lmx6A3jhwoyZ8KAIkjriwHIOAYkgXYOf1zBbPbFeIiU2b-2-nxlwAf_yMFx3b1Ouh0Bp7UaPXsPZ9g2S0JLkKD4ukUa1qW6CzIDJHEfe4qwhQSR7xQn5luxSEfLyT_LENVCvOGfdw0VmsUO6XT4wjhBNEArFKMNiqOzBnSnlvX_1VMx1Tdm4AV5iHM9YzmLDMT65_fBeiekxQNPKcXkv3z5tchcu_nVEr1srAk6HpRDLmkbYc6h4S4zo4aPcLeljFrCLpZP-IEikXkKIGD1oohvp2dpXyS_WFby-dl8YQUHTBFHqRHik2wbqTA_gabIeQy-Kon9aheVxyf8x6h2_FA\n<\/code><\/pre>\n<p>Response:<\/p>\n<pre><code>HTTP\/1.1 200 OK\nDate: Thu, 15 Sep 2016 21:53:10 GMT\nTransfer-Encoding: chunked\nContent-Type: text\/plain; charset=utf-8\nServer: Kestrel\n\nvalue\n<\/code><\/pre>\n<h2><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/b8e479f5c020ae7a0af7849abe380fca5952ce68\/2016\/09-Sep\/09-ASPNetCore-JWT-Validation\/post.md#conclusion\" id=\"user-content-conclusion\" class=\"anchor\"><\/a>Conclusion<\/h2>\n<p>As shown here, authenticating using JWT bearer tokens is straightforward in ASP.NET Core, even in less common scenarios (such as the authentication server not being available). What&#8217;s more, ASP.NET Core&#8217;s flexible authorization policy makes it easy to have fine-grained control over access to APIs. Combined with my <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/bearer-token-authentication-in-asp-net-core\/\">previous<\/a> <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/asp-net-core-authentication-with-identityserver4\/\">posts<\/a> on issuing bearer tokens, you should have a good overview of how to use this technology for authentication in ASP.NET Core web apps.<\/p>\n<h2><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/b8e479f5c020ae7a0af7849abe380fca5952ce68\/2016\/09-Sep\/09-ASPNetCore-JWT-Validation\/post.md#resources\" id=\"user-content-resources\" class=\"anchor\"><\/a>Resources<\/h2>\n<ul>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/asp-net-core-authentication-with-identityserver4\/\">Issuing Bearer Tokens in ASP.NET Core (with IdentityServer4)<\/a><\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/bearer-token-authentication-in-asp-net-core\/\">Issuing Bearer Tokens in ASP.NET Core (with OpenIddict)<\/a><\/li>\n<li><a href=\"https:\/\/www.nuget.org\/packages\/Microsoft.AspNetCore.Authentication.JwtBearer\/\">Microsoft.AspNetCore.Authentication.JwtBearer<\/a><\/li>\n<li><a href=\"https:\/\/docs.asp.net\/en\/latest\/security\/authorization\/policies.html\">ASP.NET Core Authorization<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/openiddict\/openiddict-core\">OpenIddict<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/IdentityServer\/IdentityServer4\">IdentityServer4<\/a><\/li>\n<\/ul>\n<\/article>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>This post was written and submitted by Michael Rousos In several previous posts, I discussed a customer scenario I ran into recently that required issuing bearer tokens from an ASP.NET Core authentication server and then validating those tokens in a separate ASP.NET Core web service which may not have access to the authentication server. The [&hellip;]<\/p>\n","protected":false},"author":405,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197,7509],"tags":[7467,7502,7438,7529],"class_list":["post-36890","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","category-aspnetcore","tag-asp-net-identity","tag-aspnet","tag-identity","tag-jwt"],"acf":[],"blog_post_summary":"<p>This post was written and submitted by Michael Rousos In several previous posts, I discussed a customer scenario I ran into recently that required issuing bearer tokens from an ASP.NET Core authentication server and then validating those tokens in a separate ASP.NET Core web service which may not have access to the authentication server. The [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/36890","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/405"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=36890"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/36890\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=36890"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=36890"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=36890"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}