I've been on quite an adventure to get JWT working on DotNet core 2.0 (now reaching final release today). There is a ton of documentation, but all the sample code seems to be using deprecated APIs and coming in fresh to Core, It's positively dizzying to figure out how exactly it's supposed to be implemented. I tried using Jose, but app. UseJwtBearerAuthentication has been deprecated, and there is no documentation on what to do next.
Does anyone have an open source project that uses dotnet core 2.0 that can simply parse a JWT from the authorization header and allow me to authorize requests for a HS256 encoded JWT token?
The class below doesn't throw any exceptions, but no requests are authorized, and I get no indication why they are unauthorized. The responses are empty 401's, so to me that indicates there was no exception, but that the secret isn't matching.
One odd thing is that my tokens are encrypted with the HS256 algorithm, but I see no indicator to tell it to force it to use that algorithm anywhere.
Here is the class I have so far:
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json.Linq;
using Microsoft.IdentityModel.Tokens;
using System.Text;
namespace Site.Authorization
{
public static class SiteAuthorizationExtensions
{
public static IServiceCollection AddSiteAuthorization(this IServiceCollection services)
{
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("SECRET_KEY"));
var tokenValidationParameters = new TokenValidationParameters
{
// The signing key must match!
ValidateIssuerSigningKey = true,
ValidateAudience = false,
ValidateIssuer = false,
IssuerSigningKeys = new List<SecurityKey>{ signingKey },
// Validate the token expiry
ValidateLifetime = true,
};
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>
{
o.IncludeErrorDetails = true;
o.TokenValidationParameters = tokenValidationParameters;
o.Events = new JwtBearerEvents()
{
OnAuthenticationFailed = c =>
{
c.NoResult();
c.Response.StatusCode = 401;
c.Response.ContentType = "text/plain";
return c.Response.WriteAsync(c.Exception.ToString());
}
};
});
return services;
}
}
}
Here is a solution for you.
In your startup.cs, firstly, config it as services:
second, call this services in config
now you can use it in your controller by add attribute
For full details source code that use angular as Frond-end see here
My
tokenValidationParameters
works when they look like this:and
Moreover, add options.RequireHttpsMetadata = false like this:
EDIT:
Dont forget to call
in Startup.cs -> Configure method before app.UseMvc();
Here is my implementation for a .Net Core 2.0 API:
appsettings.json:
The above code enables auth on all controllers. To allow anonymous access you can decorate an entire controller:
or just decorate a method to allow a single endpoint:
Notes:
Audience
must match the Resource ID requested by the client. In our case our client (an Angular web app) was registered separately in Azure AD, and it used its Client Id, which we registered as the Audience in the APIClientId
is called Application ID in the Azure Portal (why??), the Application ID of the app registration for the API.TenantId
is called Directory ID in the Azure Portal (why??), found under Azure Active Directory > PropertiesIf deploying the API as an Azure hosted Web App, ensure you set the Application Settings:
eg. AzureAD:Audience / xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Asp.net Core 2.0 JWT Bearer Token Authentication Implementation with Web Api Demo
Add Package "Microsoft.AspNetCore.Authentication.JwtBearer"
Startup.cs ConfigureServices()
Startup.cs Configure()
User.cs // It is a model class just for example. It can be anything.
UserContext.cs // It is just context class. It can be anything.
AccountController.cs
UserController.cs
Test on PostMan:
Pass TokenType and AccessToken in Header in other webservices.
Best of Luck! I am just Beginner. I only spent one week to start learning asp.net core.
Just to update on the excellent answer by @alerya I had to modify the helper class to look like this;
Then I could obtain the userId in my service layer. I know it's easy in the controller, but a challenge further down.
Here is a full working minimal sample with a controller. I hope you can check it using Postman or JavaScript call.
appsettings.json, appsettings.Development.json. Add a section. Note, Key should be rather long and Issuer is an address of the service:
!!! In real project, don't keep Key in appsettings.json file. It should be kept in Environment variable and take it like this:
UPDATE: Seeing how .net core settings work, you don't need to take it exactly from Environment. You may use setting. However,instead we may write this variable to environment variables in production, then our code will prefer environment variables instead of configuration.
AuthRequest.cs : Dto keeping values for passing login and password:
Startup.cs in Configure() method BEFORE app.UseMvc() :
Startup.cs in ConfigureServices() :
Add a controller:
That's all folks! Cheers!
UPDATE: People ask how get Current User. Todo:
In Startup.cs in ConfigureServices() add
In a controller add to constructor:
Add somewhere an extension and use it in your Controller (using ....)