I have the stock file | new | web | asp.net core web api project template where I selected AzureAD authentication that generated the following Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
and the following appsettings.json
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "mymsdn.onmicrosoft.com",
"TenantId": "<my azuread tenant id>",
"ClientId": "<my azuread web app id>"
}
I'm using postman to acquire token leveraging a public client profile app setup just as I have done for another web api setup that is working as expected with the same azureAd bearer token auth code and settings coordinates.
For some reason this app is trying to validate the wrong token issuer format and i'm at a loss as to how I correct it.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: AzureADJwtBearer was not authenticated. Failure message: IDX10205: Issuer validation failed. Issuer: 'https://login.microsoftonline.com/<my azuread tenantid>/v2.0'. Did not match: validationParameters.ValidIssuer: 'null' or validationParameters.ValidIssuers: 'https://sts.windows.net/<my azuread tenantid>/'.
Turns out this issue surfaces if you configured azuread app registrations entry for your ClientId to support any organization or consumer, aka microsoft account, signins instead of just your organization or any organization. The fix was to use the AddJwtBearer() block of Startup.ConfigureServices() code shown below instead of the project template provided AddAzureADBearer() block.
public void ConfigureServices(IServiceCollection services)
{
// if azuread app registrations entry for ClientId has "signInAudience": "AzureADMyOrg" or "AzureADMultipleOrgs" where "iss": "https://sts.windows.net/{TenantId}/"
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => //Configuration.Bind("AzureAd", options));
{
Configuration.Bind("AzureAd", options);
Log.LogInformation($"the AddAzureADBearer options have been configured for ClientId = {options.ClientId}");
});
// if azuread app registrations entry for ClientId has "signInAudience": "AzureADandPersonalMicrosoftAccount" where "iss": "https://login.microsoftonline.com/{TenantId}/v2.0"
services.AddAuthentication(options => { options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; })
.AddJwtBearer(options =>
{
var azureadoptions = new AzureADOptions(); Configuration.Bind("AzureAd", azureadoptions);
options.Authority = $"{azureadoptions.Instance}{azureadoptions.TenantId}/v2";
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidAudience = $"{azureadoptions.ClientId}",
//ValidAudiences = new List<string> { $"{azureadoptions.ClientId}", $"api://{azureadoptions.ClientId}", $"https://myapp.azurewebsites.net/" },
//ValidIssuer = $"https://sts.windows.net/{azureadoptions.TenantId}/" // for "signInAudience": "AzureADMyOrg" or "AzureADMultipleOrgs"
ValidIssuer = $"{azureadoptions.Instance}{azureadoptions.TenantId}/v2.0" // for "signInAudience": "AzureADandPersonalMicrosoftAccount"
//ValidIssuers = new List<string> { $"https://sts.windows.net/{azureadoptions.TenantId}/", $"{azureadoptions.Instance}{azureadoptions.TenantId}/v2.0" }
};
Log.LogInformation($"the AddJwtBearer options have been configured for ClientId = {azureadoptions.ClientId}");
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
I was trying to authenticate existing token from uwp-app in web-api and I had a similar issue:
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidIssuerException: IDX10205: Issuer validation failed. Issuer: 'https://spolujizda.b2clogin.com/4e8094c9-5058-454c-b201-ef61d7ae6619/v2.0/'. Did not match: validationParameters.ValidIssuer: 'null' or validationParameters.ValidIssuers: 'https://login.microsoftonline.com/4e8094c9-5058-454c-b201-ef61d7ae6619/v2.0/'.
at Microsoft.IdentityModel.Tokens.Validators.ValidateIssuer(String issuer, SecurityToken securityToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateIssuer(String issuer, JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateTokenPayload(JwtSecurityToken jwtToken, TokenValidationParameters validationParameters)
at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String token, TokenValidationParameters validationParameters, SecurityToken& validatedToken)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: AzureADB2CJwtBearer was not authenticated. Failure message: IDX10205: Issuer validation failed. Issuer: 'https://spolujizda.b2clogin.com/4e8094c9-5058-454c-b201-ef61d7ae6619/v2.0/'. Did not match: validationParameters.ValidIssuer: 'null' or validationParameters.ValidIssuers: 'https://login.microsoftonline.com/4e8094c9-5058-454c-b201-ef61d7ae6619/v2.0/'.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "Get", controller = "Values"}. Executing action Spolujizda.ApiServer.Controllers.ValuesController.Get (Spolujizda.ApiServer)
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information: AuthenticationScheme: AzureADB2CJwtBearer was challenged.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action Spolujizda.ApiServer.Controllers.ValuesController.Get (Spolujizda.ApiServer) in 8.105ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 8950.4739ms 401 text/plain
But for me the fix was much simpler.
For Web API I had AzureAdB2C.Instance set to https://spolujizda.b2clogin.com/tfp/.
For an UWP app, I had been issuing token via https://login.microsoftonline.com/tfp/
That is why it resulted in this error. Because in the UWP app, the token was issued for login.microsoft... and in the Web API, it was trying to verify issuer as spolujizda.b2clogin...
First I tried to change address for issuing token for uwp-app, but that didn't work.
So secondly I just changed web-api's AzureAdB2C.Instance config to login.microsoft.... and it now works.
Related
I am using Blazor WebAssembly Asp.Net Core hosted PWAand integrated the AspNetCore.Identity into it. I created the AuthenticationStateProvider in the Client-Side and now I want to allow the user access to a controller where he needs to be authorized.
I have tested via postman, the users were been created and stored in DB as aspnetusers with the right credentials. The Login/Account Controller work as I wanted it.
When the user is authorized it tells this exception in the browser when accessing the authorized controller request:
Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Response status code does not indicate success: 401 (Unauthorized).
System.Net.Http.HttpRequestException: Response status code does not
indicate success: 401 (Unauthorized).
Startup.cs (ConfigureServices-Method):
...
serviceCollection.AddDbContext<SQLiteTestDbContext>(options =>
{
options.UseSqlite(config["ConnectionStrings:SQLiteTestConnection"]);
});
serviceCollection.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<SQLiteTestDbContext>()
.AddDefaultTokenProviders();
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["JwtIssuer"],
ValidAudience = Configuration["JwtAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtSecurityKey"]))
};
});
services.AddHttpContextAccessor();
services.Configure<IdentityOptions>(options =>
options.ClaimsIdentity.UserIdClaimType = ClaimTypes.NameIdentifier);
...
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseAuthentication();
app.UseAuthorization();
...
}
Program.cs Client-Side
public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");
builder.Logging.SetMinimumLevel(LogLevel.Warning);
//Registering Shared-Library models
builder.Services.AddScoped<ObjectModel>();
builder.Services.AddBlazoredLocalStorage();
builder.Services.AddAuthorizationCore();
builder.Services.AddScoped<AuthenticationStateProvider, ApiAuthenticationStateProvider>();
builder.Services.AddScoped<IAuthService, AuthService>();
//Registered BlazorContextMenu Service
builder.Services.AddBlazorContextMenu();
//Registering FileReader service, for image upload -> Azure
builder.Services.AddFileReaderService(options => options.UseWasmSharedBuffer = true);
builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();
}
My Controller with authorize attribute:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Route("api/[controller]")]
[ApiController]
public class ObjectController : ControllerBase
{
....
Note:
When your user tries to access a protected (annotated with the Authorize attribute) page on the client he should login first or register.
In order to register, he should be redirected to an Account Controller where you should create a new user, and add it to the database (You said you " integrated the AspNetCore.Identity into it"), which is fine...and should be used to authenticate and verify the user's identity. You account controller should also produce a Jwt Token that should be passed to the client app, and stored in the local storage.
Now, whenever your user tries to access protected resources on your Web Api endpoints, you should retrieve the Jwt Token from the local storage, and add it to the request header. If you do so, the Unauthorized response would be something of the past.
Custom AuthenticationStateProvider can be a good place from which you can manage storing the Jwt Token in the local storage and retrieving it for outbound HTTP request calls.
Here's some sample code to clarify what you should do:
#code {
WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
var token = await TokenProvider.GetTokenAsync();
forecasts = await Http.GetJsonAsync<WeatherForecast[]>(
"api/WeatherForecast",
new AuthenticationHeaderValue("Bearer", token));
}
}
Note: TokenProvider is a custom AuthenticationStateProvider that defines a method called GetTokenAsync that provides (reading the Jwt Token from the local storage and passing it to the calling code) the Jwt Token
Hope this helps...
In case of Linux App Service in combination with ID Server the Authority needs to be set according to Microsoft documentation: https://learn.microsoft.com/en-us/aspnet/core/security/authentication/identity-api-authorization?view=aspnetcore-5.0#azure-app-service-on-linux-1
services.Configure<JwtBearerOptions>(
IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
options =>
{
options.Authority = "{AUTHORITY}";
});
Example: options.Authority = "https://contoso-service.azurewebsites.net";
I have an ASP.NET Core API which uses JWT Authentication. Simple setup:
....
string authority = $"https://{configuration["Auth:Authority"]}";
string audience = configuration["Auth:Audience"];
return builder.AddJwtBearer(options =>
{
options.Authority = authority;
options.Audience = audience;
options.TokenValidationParameters = new TokenValidationParameters
{
// NameClaimType = "http://schemas.org/email"
// NameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/email"
// NameClaimType = "sub"
};
});
(as you can see commented code, I have been trying several settings)
When I decode JWT (using jwt.io) I see there is claim "sub" in JWT and has string value (internal ID of user in dbo)
{
"nbf": 1592585433,
"exp": 1592585763,
"iss": "https://*************",
"aud": "api_10",
"sub": "142",
"scope": [
"openid",
"api_10"
]
}
The problem is that dotnet switch sub to name claim. This returns no (0) results:
principal.Claims.Where(w => w.Type == "sub")
This returns userId I need "142":
principal.Claims.Where(w => w.Type == ClaimTypes.Name || ClaimTypes.NameIdentifier)
What is going on?! Where is my sub claim gone?
Just add JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); on the API's ConfigureServices method. Its suggested on the other comment as well. I verified it on my sample repo.
This issue is because OIDC StandardClaims are renamed on JWT token handler. By adding JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); you will clear the inbound claim type map on the JWT token handler.
Read more here
The API client is using either JWT token issued by API itself (standard) or by Azure AD.
When I enable ONLY the custom (standard) bearer authentication, everything works perfectly, without any issues.
Also, when I enable ONLY the Azure AD bearer authentication, everything works perfectly, also.
When I enable both of them, one of them stops working.
Here is my setup of the .Net core API:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(BuildStandardJwtBearerOptions);
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options));
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
private void BuildStandardJwtBearerOptions(JwtBearerOptions options)
{
var settings = GetStandardTokenSettings(null);
options.IncludeErrorDetails = true;
options.RequireHttpsMetadata = false;
options.SaveToken = true;
var signingKeyBytes = Encoding.UTF8.GetBytes(settings.SecretKey);
var signingKey = new SymmetricSecurityKey(signingKeyBytes);
options.TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = settings.Issuer,
ValidAudience = settings.Issuer,
IssuerSigningKey = signingKey
};
}
Here is an example error for when client is sending Azure AD token:
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information:
Failed to validate the token.
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidSignatureException:
IDX10500: Signature validation failed. No security keys were provided
to validate the signature. at
System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String
token, TokenValidationParameters validationParameters) at
System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateToken(String
token, TokenValidationParameters validationParameters, SecurityToken&
validatedToken) at
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information:
AzureADJwtBearer was not authenticated. Failure message: IDX10500:
Signature validation failed. No security keys were provided to
validate the signature.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information:
Route matched with {action = "List", controller = "Account"}.
Executing action BookRental.Api.Controllers.AccountController.List
(BookRental.Api)
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information:
Authorization failed.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information:
Authorization failed for the request at filter
'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing
ChallengeResult with authentication schemes ().
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler:Information:
AuthenticationScheme: AzureADJwtBearer was challenged.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information:
Executed action BookRental.Api.Controllers.AccountController.List
(BookRental.Api) in 7.1108ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request
finished in 16.8394ms 401
How can I make those two types of tokens to work side by side?
You can try to change the default policy of the authorization system by indicating both the authentication schemes :
services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme)
.AddAzureADBearer(options => Configuration.Bind("AzureAd", options))
.AddJwtBearer("scc", BuildStandardJwtBearerOptions);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services
.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes(AzureADDefaults.BearerAuthenticationScheme, "scc")
.Build();
});
I have a REST API (core 2.1) which need to support a SPA, providing restful endpoints and some live-interactive features using SignalR;
The Hub/MVC routes are running on the same server, which is also the provider of the JWT token.
After loggin in, the client-side receives a JWT token, which places on the header for every REST request, otherwise it gets a 401 (This is working with the [Authorize] attribute).
At the client-side, the code below tries to connect to my /hub endpoint:
new HubConnectionBuilder().withUrl(HUB_URL, { accessTokenFactory: () => this.getToken() })
And if I place [Authorize] at my Hub class, I get the following error (Without the authorization, the client can send and listen correctly):
WebSocket connection to 'wss://localhost:5001/hub?id=MY_ID&access_token=MY_TOKEN' failed: HTTP Authentication failed; no valid credentials available
The server logged failed authentications:
(Triggered a console.log on AddJwtBearerOptions.Events.OnMessageReceived)
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET https://localhost:5001/hub?
id=MY_ID&access_token=MY_TOKEN
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed.
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
AuthenticationScheme: Bearer was challenged.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.3658ms 401
Differently from the those requests, using the SAME JWT TOKEN with the REST ones (Using [Authorize]), with the Header: Bearer XXXX instead of querystring, triggers the OnTokenValidated. The OnAuthenticationFailed is never triggered, even if the authentication fails:
(Triggered a console.log on AddJwtBearerOptions.Events.OnMessageReceived)
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET https://localhost:5001/api/products application/json
(Triggered a console.log on AddJwtBearerOptions.Events.OnTokenValidated)
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[2]
Successfully validated the token.
Check below my ´Startup.cs`
ConfigureServices(IServiceCollection)
services.AddSignalR();
services.AddCors(option => option.AddPolicy("CorsPolicy", p => p.AllowAnyHeader().AllowAnyOrigin().AllowAnyMethod().AllowCredentials()));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters{
ValidateIssuer = true,
ValidIssuer = Configuration["JWT:Issuer"],
ValidateLifetime = true,
ValidateAudience = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWT:SecurityKey"]))
};
});
Configure(IApplicationBuilder)
app.UseAuthentication();
app.UseCors("CorsPolicy");
app.UseHttpsRedirection();
app.UseMvc();
app.UseSignalR(routes => {
routes.MapHub<ApplicationHub>("/hub");
});
You also need to add this block inside the .AddJwtBearer section:
// We have to hook the OnMessageReceived event in order to
// allow the JWT authentication handler to read the access
// token from the query string when a WebSocket or
// Server-Sent Events request comes in.
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
var accessToken = context.Request.Query["access_token"];
// If the request is for our hub...
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
(path.StartsWithSegments("/hub")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
This can be found here in the docs.
info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
Authorization failed.
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
AuthenticationScheme: Bearer was challenged.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 0.3658ms 401
Spend 20 hours for fixing. :(
Reason was in:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class ChatHub : Hub<IChatClient>
My service configuration:
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options => ...)
UPD:
Full work example with JS client here.
To expand on what #marcusturewicz already have stated, one should also check for the token inside the Authorization header in case if the access token is sent in the header instead of query.
Although, this may vary from how e.g., the client implementer sends the token.
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
// If no token is present in the query, we can
// try to get it from the Authorization header.
StringValues accessToken = context.Request.Query["access_token"] == StringValues.Empty
? context.Request.Headers["Authorization"]
: context.Request.Query["access_token"];
// If the request is for our hub...
var path = context.HttpContext.Request.Path;
if (!string.IsNullOrEmpty(accessToken) &&
(path.StartsWithSegments("/hub")))
{
// Read the token out of the query string
context.Token = accessToken;
}
return Task.CompletedTask;
}
};
I have implemented the normal login behavior where a JWT token is issued upon successful logon. The API (ASP.Net) should then restrict access to certain Controller actions using the [Authorize] attribute - however I keep on getting a:
401 - Unauthorized response ("Authorization has been denied for this request.")
I am relatively sure I am not configuring the JWT Token authentication correctly - however I have this in my startup, using Microsoft.Owin.Host.SystemWeb:
public void Configuration(IAppBuilder app) {
ConfigureOAuthTokenConsumption(app);
}
private void ConfigureOAuthTokenConsumption(IAppBuilder app) {
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions {
AllowedAudiences = new string[] { "*" },
TokenValidationParameters = new TokenValidationParameters {
ValidateIssuer = true,
ValidIssuer = "SomeValidIssuer",
ValidateAudience = true,
ValidAudience = "SomeValidAudience",
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("mysupersecretkey"))
}
}
);
}
With a very simple token being passed through to the request via header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MzM1NzY5MDEsImlzcyI6IlNvbWVWYWxpZElzc3VlciIsImF1ZCI6IlNvbWVWYWxpZEF1ZGllbmNlIn0.YfgbVuLgjTagkZTHwXRh9gQxOq5boeMa7TOgq0keKc0
You can use this site to see the contents of the token
I have followed this excellent link on Securing your ASP.NET Core 2.0 API which is working like a charm, but dotNetCore is not an option for the project I am currently working on - however I have followed a similar path in issuing the tokens.
What am I doing wrong, why am I getting a 401 on my request?