Authentication and Authorization in .Net Core 5 and Angular 10 using JWT problem - api

Hello I'm trying make authorization using JWT token so when not authorized user request api or request service it decline,
I've used JWT token with claim Role and made Job column in my database as role so that It will get the role from it
the problem is I can't decode the token or tbh I tried my best with the help of identity to decode it but I sure can't
that's my startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication();
services.AddCors(options =>
{
options.AddPolicy("EnableCORS", Builder =>
{
Builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddDbContext<media_cloudContext>(option => option.UseSqlServer(Configuration.GetConnectionString("MediaCloudCS")));
services.AddScoped<ILoginService, LoginService>();
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "MediaCloudApi", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MediaCloudApi v1"));
}
app.UseHttpsRedirection();
app.UseCors("EnableCORS");
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
I added JWT package and tried to add default scheme but it can't define it and the only thing avilable JWTBearerExtension
that's my token creation service
public class TokenHelper
{
public const string Issuer = "http://MediaCloud.com";
public const string Audience = "http://MediaCloud.com";
public const string Secret = "OFRC1j9aaR2BvADxNWlG2pmuD392UfQBZZLM1fuzDEzDlEpSsn+btrpJKd3FfY855OMA9oK4Mc8y48eYUrVUSw==";
public static string GenerateSecureSecret()
{
var hmac = new HMACSHA256();
return Convert.ToBase64String(hmac.Key);
}
public static string GenerateToken(UserInfo user)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Convert.FromBase64String(Secret);
var claimsIdentity = new ClaimsIdentity(new[] {
new Claim(ClaimTypes.Name, user.Id.ToString()),
new Claim(ClaimTypes.Role, user.Job),
});
var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = claimsIdentity,
Issuer = Issuer,
Audience = Audience,
Expires = DateTime.Now.AddMinutes(15),
SigningCredentials = signingCredentials,
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
}
and that's the get request from the controller
[HttpGet,Authorize]
public async Task<ActionResult<IEnumerable<UserInfo>>> GetUserInfos()
{
return await _context.UserInfos.ToListAsync();
}
and the error code from postman
STATUS 500 INTERNAL SERVER ERROR
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).
at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
HEADERS
=======
Accept: */*
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 69
Content-Type: application/json
Host: localhost:44371
User-Agent: PostmanRuntime/7.28.4
token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6IjciLCJyb2xlIjoiYWRtaW4iLCJuYmYiOjE2MzU5NzMyMDYsImV4cCI6MTYzNTk3NDEwNiwiaWF0IjoxNjM1OTczMjA2LCJpc3MiOiJodHRwOi8vTWVkaWFDbG91ZC5jb20iLCJhdWQiOiJodHRwOi8vTWVkaWFDbG91ZC5jb20ifQ.QjOC2ixirm9zmMmFDRO28JPd1Q97mq_M8bxlmmgT8EU
Postman-Token: 3911736a-ea2b-4273-ba35-d0315a560e71
I think the problem is the default schema but I can't add it and I'm new to .net core

you have to add to ConfigureServices(IServiceCollection services) of your startup file the code similar this one
var key = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration["Tokens:Key"]));
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
IssuerSigningKey = key,
ValidateIssuerSigningKey = true,
ValidateLifetime = true,
ValidateIssuer = false,
ValidAudience =Configuration["Tokens:Audience"] ,
ValidateAudience = true
};
});
and it is better to use appsettings to keep token parameters then to hard code them. Add somethig like this to to appsettings.json
"Tokens": {
"Key": "xxxxxx"
"Audience": "xxxxx",
"Issuer": "xxxx"
}

Related

ASP.NET Core returns InternalServerError while using Identity server

I trying to add identity server for my web API as its identity server4 documentation. when I was trying to call API from my console application it's every time returns InternalServerError.
Here is My Identity server Config.cs
public static class Config
{
// register api
public static IEnumerable<ApiScope> ApiScopes => new List<ApiScope>
{
// in here add your api name
new ApiScope("api1", "My API")
};
// register client which is going to access api. eg: front-end application, mobile apps etc. can add multiple client.
public static IEnumerable<Client> Clients => new List<Client>
{
new Client
{
// which is going to access
ClientId = "client",
// no interactive user, use the clientid/secret for authentication
AllowedGrantTypes = GrantTypes.ClientCredentials,
// secret for authentication
ClientSecrets =
{
new Secret("secret".Sha256())
},
// scopes that client has access to
AllowedScopes = { "api1" }
}
};
}
and here the identity server startup file configuration service and configure functions
public void ConfigureServices(IServiceCollection services)
{
// uncomment, if you want to add an MVC-based UI
services.AddControllersWithViews();
var builder = services.AddIdentityServer()
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients);
builder.AddDeveloperSigningCredential();
builder.AddDeveloperSigningCredential();
}
public void Configure(IApplicationBuilder app)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// uncomment if you want to add MVC
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
// uncomment, if you want to add MVC
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
and here is my API startup file's congurationService and configure functions
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:14030/";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
}
);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
here is my API controller
[Route("identity")]
public class IdentityController : ControllerBase
{
[HttpGet]
[Authorize]
public IActionResult Get() => Ok(new JsonResult(from c in User.Claims select new { c.Type, c.Value }));
}
and here is my console application client request a api
static async System.Threading.Tasks.Task Main(string[] args)
{
// discover endpoints from metadata
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("http://localhost:14030");
if (disco.IsError)
{
Console.WriteLine(disco.Error);
return;
}
// request token
var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
Address = disco.TokenEndpoint,
ClientId = "client",
ClientSecret = "secret",
Scope = "api1"
});
if (tokenResponse.IsError)
{
Console.WriteLine(tokenResponse.Error);
return;
}
Console.WriteLine(tokenResponse.Json);
Console.WriteLine("\n\n");
// call api
var apiClient = new HttpClient();
apiClient.SetBearerToken(tokenResponse.AccessToken);
var response = await apiClient.GetAsync("https://localhost:5001/identity");
if (!response.IsSuccessStatusCode)
{
Console.WriteLine(response.StatusCode);
}
else
{
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
}
}
what are the mistakes should I have to fix. Im really appreciates your valuable answers and efforts.
Thank
I got the code working, I would do the following:
use HTTPS here, not HTTP:
var disco = await
client.GetDiscoveryDocumentAsync("http://localhost:14030");
Remove the duplicate lines of in IdentityServer startup class:
builder.AddDeveloperSigningCredential();
I would add in your API startup.cs
services.AddAuthorization();
Remove the trailing / at the end of the URL here:
options.Authority = "https://localhost:14030/";
To get more debugging output from your API, you can add the following two trace lines to your appsettings.Development.json file:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"Microsoft.AspNetCore.Authentication": "Trace",
"Microsoft.AspNetCore.Authorization": "Trace"
}
}
}
If you want to validate the Audience (and using IdentityServer4 v4.00) you can add:
services.AddControllers();
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://localhost:14030";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidAudiences = new[] {"https://localhost:14030/resources"},
ValidateAudience = true
};
}
);

Authorize Attribute not working with JWT Access Token in ASP.Net Core

Trying to setup JWT with Ast.Net Core app and somehow when I use the [Authorize] attribute on the method it shows Bearer error="invalid_token"
Not sure what I am missing here.
AppSettings:
"Jwt": {
"Key": "ThisisaKeyforAPIAccess",
"Issuer": "TestSite.com"
}
Method to generate Access Token:
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Issuer"],
expires: DateTime.Now.AddMinutes(10),
signingCredentials: credentials);
return new
{
token = new JwtSecurityTokenHandler().WriteToken(token),
expiration = token.ValidTo
};
Auth.cs (To Check Token)
public static IServiceCollection AddAuthentication(this IServiceCollection services, IConfiguration configuration)
{
var issuerID = configuration.GetSection("Jwt").GetValue<string>("Issuer");
services.AddAuthentication(
option => {
option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
option.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}
).
AddJwtBearer(options => {
options.SaveToken = true;
options.RequireHttpsMetadata = true;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidAudience = issuerID,
ValidIssuer = issuerID,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Jwt:Key"]))
};
});
return services;
}
and finally in Startup.cs
services.AddAuthentication(_configuration);
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build();
});
and in Configure method for Startup class
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApiVersionDescriptionProvider provider)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseAuthentication();
app.UseMvc();
}
If I use the [Authorize] attribute I am getting invalid token on the method. Not sure what I am missing here.

ASP.NET Core authentication with JWT: 'The signature is invalid'

I want to enable authentication based on jwt claims. For some reason the token seems to be invalid, more specifically its signature seems to be the problem.
I tried verifying the signature on https://jwt.io/ and it is verified successfully.
My token is
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZ2VudCIsImF1dCI6WyJST0xFX0FHRU5UIl0sImlzcyI6Ik1ULVVzZXIiLCJpYXQiOjE1NjA2OTcyMDIsImV4cCI6MTU2MDY5ODEwMn0.WDTPFuEsRRuDfko2dR_5QsWWmyEwUtup-C-V3AF0tE95SJWuNtTiWQCcGoHsNdi-Y7G62pNv4TpaQ3h-deGR3A
And the secret is
9ST5hQe5dUNfAJOQZAtt19uiDhNtKKUt
My Startup.cs class:
public void ConfigureServices(IServiceCollection services)
{
/*...*/
var key = Encoding.ASCII.GetBytes("9ST5hQe5dUNfAJOQZAtt19uiDhNtKKUt");
var signingKey = new SymmetricSecurityKey(key);
// Authenticate a request
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateAudience = false,
ValidateIssuer = false
};
});
// Custom policy to check if a certain claim has a certain value
services.AddAuthorization(options =>
{
options.AddPolicy(
"IsAgentPolicy",
policy => policy.RequireClaim("aut", "ROLE_AGENT")
);
});
/*...*/
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseMvc();
}
My test api controller ValuesController.cs:
[Route("api/[controller]")]
public class ValuesController : ControllerBase
{
// GET: api/<controller>
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/<controller>/5
[HttpGet("{id}")]
[Authorize("IsAgentPolicy")]
public string Get(int id)
{
return "value";
}
}
I tried to hit the 'localhost:5000/api/values/1' endpoint (which has an authorization attribute), adding the 'Bearer ' to the 'Authorization' header, however I get a response header
WWW-Authenticate →Bearer error="invalid_token", error_description="The signature is invalid"
Solved
It seems that the secret was Base64URL encoded and needed decoding before it could be used in forming the signing key
var key = Base64UrlEncoder.DecodeBytes("YOUR_SECRET");
SymmetricSecurityKey signingKey = new SymmetricSecurityKey(key);

Getting an error "blocked by CORS policy" only for "https://localhost:44361/connect/token" in Angular 7 web app

Complete error is as shown below.
Access to XMLHttpRequest at 'https://localhost:44361/connect/token' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have enabled cores policy in my start up class in .net core web api as shown below.
My ConfigureService method
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<LEAFDDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), builder =>
{
builder.EnableRetryOnFailure(5, TimeSpan.FromSeconds(10), null);
}));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<LEAFDDbContext>()
.AddDefaultTokenProviders();
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
Installer.ConfigureServices(services);
//services.AddCors();
//services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
//services.AddSingleton<IAuthenticationSchemeProvider, CustomAuthenticationSchemeProvider>();
//services.AddAuthentication(options =>
//{
// //options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// //options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// //options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
// options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
// options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
//})
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Events.OnRedirectToLogin = ctx =>
{
// if it is an ajax/api request, don't redirect
// to login page.
if (!(IsAjaxRequest(ctx.Request) || IsApiRequest(ctx.Request)))
{
ctx.Response.Redirect(ctx.RedirectUri);
return Task.CompletedTask;
}
ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
return ctx.Response.WriteAsync("Unauthorized");
};
})
.AddOAuthValidation()
//services.AddAuthentication()
.AddOpenIdConnectServer(options =>
{
options.Provider = new AuthorizationProvider();
// Enable the authorization and token endpoints.
options.AuthorizationEndpointPath = "/connect/authorize";
options.TokenEndpointPath = "/connect/token";
options.AllowInsecureHttp = true;
// Note: to override the default access token format and use JWT, assign AccessTokenHandler:
//
options.AccessTokenHandler = new JwtSecurityTokenHandler
{
InboundClaimTypeMap = new Dictionary<string, string>(),
OutboundClaimTypeMap = new Dictionary<string, string>()
};
//
// Note: when using JWT as the access token format, you have to register a signing key.
//
// You can register a new ephemeral key, that is discarded when the application shuts down.
// Tokens signed using this key are automatically invalidated and thus this method
// should only be used during development:
//
options.SigningCredentials.AddEphemeralKey();
//
// On production, using a X.509 certificate stored in the machine store is recommended.
// You can generate a self-signed certificate using Pluralsight's self-cert utility:
// https://s3.amazonaws.com/pluralsight-free/keith-brown/samples/SelfCert.zip
//
//options.SigningCredentials.AddCertificate("7D2A741FE34CC2C7369237A5F2078988E17A6A75");
});
}
Configure method
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
//app.UseOAuthValidation();
app.UseAuthentication();
app.UseMvc();
app.UseMiddleware();
app.UseCors("CorsPolicy");
//app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin().AllowCredentials());
app.UseWelcomePage();
}
This is working as expected for all other calls except 'https://localhost:44361/connect/token' : When getting the token.
I'm sending all the requests from Angular 7 web app to .net core web api.
As a work around i have installed cross-origin resource sharing extension from google chrome and I need a code level change to fix this issue permanently.
This is the final solution i came up with.
Instead of calling "https://localhost:44361/connect/token" directly from Angular 7 app, I have created a method in API controller that will invoke above call and get the token. So when ever i need all i need is to call the newly created method in API controller.
New api call as follows
[HttpPost]
[Route("/api/[controller]/Token")]
[EnableCors("CorsPolicy")]
public async Task<ContentResult> Token(LoginTokenRequestModel model)
{
string UserId = string.Empty;
try
{
using (HttpClient httpClient = new HttpClient())
{
if (!String.IsNullOrEmpty(model.Email))
{
var content = new FormUrlEncodedContent(new KeyValuePair<string, string>[]{
new KeyValuePair<string, string>("grant_type", model.grant_type),
new KeyValuePair<string, string>("client_secret", model.client_secret),
new KeyValuePair<string, string>("client_id", model.client_id),
new KeyValuePair<string, string>("username", model.Email),
new KeyValuePair<string, string>("password", model.Password),
});
string apiURL = "https://localhost:44361";
var response = await httpClient.PostAsync(apiURL + "/connect/token", content);
var resultContent = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var token = JsonConvert.DeserializeObject<object>(resultContent);
return new ContentResult
{
Content = token.ToString(),
ContentType = "text/plain",
StatusCode = 200
};
}
return new ContentResult
{
Content = JsonConvert.DeserializeObject<object>(resultContent).ToString(),
ContentType = "text/plain",
StatusCode = 200
};
}
}
}
catch (Exception ex)
{
return new ContentResult
{
Content = ex.Message,
ContentType = "text/plain",
StatusCode = 400
};
}
return new ContentResult
{
Content = "",
ContentType = "text/plain",
StatusCode = 400
};
}
This resolved my issue.
Use app.UseCors() before app.useMvc(). Order matters when it comes to middleware invocation. Personally, I keep it in environment determining if-else.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseCors("CorsDevPolicy");
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseMiddleware(typeof(ErrorHandlingMiddleware));
app.UseMvc();
}

.NET Core 2 Web API JWT token not recognized

I followed this tutorial to configure JWT authorization in my Web API app. The token generation and handout works fine, but when I send a request back to the server with the token, it doesn't populate the identity, so it fails if authorization is required.
I've tested both with a reactjs frontend and Postman. Both end up returning nothing (without Authorize decorator - User.Identity.isAuthorized is false), or 404 with the decorator. I have confirmed that the token is being sent properly.
I'm also using Identity, if that matters.
ConfigureServices method
public void ConfigureServices(IServiceCollection services)
{
...
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
}
Configure method
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.UseCors("SiteCorsPolicy");
app.UseMvc();
...
}
Function to build the token
private string BuildToken(AuthViewModel user)
{
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Username),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken
(
_config["Jwt:Issuer"],
_config["Jwt:Audience"],
//claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
Excerpt from appsettings.json
"Jwt": {
"Key": "<secret stuff>",
"Issuer": "http://localhost:53530/",
"Audience": "http://localhost:8080/"
}
Test function I'm trying to call but is failing
[HttpGet("currentuser"), Authorize]
public async Task<ApplicationUser> GetCurrentUser()
{
var username = User.Identity.Name;
return await _context.ApplicationUsers.SingleOrDefaultAsync(u => u.UserName == username);
}
I figured it out. I had to add a new Authorization Policy.
services.AddAuthorization(auth =>
{
auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireAuthenticatedUser().Build());
});
Then I decorated the controller with
[Authorize("Bearer"]
I've been messing with this for a couple days, trying different tutorials, so I know this was working at one point without the policy. Dunno why I needed it this time or why it wasn't part of the tutorial.
If someone figures out what I screwed up in the first place, I'm all ears.
I ran into the same issue (.net core 2.1) and was really happy to make it work using your answer #atfergs.
After fiddling with the whole setup I found out that no new Authorization Policy is required.
It is sufficient to decorate the controller with
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
considering the following setup
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{...}
Now
User?.Identity?.IsAuthenticated
is true :)
Cheers!