I have been developing an application that involves using JWT validation and this is my first time doing it. Needless to say I have learned a lot and feel good about where it is currently at. However, as I had figured out one of my last issues with it I started to run into an error with one of my endpoints, 401 Unauthorized. This was actually a positive for me because now I knew the validation was working.
Once I used a valid token and put it in Postman and hit the same endpoint, still I got 401. As an important note I am working on Mac and had been doing all this work on VSCode since I figured I should get more used to that and not be so dependent on Visual Studio. I had originally started in Visual Studio using Parallels.
This is where it gets weird. I decided to pull down the new changes I had made that I thought should now be working. This was pulled into the Visual Studio local repo now and when I ran it and hit the endpoint in Postman with the same token it worked like a charm.
So my guess is that I am either using the "dotnet run" command wrong or have encountered some weird edge case. Any thoughts or help would be much appreciated.
Side Note:
Before anyone says anything about secrets/appsettings I did make sure all of those were the same on the VSCode and VisualStudio side so I know it is not that. If I need to post any files for more understanding I would be happy to do so.
Again all I have been doing to run the app on the VSCode (non parallels) side of things is using the "dotnet run" command.
Code for adding auth:
public static void AddIdentityAndAuth(this IServiceCollection services, IConfiguration config)
{
// Add Identity (DefaultTokenProviders didn't work)
services.AddIdentityCore<FinFormUser>()
.AddRoles<FinFormRole>()
.AddEntityFrameworkStores<FinFormDbContext>();
var domain = $"https://{config["AUTH0_DOMAIN"]}/";
/* New Implementation of Auth0 signature validation */
/* Uses Auth0 supplied jwks endpoint now */
var client = new RestClient(domain);
var request = new RestRequest(resource:".well-known/jwks.json");
request.AddHeader("content-type", "application/json");
RestResponse response = client.Execute(request);
var jsonRes = JsonSerializer.Deserialize<Auth0SignResponse>(response!.Content!.ToString());
var signingKey = jsonRes!.keys[0].x5c[0]; //key from json response
var publicKeyArray2 = Convert.FromBase64String(signingKey);
var cert = new X509Certificate2(publicKeyArray2);
/* End Implementation */
// Add in Authentication with JWT
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidAudience = config["AUTH0_AUDIENCE"],
ValidIssuer = domain,
IssuerSigningKeyResolver = (t, st, i, p) => new[] {
new X509SecurityKey(cert)
},
};
});
// Add Authorization
services.AddAuthorization();
}
Running API on MacOS:
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7154
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5274
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Result on MacOS: postman screenshot result Mac
Running API on Parallels (Windows):
info: Microsoft.Hosting.Lifetime[14]
Now listening on: https://localhost:7154
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5274
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Result on Parallels: postman screenshot result windows