{"id":36877,"date":"2017-01-23T11:36:46","date_gmt":"2017-01-23T19:36:46","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/?p=8945"},"modified":"2017-01-23T11:36:46","modified_gmt":"2017-01-23T19:36:46","slug":"asp-net-core-authentication-with-identityserver4","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/asp-net-core-authentication-with-identityserver4\/","title":{"rendered":"ASP.NET Core Authentication with IdentityServer4"},"content":{"rendered":"<p><em>This is a guest post by Mike Rousos<\/em><\/p>\n<p>In my post on <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/bearer-token-authentication-in-asp-net-core\/\">bearer token authentication in ASP.NET Core<\/a>, I mentioned that there are a couple good third-party libraries for issuing JWT bearer tokens in .NET Core. In that post, I used <a href=\"https:\/\/github.com\/openiddict\/openiddict-core\">OpenIddict<\/a> to demonstrate how end-to-end token issuance can work in an ASP.NET Core application.<\/p>\n<p>Since that post was published, I&#8217;ve had some requests to also show how a similar result can be achieved with the other third-party authentication library available for .NET Core: <a href=\"https:\/\/github.com\/IdentityServer\/IdentityServer4\">IdentityServer4<\/a>. So, in this post, I&#8217;m revisiting the question of how to issue tokens in ASP.NET Core apps and, this time, I&#8217;ll use IdentityServer4 in the sample code.<\/p>\n<p>As before, I think it&#8217;s worth mentioning that there are a lot of good options available for authentication in ASP.NET Core. <a href=\"https:\/\/azure.microsoft.com\/en-us\/documentation\/articles\/active-directory-authentication-scenarios\/\">Azure Active Directory Authentication<\/a> is an easy way to get authentication as a service. If you would prefer to own the authentication process yourself, I&#8217;ve used and had success with both <a href=\"https:\/\/github.com\/openiddict\/openiddict-core\">OpenIddict<\/a> and <a href=\"https:\/\/github.com\/IdentityServer\/IdentityServer4\">IdentityServer4<\/a>.<\/p>\n<p>Bear in mind that both IdentityServer4 and OpenIddict are third-party libraries, so they are maintained and supported by community members &#8211; not by Microsoft.<\/p>\n<h2><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/8ca299572fed7d8b63ccfd311e48ddec9c051e2a\/2016\/11-Nov\/IdentityServer4Authentication\/post.md#the-scenario\" id=\"user-content-the-scenario\" class=\"anchor\"><\/a>The Scenario<\/h2>\n<p>As you may remember from <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/bearer-token-authentication-in-asp-net-core\/\">last time<\/a>, the goal of this scenario is to setup an authentication server which will allow users to sign in (via <a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/security\/authentication\/identity\">ASP.NET Core Identity<\/a>) and provides a JWT bearer token that can be used to access protected resources from a SPA or mobile app.<\/p>\n<p>In this scenario, all the components are owned by the same developer and trusted, so an <a href=\"https:\/\/tools.ietf.org\/html\/rfc6749#section-1.3.3\">OAuth 2.0 resource owner password flow<\/a> is acceptable (and is used here because it&#8217;s simple to use in a demonstration). Be aware that this model exposes user credentials and access tokens (both of which are sensitive and could be used to impersonate a user) to the client. In more complex scenarios (especially if clients shouldn&#8217;t be trusted with user credentials or access tokens), OpenID Connect flows such as <a href=\"https:\/\/openid.net\/specs\/openid-connect-core-1_0.html#ImplicitFlowAuth\">implicit<\/a> or <a href=\"https:\/\/openid.net\/specs\/openid-connect-core-1_0.html#HybridFlowAuth\">hybrid<\/a> flows are preferable. IdentityServer4 and OpenIddict both support those scenarios. One of IdentityServer4&#8217;s maintainers (Dominick Baier) has a good blog post on <a href=\"https:\/\/leastprivilege.com\/2016\/01\/17\/which-openid-connectoauth-2-o-flow-is-the-right-one\/\">when different flows should be used<\/a> and IdentityServer4 quickstarts include <a href=\"http:\/\/docs.identityserver.io\/en\/release\/quickstarts\/3_interactive_login.html\">a sample of using the implicit flow<\/a>.<\/p>\n<p>As we walk through this scenario, I&#8217;d also encourage you to check out <a href=\"https:\/\/identityserver4.readthedocs.io\/en\/release\/\">IdentityServer4 documentation<\/a>, as it gives more detail than I can fit into this (relatively) short post.<\/p>\n<h2><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/8ca299572fed7d8b63ccfd311e48ddec9c051e2a\/2016\/11-Nov\/IdentityServer4Authentication\/post.md#getting-started\" id=\"user-content-getting-started\" class=\"anchor\"><\/a>Getting Started<\/h2>\n<p>As before, my first step is to create a new ASP.NET Core web app from the &#8216;web application&#8217; template, making sure to select &#8220;Individual User Accounts&#8221; authentication. This will create an app that uses ASP.NET Core Identity to manage users. An Entity Framework Core context will be auto-generated to manage identity storage. The connection string in appsettings.json points to the database where this data will be stored.<\/p>\n<p>Because it&#8217;s interesting to understand how IdentityServer4 includes role and claim information in its tokens, I also seed the database with a couple roles and add a custom property (<code>OfficeNumber<\/code>) to my <code>ApplicationUser<\/code> type which can be used as a custom claim later.<\/p>\n<p>These initial steps of setting up an ASP.NET Core application with identity are identical to what I did in my previously with OpenIddict, so I won&#8217;t go into great detail here. If you would like this setup explained further, please see <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/bearer-token-authentication-in-asp-net-core\/\">my previous post<\/a>.<\/p>\n<h2><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/8ca299572fed7d8b63ccfd311e48ddec9c051e2a\/2016\/11-Nov\/IdentityServer4Authentication\/post.md#adding-identityserver4\" id=\"user-content-adding-identityserver4\" class=\"anchor\"><\/a>Adding IdentityServer4<\/h2>\n<p>Now that our base ASP.NET Core application is up and running (with Identity services), we&#8217;re ready to add IdentityServer4 support.<\/p>\n<ol>\n<li>Add <code>\"IdentityServer4\": \"1.0.2\"<\/code> as a dependency in the app&#8217;s project.json file.<\/li>\n<li>Add IdentityServer4 to the HTTP request processing pipeline with a call to <code>app.UseIdentityServer()<\/code> in the app&#8217;s <code>Startup.Configure<\/code> method.\n<ol>\n<li>It&#8217;s important that the <code>UseIdentityServer()<\/code> call come after registering ASP.NET Core Identity (<code>app.UseIdentity()<\/code>).<\/li>\n<\/ol>\n<\/li>\n<li>Register IdentityServer4 services in the <code>Startup.ConfigureServices<\/code> method by calling <code>services.AddIdentityServer()<\/code>.<\/li>\n<\/ol>\n<p>We&#8217;ll also want to specify how IdentityServer4 should sign tokens. During development, an auto-generated certificate can be used to sign tokens by calling <code>AddTemporarySigningCredential<\/code> after the call to <code>AddIdentityServer<\/code> in <code>Startup.ConfigureServices<\/code>. Eventually, we&#8217;ll want to use a real cert for signing, though. We can sign with an x509 certificate by calling <code>AddSigningCredential<\/code>:<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre>services.AddIdentityServer()\n  <span class=\"pl-c\">\/\/ .AddTemporarySigningCredential() \/\/ Can be used for testing until a real cert is available<\/span>\n  .AddSigningCredential(<span class=\"pl-k\">new<\/span> X509Certificate2(Path.Combine(<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>.<span class=\"pl-pds\">\"<\/span><\/span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>certs<span class=\"pl-pds\">\"<\/span><\/span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>IdentityServer4Auth.pfx<span class=\"pl-pds\">\"<\/span><\/span>)))<\/pre>\n<\/div>\n<p>Note that you should not load the certificate from the app path in production; there are other <code>AddSigningCredential<\/code> overloads that can be used to load the certificate from the machine&#8217;s certificate store.<\/p>\n<p>As mentioned in <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/bearer-token-authentication-in-asp-net-core\/\">my previous post<\/a>, it&#8217;s possible to create self-signed certificates for testing this out with the <code>makecert<\/code> and <code>pvk2pfx<\/code> command line tools (which should be on the path in a Visual Studio Developer Command prompt).<\/p>\n<ul>\n<li><code>makecert -n \"CN=AuthSample\" -a sha256 -sv IdentityServer4Auth.pvk -r IdentityServer4Auth.cer<\/code>\n<ul>\n<li>This will create a new self-signed test certificate with its public key in IdentityServer4Auth.cer and it\u2019s private key in IdentityServer4Auth.pvk.<\/li>\n<\/ul>\n<\/li>\n<li><code>pvk2pfx -pvk IdentityServer4Auth.pvk -spc IdentityServer4Auth.cer -pfx IdentityServer4Auth.pfx<\/code>\n<ul>\n<li>This will combine the pvk and cer files into a single pfx file containing both the public and private keys for the certificate. Our app will use the private key from the pfx to sign tokens. <strong>Make sure to protect this file<\/strong>. The .cer file can be shared with other services for the purpose of signature validation.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>Token issuance from IdentityServer4 won&#8217;t yet be functional, but this is the skeleton of how IdentityServer4 is connected to our ASP.NET Core app.<\/p>\n<h3><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/8ca299572fed7d8b63ccfd311e48ddec9c051e2a\/2016\/11-Nov\/IdentityServer4Authentication\/post.md#configuring-identityserver4\" id=\"user-content-configuring-identityserver4\" class=\"anchor\"><\/a>Configuring IdentityServer4<\/h3>\n<p>Before IdentityServer4 will function, it must be configured. This configuration (which is done in <code>ConfigureServices<\/code>) allows us to specify how users are managed, what clients will be connecting, and what resources\/scopes IdentityServer4 is protecting.<\/p>\n<h4><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/8ca299572fed7d8b63ccfd311e48ddec9c051e2a\/2016\/11-Nov\/IdentityServer4Authentication\/post.md#specify-protected-resources\" id=\"user-content-specify-protected-resources\" class=\"anchor\"><\/a>Specify protected resources<\/h4>\n<p>IdentityServer4 must know what scopes can be requested by users. These are defined as <a href=\"http:\/\/docs.identityserver.io\/en\/release\/configuration\/resources.html\">resources<\/a>. IdentityServer4 has two kinds of resources:<\/p>\n<ul>\n<li>API resources represent some protected data or functionality which a user might gain access to with an access token. An example of an API resource would be a web API (or set of APIs) that require authorization to call.<\/li>\n<li>Identity resources represent information (claims) which are given to a client to identify a user. This could include their name, email address, or other claims. Identity information is returned in an ID token by OpenID Connect flows. In our simple sample, we&#8217;re using an OAuth 2.0 flow (the password resource flow), so we won&#8217;t be using identity resources.<\/li>\n<\/ul>\n<p>The simplest way to specify resources is to use the <code>AddInMemoryApiResources<\/code> and <code>AddInMemoryIdentityResources<\/code> extension methods to pass a list of resources. In our sample, we do that by updating our <code>services.AddIdentityServer()<\/code> call to read as follows:<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre>services.AddIdentityServer()\n  <span class=\"pl-c\">\/\/ .AddTemporarySigningCredential() \/\/ Can be used for testing until a real cert is available<\/span>\n  .AddSigningCredential(<span class=\"pl-k\">new<\/span> X509Certificate2(Path.Combine(<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>.<span class=\"pl-pds\">\"<\/span><\/span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>certs<span class=\"pl-pds\">\"<\/span><\/span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>IdentityServer4Auth.pfx<span class=\"pl-pds\">\"<\/span><\/span>)))\n  .AddInMemoryApiResources(MyApiResourceProvider.GetAllResources()); <span class=\"pl-c\">\/\/ &lt;- THE NEW LINE <\/span><\/pre>\n<\/div>\n<p>The <code>MyApiResourceProvider.GetAllResources()<\/code> method just returns an <code>IEnumerable<\/code> of ApiResources.<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-k\">return<\/span> <span class=\"pl-k\">new<\/span>[]\n{\n    <span class=\"pl-c\">\/\/ Add a resource for some set of APIs that we may be protecting<\/span>\n    <span class=\"pl-c\">\/\/ Note that the constructor will automatically create an allowed scope with<\/span>\n    <span class=\"pl-c\">\/\/ name and claims equal to the resource's name and claims. If the resource<\/span>\n    <span class=\"pl-c\">\/\/ has different scopes\/levels of access, the scopes property can be set to<\/span>\n    <span class=\"pl-c\">\/\/ list specific scopes included in this resource, instead.<\/span>\n    <span class=\"pl-k\">new<\/span> ApiResource(\n        <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>myAPIs<span class=\"pl-pds\">\"<\/span><\/span>,                                       <span class=\"pl-c\">\/\/ Api resource name<\/span>\n        <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>My API Set #1<span class=\"pl-pds\">\"<\/span><\/span>,                                <span class=\"pl-c\">\/\/ Display name<\/span>\n        <span class=\"pl-k\">new<\/span>[] { JwtClaimTypes.Name, JwtClaimTypes.Role, <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>office<span class=\"pl-pds\">\"<\/span><\/span> }) <span class=\"pl-c\">\/\/ Claims to be included in access token<\/span>\n};<\/pre>\n<\/div>\n<p>If we also needed identity resources, they could be added with a similar call to <code>AddInMemoryIdentityResources<\/code>.<\/p>\n<p>If more flexibility is needed in specifying resources, this can be accomplished by registering a custom <code>IResourceStore<\/code> with ASP.NET Core&#8217;s dependency injection. An <code>IResourceStore<\/code> allows for finer control over how resources are created, allowing a developer to read resource information from an external data source, for example. An <code>IResourceStore<\/code> which works with EntityFramework.Core (<code>IdentityServer4.EntityFramework.Stores.ResourceStore<\/code>) is available in the IdentityServer4.EntityFramework package.<\/p>\n<h4><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/8ca299572fed7d8b63ccfd311e48ddec9c051e2a\/2016\/11-Nov\/IdentityServer4Authentication\/post.md#specify-clients\" id=\"user-content-specify-clients\" class=\"anchor\"><\/a>Specify Clients<\/h4>\n<p>In addition to specifying protected resources, IdentityServer4 must be configured with a list of clients that will be requesting tokens. Like configuring resources, client configuration can be done with an extension method: <code>AddInMemoryClients<\/code>. Also like configuring resources, it&#8217;s possible to have more control over the client configuration by implementing our own <code>IClientStore<\/code>. In this sample, a simple call to <code>AddInMemoryClients<\/code> would suffice to configure clients, but I opted to use an <code>IClientStore<\/code> to demonstrate how easy it is to extend IdentityServer4 in this way. This would be a useful approach if, for example, client information was read from an external database. And, as with <code>IResourceStore<\/code>, you can find a ready-made <code>IClientStore<\/code> implementation for working with EntityFramework.Core in the IdentityServer4.EntityFramework package.<\/p>\n<p>The <code>IClientStore<\/code> interface only has a single method (<code>FindClientByIdAsync<\/code>) which is used to look up clients given a client ID. The returned object (of type <code>Client<\/code>) contains, <a href=\"http:\/\/docs.identityserver.io\/en\/release\/reference\/client.html\">among other things<\/a>, information about the client&#8217;s name, allowed grant types and scopes, token lifetimes, and the client secret (if it has one).<\/p>\n<p>In my sample, I added the following <code>IClientStore<\/code> implementation which will yield a single client configured to use the resource owner password flow and our custom &#8216;myAPIs&#8217; resource:<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-k\">public<\/span> <span class=\"pl-k\">class<\/span> <span class=\"pl-en\">CustomClientStore<\/span> : <span class=\"pl-k\">IClientStore<\/span>\n{\n    <span class=\"pl-k\">public<\/span> <span class=\"pl-k\">static<\/span> IEnumerable&lt;Client&gt; <span class=\"pl-en\">AllClients<\/span> { <span class=\"pl-k\">get<\/span>; } = <span class=\"pl-k\">new<\/span>[]\n    {\n        <span class=\"pl-k\">new<\/span> Client\n        {\n            ClientId = <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>myClient<span class=\"pl-pds\">\"<\/span><\/span>,\n            ClientName = <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>My Custom Client<span class=\"pl-pds\">\"<\/span><\/span>,\n            AccessTokenLifetime = <span class=\"pl-c1\">60<\/span> * <span class=\"pl-c1\">60<\/span> * <span class=\"pl-c1\">24<\/span>,\n            AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,\n            RequireClientSecret = <span class=\"pl-c1\">false<\/span>,\n            AllowedScopes = \n            {\n                <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>myAPIs<span class=\"pl-pds\">\"<\/span><\/span>\n            }\n        }\n    };\n\n    <span class=\"pl-k\">public<\/span> Task&lt;Client&gt; <span class=\"pl-en\">FindClientByIdAsync<\/span>(<span class=\"pl-k\">string<\/span> <span class=\"pl-smi\">clientId<\/span>)\n    {\n        <span class=\"pl-k\">return<\/span> Task.FromResult(AllClients.FirstOrDefault(c =&gt; c.ClientId == clientId));\n    }\n}<\/pre>\n<\/div>\n<p>I then registered the store with ASP.NET Core dependency injection (<code>services.AddSingleton&lt;IClientStore, CustomClientStore&gt;()<\/code> in <code>Startup.ConfigureServices<\/code>).<\/p>\n<h4><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/8ca299572fed7d8b63ccfd311e48ddec9c051e2a\/2016\/11-Nov\/IdentityServer4Authentication\/post.md#connecting-identityserver4-and-aspnet-core-identity\" id=\"user-content-connecting-identityserver4-and-aspnet-core-identity\" class=\"anchor\"><\/a>Connecting IdentityServer4 and ASP.NET Core Identity<\/h4>\n<p>To use ASP.NET Core Identity, we&#8217;ll be using the <code>IdentityServer4.AspNetIdentity<\/code> package. After adding this package to our project.json, the previous <code>app.AddIdentityServer()<\/code> call in <code>Startup.ConfigureServices<\/code> can be updated to look like this:<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre>services.AddIdentityServer()\n  <span class=\"pl-c\">\/\/ .AddTemporarySigningCredential() \/\/ Can be used for testing until a real cert is available<\/span>\n  .AddSigningCredential(<span class=\"pl-k\">new<\/span> X509Certificate2(Path.Combine(<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>.<span class=\"pl-pds\">\"<\/span><\/span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>certs<span class=\"pl-pds\">\"<\/span><\/span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>IdentityServer4Auth.pfx<span class=\"pl-pds\">\"<\/span><\/span>)))\n  .AddInMemoryApiResources(MyApiResourceProvider.GetAllResources())\n  .AddAspNetIdentity&lt;ApplicationUser&gt;(); <span class=\"pl-c\">\/\/ &lt;- THE NEW LINE<\/span><\/pre>\n<\/div>\n<p>This will cause IdentityServer4 to get user profile information from our ASP.NET Core Identity context, and will automatically setup the necessary <code>IResourceOwnerPasswordValidator<\/code> for validating credentials. It will also configure IdentityServer4 to correctly extract JWT subject, user name, and role claims from ASP.NET Core Identity entities.<\/p>\n<h2><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/8ca299572fed7d8b63ccfd311e48ddec9c051e2a\/2016\/11-Nov\/IdentityServer4Authentication\/post.md#putting-it-together\" id=\"user-content-putting-it-together\" class=\"anchor\"><\/a>Putting it Together<\/h2>\n<p>With configuration done, IdentityServer4 should now work to serve tokens for the client we defined. The registering of IdentityServer4 services in <code>Startup.ConfigureServices<\/code> ends up looking like this all together:<\/p>\n<div class=\"highlight highlight-source-cs\">\n<pre><span class=\"pl-c\">\/\/ Add IdentityServer services<\/span>\nservices.AddSingleton&lt;IClientStore, CustomClientStore&gt;();\n\nservices.AddIdentityServer()\n    <span class=\"pl-c\">\/\/ .AddTemporarySigningCredential() \/\/ Can be used for testing until a real cert is available<\/span>\n    .AddSigningCredential(<span class=\"pl-k\">new<\/span> X509Certificate2(Path.Combine(<span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>.<span class=\"pl-pds\">\"<\/span><\/span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>certs<span class=\"pl-pds\">\"<\/span><\/span>, <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>IdentityServer4Auth.pfx<span class=\"pl-pds\">\"<\/span><\/span>)))\n    .AddInMemoryApiResources(MyApiResourceProvider.GetAllResources())\n    .AddAspNetIdentity&lt;ApplicationUser&gt;();<\/pre>\n<\/div>\n<p>As before, a tool like <a href=\"https:\/\/www.getpostman.com\/\">Postman<\/a> can be used to test out the app. The scope we specify in the request should be our custom API resource scope (&#8216;myAPIs&#8217;).<\/p>\n<p>Here is a sample token request:<\/p>\n<pre><code>POST \/connect\/token HTTP\/1.1\nHost: localhost:5000\nCache-Control: no-cache\nPostman-Token: 958df72b-663c-5638-052a-aed41ba0dbd1\nContent-Type: application\/x-www-form-urlencoded\n\ngrant_type=password&amp;username=Mike%40Contoso.com&amp;password=MikesPassword1!&amp;client_id=myClient&amp;scope=myAPIs\n<\/code><\/pre>\n<p>The returned access token in our app&#8217;s response (which can be decoded using <a href=\"http:\/\/jwt.calebb.net\/\">online utilities<\/a>) looks like this:<\/p>\n<div class=\"highlight highlight-source-json\">\n<pre>{\n <span class=\"pl-ii\">alg<\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>RS256<span class=\"pl-pds\">\"<\/span><\/span>,\n <span class=\"pl-ii\">kid<\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>671A47CE65E10A98BB86EDCD5F9684E9D048FAE9<span class=\"pl-pds\">\"<\/span><\/span>,\n <span class=\"pl-ii\">typ<\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>JWT<span class=\"pl-pds\">\"<\/span><\/span>,\n <span class=\"pl-ii\">x5t<\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>ZxpHzmXhCpi7hu3NX5aE6dBI-uk<span class=\"pl-pds\">\"<\/span><\/span>\n}.\n{\n <span class=\"pl-ii\">nbf<\/span>: <span class=\"pl-c1\">1481054282<\/span>,\n <span class=\"pl-ii\">exp<\/span>: <span class=\"pl-c1\">1481140682<\/span>,\n <span class=\"pl-ii\">iss<\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>http:\/\/localhost:5000<span class=\"pl-pds\">\"<\/span><\/span>,\n <span class=\"pl-ii\">aud<\/span>: [\n  <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>http:\/\/localhost:5000\/resources<span class=\"pl-pds\">\"<\/span><\/span>,\n  <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>myAPIs<span class=\"pl-pds\">\"<\/span><\/span>\n ],\n <span class=\"pl-ii\">client_id<\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>myClient<span class=\"pl-pds\">\"<\/span><\/span>,\n <span class=\"pl-ii\">sub<\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>f6435683-f81c-4bd4-9c14-c7c09b236f4e<span class=\"pl-pds\">\"<\/span><\/span>,\n <span class=\"pl-ii\">auth_time<\/span>: <span class=\"pl-c1\">1481054281<\/span>,\n <span class=\"pl-ii\">idp<\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>local<span class=\"pl-pds\">\"<\/span><\/span>,\n <span class=\"pl-ii\">name<\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>Mike@Contoso.com<span class=\"pl-pds\">\"<\/span><\/span>,\n <span class=\"pl-ii\">role<\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>Administrator<span class=\"pl-pds\">\"<\/span><\/span>,\n <span class=\"pl-ii\">office<\/span>: <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>300<span class=\"pl-pds\">\"<\/span><\/span>,\n <span class=\"pl-ii\">scope<\/span>: [\n  <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>myAPIs<span class=\"pl-pds\">\"<\/span><\/span>\n ],\n <span class=\"pl-ii\">amr<\/span>: [\n  <span class=\"pl-s\"><span class=\"pl-pds\">\"<\/span>pwd<span class=\"pl-pds\">\"<\/span><\/span>\n ]\n}.\n[<span class=\"pl-ii\">signature<\/span>]<\/pre>\n<\/div>\n<p>You can read more details about how to understand the JWT fields in <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/bearer-token-authentication-in-asp-net-core\/\">my previous post<\/a>. Note that there are a few small differences between the tokens generated with OpenIddict and those generated with IdentityServer4.<\/p>\n<ul>\n<li>IdentityServer4 includes the amr (authentication method references) field which lists authentication methods used.<\/li>\n<li>IdentityServer4 always requires a client be specified in token requests, so it will always have a client_id in the response whereas OpenIddict treats the client as optional for some OAuth 2.0 flows.<\/li>\n<li>IdentityServer4 does not include the optional <a href=\"https:\/\/tools.ietf.org\/html\/rfc7519#section-4.1.6\">iat<\/a> field indicating when the access token was issued, but does include the auth_time field (<a href=\"https:\/\/openid.net\/specs\/openid-connect-core-1_0.html#IDToken\">defined by OpenID Connect<\/a> as an optional field for OAuth 2.0 flows) which will have the same value.<\/li>\n<\/ul>\n<p>In both cases, it&#8217;s possible to customize claims that are returned for given resources\/scopes, so developers can make sure claims important to their scenarios are included.<\/p>\n<h2><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/8ca299572fed7d8b63ccfd311e48ddec9c051e2a\/2016\/11-Nov\/IdentityServer4Authentication\/post.md#conclusion\" id=\"user-content-conclusion\" class=\"anchor\"><\/a>Conclusion<\/h2>\n<p>Hopefully this walkthrough of a simple IdentityServer4 scenario is useful for understanding how that package can be used to enable authentication token issuance in ASP.NET Core. Please be sure to check out the <a href=\"http:\/\/docs.identityserver.io\/en\/release\/\">IdentityServer4 docs<\/a> for more complete documentation. As IdentityServer4 is not a Microsoft-owned library, support questions or issue reports should be directed to <a href=\"https:\/\/identityserver.io\/\">IdentityServer<\/a> or <a href=\"https:\/\/github.com\/IdentityServer\/IdentityServer4\">the IdentityServer4 GitHub repository<\/a>.<\/p>\n<p>The scenario implemented here is no different from what was covered <a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/bearer-token-authentication-in-asp-net-core\/\">previously<\/a>, but serves as an example of how different community-driven libraries can work to solve a given problem. One of the most exciting aspects of .NET Core is the tremendous community involvement we&#8217;ve seen in producing high-quality libraries to extend what can be done with .NET Core and ASP.NET Core. I think token-based authentication is a great example of that.<\/p>\n<p>I have checked in <a href=\"https:\/\/github.com\/mjrousos\/IdentityServer4Authentication\">sample code<\/a> that shows the end product of the walk-through in this blog. Reviewing that repository may be helpful in clarifying any remaining questions.<\/p>\n<h2><a href=\"https:\/\/github.com\/mjrousos\/dotnet-blog\/blob\/8ca299572fed7d8b63ccfd311e48ddec9c051e2a\/2016\/11-Nov\/IdentityServer4Authentication\/post.md#resources\" id=\"user-content-resources\" class=\"anchor\"><\/a>Resources<\/h2>\n<ul>\n<li><a href=\"https:\/\/github.com\/IdentityServer\/IdentityServer4\">IdentityServer4 project site<\/a><\/li>\n<li><a href=\"https:\/\/www.nuget.org\/packages\/IdentityServer4\/1.0.2\">IdentityServer4 library (NuGet)<\/a><\/li>\n<li><a href=\"https:\/\/identityserver4.readthedocs.io\/en\/release\/\">IdentityServer4 documentation<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/security\/authentication\/identity\">ASP.NET Core Identity<\/a><\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/aspnet\/bearer-token-authentication-in-asp-net-core\/\">Previous blog post on ASP.NET Core token-based authentication<\/a><\/li>\n<li><a href=\"https:\/\/openid.net\/specs\/openid-connect-core-1_0.html\">OpenID Connect spec<\/a><\/li>\n<li><a href=\"https:\/\/tools.ietf.org\/html\/rfc6749\">OAuth 2.0 spec<\/a><\/li>\n<li><a href=\"https:\/\/leastprivilege.com\/2016\/01\/17\/which-openid-connectoauth-2-o-flow-is-the-right-one\/\">Choosing the right connection flow<\/a><\/li>\n<li><a href=\"https:\/\/tools.ietf.org\/html\/rfc7519\">JSON Web Token (JWT) spec)<\/a><\/li>\n<li><a href=\"https:\/\/www.getpostman.com\/\">Postman<\/a><\/li>\n<li><a href=\"http:\/\/jwt.calebb.net\/\">Online JWT decoder<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/mjrousos\/IdentityServer4Authentication\">Sample code from this article<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>This is a guest post by Mike Rousos In my post on bearer token authentication in ASP.NET Core, I mentioned that there are a couple good third-party libraries for issuing JWT bearer tokens in .NET Core. In that post, I used OpenIddict to demonstrate how end-to-end token issuance can work in an ASP.NET Core application. [&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,7525],"class_list":["post-36877","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","category-aspnetcore","tag-asp-net-identity","tag-identityserver"],"acf":[],"blog_post_summary":"<p>This is a guest post by Mike Rousos In my post on bearer token authentication in ASP.NET Core, I mentioned that there are a couple good third-party libraries for issuing JWT bearer tokens in .NET Core. In that post, I used OpenIddict to demonstrate how end-to-end token issuance can work in an ASP.NET Core application. [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/36877","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=36877"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/36877\/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=36877"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=36877"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=36877"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}