401 un-authorized message using Auth0 authorization in ASP.NET Core - asp.net-core

I started doing angular2 + asp.net core application, started implementing Auth0. I created client application and a user.
Here is client application setup, provided url for Api:
User login works fine:
Now I have an api with this controller:
[Route("api")]
public class PingController : Controller
{
[Authorize]
[HttpGet]
[Route("ping/secure")]
public string PingSecured()
{
return "All good. You only get this message if you are authenticated.";
}
}
And in startup.cs I tried implementing like this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
var options = new JwtBearerOptions
{
Audience = "uUdThU122xYPugR8gLoNTr3HdJ6sWvQV",
Authority = "https://dntquitpls.eu.auth0.com/",
};
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
};
app.UseJwtBearerAuthentication(options);
app.UseCors(builder =>
builder.WithOrigins("http://localhost:61290/").AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
);
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapWebApiRoute("defaultApi",
"api/{controller}/{id?}");
});
}
And it does not work getting this:
Api part is done by Auth0 Api tutorial, for example if I create a Api and there is a test Bearer token it works with that in api, also i configure Startup.cs file by that Api, but unfortunately with my Bearer token from response does not work.
Please any ideas why it does not work and I am not getting authorized?

Found a solution, now it works, the problem was in Startup.cs file in options HS256 Encoding, which is used for UseJwtBearerAuthentication, solution:
var keyAsBytes = Encoding.ASCII.GetBytes("CLIENT_SECRET");
var options = new JwtBearerOptions
{
TokenValidationParameters =
{
ValidIssuer = "https://dntquitpls.eu.auth0.com/",
ValidAudience = "uUdThU122xYPugR8gLoNTr3HdJ6sWvQV",
IssuerSigningKey = new SymmetricSecurityKey(keyAsBytes)
}
};
app.UseJwtBearerAuthentication(options);
source:
http://www.jerriepelser.com/blog/using-roles-with-the-jwt-middleware/
if you want to work with RS256 encoding use this:
var certificationData = Configuration["auth0:certificate"];
var certificate = new X509Certificate2(Convert.FromBase64String(certificationData));
var options = new JwtBearerOptions()
{
Audience = Configuration["auth0:clientId"],
Authority = Configuration["auth0:authority"],
AutomaticChallenge = true,
AutomaticAuthenticate = true,
TokenValidationParameters = {
ValidIssuer = Configuration["auth0:authority"],
ValidAudience = Configuration["auth0:clientId"],
IssuerSigningKey = new X509SecurityKey(certificate)
}
};
app.UseJwtBearerAuthentication(options);

Related

Authenticate API in .net core using ping identity OAuth2.0

Problem Statement : I want to secure APIs using ping identity OAuth 2.0. I am following this blog but I get 401.
I have configured in postman tool with OAuth2.0 with details provided by ping identity team and I'm able to generate the token but the same token when I copy paste and send it as Bearer, I get 401 in the API.
I doubt if I'm giving the wrong callback URL. If my API URL is say http://web.abc.com/_api/home/userinfo then what should be my callback URL?
NOTE : I am not using this solution in the browser and directly trying to secure the APIs. May be my approach itself is not correct. Let me know if any better solution.
EDIT :
Startup.cs looks like this :
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)
{
string x509PublicCert = #"XXXXXXXXXXX";
var byteCert = Convert.FromBase64String(x509PublicCert);
var x509Cert = new X509Certificate2(byteCert);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Audience = "http://localhost:65180/";//Configuration["Audience"]; //"http://localhost:9000/";
options.Authority = "https://myloginqa.xyz.com:8080/"; //Configuration["Authority"]; // "https://idp.yourcompany.com:5000/";
options.TokenValidationParameters = new TokenValidationParameters
{
// Validate the JWT Audience
ValidateIssuerSigningKey = true,
IssuerSigningKey = new X509SecurityKey(x509Cert),
ValidateIssuer = true,
ValidIssuer = "myloginqa.xyz.com",//Configuration["Issuer"], //idp.yourcompany.com
ValidateAudience = false,
ValidateLifetime = true,
// If you want to allow a certain amount of clock drift, set that here:
ClockSkew = TimeSpan.Zero
};
});
services.AddControllersWithViews();
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
// 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();
}
else
{
app.UseExceptionHandler("/Error");
}
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors("CorsApi");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
}
Controller looks like this :
[EnableCors("CorsApi")]
//[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Authorize]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase

how to use one jwt token from One Api for Authentication all Apis in local enterprise application asp.net core (not use idedentityserver)

I need run Api Authentication server(use jwt) for all apis in local application .how to create it with out use identityserver ?
How can the initial token be validated on other Apis?
How to send the received token to the first server for validation and received the answer initial this token to this server ?
You could refer to the following steps to use JWT Authentication In ASP.NET Core.
Configure the authentication schema with JWT bearer options.
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:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
};
});
services.AddControllersWithViews();
}
In this example, I have stored these values in appsettings.json file.
{
"Jwt": {
"Key": "ThisismySecretKey",
"Issuer": "Test.com"
}
}
Call the app.UseAuthentication() method in the Configure method of startup class.
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
Generate JSON Web Token
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
using Test.Models;
namespace Test.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class LoginController : ControllerBase
{
private IConfiguration _config;
public LoginController(IConfiguration config)
{
_config = config;
}
[AllowAnonymous]
[HttpPost]
public IActionResult Login([FromBody] UserModel login)
{
IActionResult response = Unauthorized();
var user = AuthenticateUser(login);
if (user != null)
{
var tokenString = GenerateJSONWebToken(user);
response = Ok(new { token = tokenString });
}
return response;
}
private string GenerateJSONWebToken(UserModel userInfo)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[] {
new Claim(JwtRegisteredClaimNames.Sub, userInfo.Username),
new Claim(JwtRegisteredClaimNames.Email, userInfo.EmailAddress),
new Claim("DateOfJoing", userInfo.DateOfJoing.ToString("yyyy-MM-dd")),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
};
var token = new JwtSecurityToken(_config["Jwt:Issuer"],
_config["Jwt:Issuer"],
claims,
expires: DateTime.Now.AddMinutes(120),
signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
private UserModel AuthenticateUser(UserModel login)
{
UserModel user = null;
//Validate the User Credentials
//Demo Purpose, I have Passed HardCoded User Information
if (login.Username == "Jignesh")
{
user = new UserModel { Username = "Jignesh Trivedi", EmailAddress = "test.btest#gmail.com" };
}
return user;
}
}
}
Then, if you request the "API/login" method to generate the token, you have to passed the following JSON in the request body.
{"username": "Jignesh", "password": "password"}
Then, after getting the JWT token, you could add the "Authorization" property in the request header when you access other API controller.
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJKaWduZXNoIFRyaXZlZGkiLCJlbWFpbCI6InRlc3QuYnRlc3RAZ21haWwuY29tIiwiRGF0ZU9mSm9pbmciOiIwMDAxLTAxLTAxIiwianRpIjoiYzJkNTZjNzQtZTc3Yy00ZmUxLTgyYzAtMzlhYjhmNzFmYzUzIiwiZXhwIjoxNTMyMzU2NjY5LCJpc3MiOiJUZXN0LmNvbSIsImF1ZCI6IlRlc3QuY29tIn0.8hwQ3H9V8mdNYrFZSjbCpWSyR1CNyDYHcGf6GqqCGnY
If you mean using one JWT token for multiple API applications, as far as I know, a JWT token is intended for a certain service or application indicated by the audience (aud) claim. You cannot use the same token for another application or service.
More detail information please check the following links:
JWT Authentication In ASP.NET Core
JWT token for multiple websites

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

How can I implement Bearer Token in MVC 6 API vNext?

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