How can I implement Bearer Token in MVC 6 API vNext? - asp.net-core

I am working on a sample SPA application to get my hands on ASP.NET 5. I am using Visual Studio Community 2015 RC.
I am stuck on Bearer token generation. I need to generate a token for AngularJS app so that I can call and authenticate APIs.

Have a look at this similar question Token Based Authentication in ASP.NET Core
Matt DeKrey's answer may solve your problem.

You can implement claim based authentication like below;
Add a method in Startup.cs
public void ConfigureAuthentication(IServiceCollection services)
{
var key = Encoding.ASCII.GetBytes("very-secret-much-complex-secret");
var tokenValidationParameters = new TokenValidationParameters
{
// The signing key must match
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
// Validate the JWT issuer (Iss) claim
ValidateIssuer = false,
//ValidIssuers = validIssuerList,
// Validate the JWT audience (Aud) claim
ValidateAudience = false,
//ValidAudiences = validAudienceList,
// Validate token expiration
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>
{
o.TokenValidationParameters = tokenValidationParameters;
});
}
And call this method in ConfigureServices method on Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//DI Injections
services.AddScoped<IAuthService, AuthService>();
services.AddScoped<IAudienceService, AudienceService>();
ConfigureAuthentication(services);
services.AddMvc(
options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
}
Then, UseAuthentication in the Configure method
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
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.UseAuthentication();
app.UseHttpsRedirection();
app.UseMvc();
}
Above we configured our API to use JWT authentication as authorization layer. Lets see how we generate a valid token below;
public async Task<string> Authenticate(string apiKey, string sharedSecret)
{
//get audience by apikey and password from database
//create token from createdobject
var audience = await audienceService.GetByCredentials(apiKey, sharedSecret);
// return null if auudience not found
if (audience == null)
return null;
// authentication successful so generate jwt token
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes("very-secret-much-complex-secret");
var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature);
//arange claims from permissions
var claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, audience.Name),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
claims.AddRange(audience.Permissions.Where(p => p.Value).Select(p => new Claim(ClaimsIdentity.DefaultRoleClaimType, p.Key.GetHashCode().ToString())));
var token = new JwtSecurityToken(
audience.Name,
audience.Name,
claims,
expires: DateTime.UtcNow.AddDays(7),
signingCredentials: signingCredentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
You can find the whole project in my GitHub repo:https://github.com/ilkerkaran/simple-claim-based-auth

Related

ASP.NET Core 5 MVC web application - Login via xamarin

I've developed my ASP.NET Core 5 MVC application with "Individual Login". Registering and logging within the app works fine.
Now I want to log in to my MVC web application with an API for my Xamarin App. From what I've read "JWT" should be used. I want to use as much "standard" in the backend as possible, ideally using standard APIs.
Unfortunately, all the sites I've tried could not help me (solution broken, non-existing urls,....).
Could somebody please post me a working tutorial or an example for the backend please.
Thanks, Jeppen
From api, you can configure the jwt authentication as this.
In Startup
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>
{
o.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role,
//The previous three items are required
ValidIssuer = "http://localhost:5000",
ValidAudience = "api",
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("this is a long key"))
/***********************************default TokenValidationParameters parameter***********************************/
// RequireSignedTokens = true,
// SaveSigninToken = false,
// ValidateActor = false,
};
});
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
//...
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
//...
}
Apply for a token, generate a string token in the action.
public IActionResult Authenticate()
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes("this is a long key");
var authTime = DateTime.UtcNow;
var expiresAt = authTime.AddDays(7);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(JwtClaimTypes.Audience,"api"),
new Claim(JwtClaimTypes.Issuer,"http://localhost:5000"),
new Claim(JwtClaimTypes.Id, "10"),
new Claim(JwtClaimTypes.Name, "my name"),
new Claim(JwtClaimTypes.Email, "email"),
}),
Expires = expiresAt,
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
var tokenString = tokenHandler.WriteToken(token);
return Ok(tokenString);
}
Xamarin App receives token and save it. When Xamarin App access the authorized resource, it can carray this token with this header.
var client = new HttpClient();
var token = client.GetAsync("[url that get the token] ");
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");
client.GetAsync("[url that get the authorized resource] ");

JWT token not being validated correctly

I have an ASP.NET Core MVC application that uses JWT for validation
I add the authentication in the startup class, using our token secret in our appsettings file to validate the token.
services.Configure<ApplicationSettings>(Configuration.GetSection("AppSettings"));
var key = System.Text.Encoding.UTF8
.GetBytes(Configuration.GetSection("AppSettings:Token").Value);
services.AddAuthentication(x => {
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(x => {
x.RequireHttpsMetadata = false;
x.SaveToken = false;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false,
ClockSkew = TimeSpan.Zero
};
});
And add the authorization middleware
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors("MyPolicy");
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Now when a user tries to login the following controller method is run, using the same token secret to generate the token.
[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] UserForLoginDto userForLoginDto)
{
var user = await _userManager.FindByNameAsync(userForLoginDto.Username);
var result = await _signInManager
.CheckPasswordSignInAsync(user, userForLoginDto.Password, false);
if (result.Succeeded)
{
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim("UserID",user.Id.ToString())
}),
Expires = DateTime.UtcNow.AddDays(1),
SigningCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8
.GetBytes(appSettings.Token)), SecurityAlgorithms.HmacSha256Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var securityToken = tokenHandler.CreateToken(tokenDescriptor);
var token = tokenHandler.WriteToken(securityToken);
return Ok(new { token });
}
return Unauthorized();
}
So when the user logs in, a token is generated and send back to the client.
At this point I would expect that I could just add [Authorize] attribute to a controller method, and then the MVC framework will look for a valid token in the http headers. So I create a test controller method
[HttpGet]
[Authorize]
public IActionResult Get()
{
return Ok("Test");
}
And send a request that corresponds to the test controller method with the Authorization header set to Bearer <Token> yet I still get a 401 unauthorized.
Can anyone explain why this might happen? Please tell me if you need additional information.
I think it's the matter of using your middleware:
app.UseRouting();
app.UseAuthorization();
app.UseAuthentication();
Could try it in the following way:
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
So first, we use authenticate the user - where the middleware reads the token and inject the identity to http context

.net Core 3 Web API JWT unauthorized

I am beginner in the world of authentication and I am trying to implement a simple example to secure my api.
In my Login action I generate a JWT like:
var claims = new[] {
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("ThIsIsAKeyT03ncrypt!4lw4ysUs3AStr0ng1"));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: "https://localhost:44392/",
audience: "https://localhost:44392/",
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
My controller is tagged as follows:
[ApiController]
[Route("api/[controller]")]
[Authorize]
public class WeatherForecastController : ControllerBase
{
and the StartUp class handles the authentication like:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseAuthentication();
and:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidIssuer = "https://localhost:44392/",
ValidAudience = "https://localhost:44392/",
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("ThIsIsAKeyT03ncrypt!4lw4ysUs3AStr0ng1")),
ValidateLifetime = true
};
});
The problem is that although I am using the same symmetric key, issuer and audience, when testing through postman, the result is always status 401.
Is there a setting/option I am missing? Any help would be welcome
Problem solved by adding
services.AddAuthentication(cfg =>
{
cfg.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
cfg.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
in the StartUp class.

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.

.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!