not check Token validation in Asp core 3 - c#

i need to check token Validation with this :
public static void AddJWTAuthnticationInjection(this IServiceCollection services,SiteSetting siteSetting)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
var securityKey = Encoding.UTF8.GetBytes(siteSetting.JwtSetting.SecretKey);
var ValidatePrameters = new TokenValidationParameters
{
//Tlorance for Expire Time and Befor Time of Token .
ClockSkew = TimeSpan.Zero,
RequireSignedTokens = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(securityKey),
// I Need Check Expire Token or Not
RequireExpirationTime = true,
ValidateLifetime = true,
ValidateAudience = true,
ValidAudience = siteSetting.JwtSetting.Audience,
ValidateIssuer = true,
ValidIssuer = siteSetting.JwtSetting.Issuer
};
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = ValidatePrameters;
});
}
and i use this middlware in project :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseCors(builder => builder
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed((host) => true)
.AllowCredentials()
);
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
and this is my services :
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddFluentValidation(cfg => cfg.RegisterValidatorsFromAssemblyContaining<CreateRoleValidator>());
services.Configure<SiteSetting>(Configuration.GetSection(nameof(SiteSetting)));
services.AddControllers().AddControllersAsServices();
services.AddContext(Configuration);
services.AddLoginngBehavior();
services.RegisterRedis(Configuration);
services.AddMediatR();
services.AddCors();
services.Injection();
**services.AddJWTAuthnticationInjection(_siteSetting);**
}
but when i send the request with tokenin this controller :
[Authorize]
[Pemission("مدیریت نقش ها")]
public class RoleController : BaseController
{
[HttpGet]
[Authorize]
[Pemission("لیست نقش ها")]
public async Task<ReturnResult<IList<Role>>> GetRoles()
{
var result = await mediator.Send(new GetAllRoleQuery());
if (result.Success)
{
return Ok(result.Result);
}
return BadRequest(result.ErrorMessage);
}
}
when i start the project it got this this service AddJWTAuthnticationInjection but when i send a request it not checked it .
it not checked the token Validation . and show me UnAuthorize . whats the problem ? how can i solve the problem ???

Nothing in your code looks to jump out as misconfigured, however there are a few things that I check when I have tried to troubleshoot similar issues in the past:
Check WWW-Authenticate Response Header
By default asp.net will add a WWW-Authenticate header which can reveal what is failing. It can help you track down the issues (e.g. is the key invalid? Or the audience?). The header value will be something like Bearer error="invalid_token", error_description="The token is expired".
Is the token valid?
Copy and paste your token into jwt.io. Is the expiry what you expect? Check issuer/audience etc.
Check Authentication Events
JwtBearerOptions has an Events property that can be used to hook into different events and can help track down issues. Below is an example of wiring these up, adding a breakpoint or logging from within each event can be very handy.
.AddJwtBearer(options =>
{
options.Events = new JwtBearerEvents {
OnChallenge = context => {
Console.WriteLine("OnChallenge:");
return Task.CompletedTask;
},
OnAuthenticationFailed = context => {
Console.WriteLine("OnAuthenticationFailed:");
return Task.CompletedTask;
},
OnMessageReceived = context => {
Console.WriteLine("OnMessageReceived:");
return Task.CompletedTask;
},
OnTokenValidated = context => {
Console.WriteLine("OnTokenValidated:");
return Task.CompletedTask;
},
};
Turn Off Validation
You have true for all validation events for TokenValidationParameters. Set these to false and then enable each one individually to see which one is causing the issue.

Your code should work It seems your token is invalid. Change some validation parameter values to false like the following code:
var ValidatePrameters = new TokenValidationParameters
{
//Tlorance for Expire Time and Befor Time of Token .
ClockSkew = TimeSpan.Zero,
RequireSignedTokens = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(securityKey),
// I Need Check Expire Token or Not
RequireExpirationTime = true,
ValidateLifetime = false,
ValidateAudience = false,
ValidAudience = siteSetting.JwtSetting.Audience,
ValidateIssuer = false,
ValidIssuer = siteSetting.JwtSetting.Issuer
};
Then check the token's content with the SecurityKey on "jwt.io".
Moreover, if you're using policy-based auth, you should register the "مدیریت نقش ها" policy.

Related

Retrieve claims from JWT authentication on ASP.NET Core MVC

I have inherited an ASP.NET Core 5 MVC application that has integrated the authentication of the users with a third-party identity server, WSO2.
The authentication is working fine, but I'm not able to understand how to retrieve the username of the user that has logged in.
Here is the code:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSession();
services.AddControllersWithViews();
services.AddTransient<IUserRepository, UserRepository>();
services.AddTransient<ITokenService, TokenService>();
services.AddAuthentication(auth =>
{
auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
//auth.DefaultChallengeScheme = 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.AddHttpClient();
}
in the controller I have added:
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme, Roles = "Administrator,Supervisor")]
Is the name and roles found in the JWT token?
If, so then the issue is that OpenIDConnect and Microsoft do not agree about what the name of the 'name' claim should be.
To address this, you need to tell AddJwtBearer, which claim is the 'name' and 'role' claim using:
.AddMyJwtBearer(opt =>
{
...
opt.TokenValidationParameters.RoleClaimType = "roles";
opt.TokenValidationParameters.NameClaimType = "name";

Ocelot Asp.net Core PreAuthentication Middleware

I'm currently using Ocelot as Api Gateway for a micro-services architecture. I have some authenticated reroutes and to be able to use it I declared a authentication Middleware like this :
var authenticationProviderKey = "Authentification";
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(authenticationProviderKey, x =>
{
x.RequireHttpsMetadata = false;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(token.Secret)),
ValidIssuer = token.Issuer,
ValidAudience = token.Audience,
ValidateIssuer = true,
ValidateAudience = true
};
});
I wanted to run some custom validation to implement refresh token workflow, to do so I implemented the preAuthentication Middleware to make so tests :
PreAuthenticationMiddleware = async (ctx, next) =>
{
IEnumerable<string> header;
ctx.DownstreamRequest.Headers.TryGetValues("Authorization", out header);
if (header.FirstOrDefault() != null)
{
if (JwtUtils.ValidateExpirationToken(header.FirstOrDefault()))
{
//On validate refresh token
Console.WriteLine("PreAuthentification Middleware");
Tuple<int, string> credentials = JwtUtils.retrieveInfos(header.FirstOrDefault());
string token = JwtUtils.GenerateToken(credentials.Item1, credentials.Item2);
ctx.DownstreamRequest.Headers.Remove("Authorization");
ctx.DownstreamRequest.Headers.Add("Authorization", token);
await next.Invoke();
}
}
}
From what I understood, when I make an api Call, the preAuthenticate Middleware would be called, and with next.Invoke() my Authentication middleware would be called. The newly generated token in my PreAuthentication middleware is a valid one, but my authentication middleware throws an expiredToken exception even tho he's not. Therefore I think the authentication Middleware is run against the first JWT when the new one has not been yet set to the Authorization Header. Is it the attended behaviour? Or maybe I did not understood correctly the middleware in Ocelot?
Anyway, some help would be much appreciated !
Have a good day,
Lio

How to set JwtBearerOptions after calling function AddJwtBearer(jwtBearerScheme, o => { }); with empty opts in asp.net core?

I'm using Asp.net Core 3.1. While creating a new web project using Visual Studio we select API template and Change Authentication to Individual User Accounts and configure Azure ADB2C options and finally create the project.
In our generated Startup.cs file, we have following function:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
services.AddControllers();
}
The implementation of AddAzureADB2CBearer() can be found here. This implementation has a line of code is as follows:
builder.Services.Configure(scheme, configureOptions);
builder.AddJwtBearer(jwtBearerScheme, o => { });
In the above line, its adding JwtBearer with empty JwtBearerOptions. And Authentication is working perfect. But I want to set some JwtBearerOptions after the following line of code:
services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
Is there any way to configure those options after executing the above two lines? I tried the following lines but nothing worked.
services.Configure<JwtBearerOptions>(options =>
{
options.TokenValidationParameters.ValidateIssuer = false; // accept several tenants (here simplified)
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = AuthenticationFailed
};
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateLifetime = true,
ValidateAudience = true,
ValidAudience = "myAudience"
};
});
Please note that I can use AddJwtBearer function and pass options after setting them. But I want to use Microsoft default implementation. And just need to update my JwtBearerOptions that was passed to AddJwtBearer as an argument.
You can try to override the specific schema after AddAzureADB2CBearer:
services.AddAuthentication(AzureADB2CDefaults.BearerAuthenticationScheme)
.AddAzureADB2CBearer(options => Configuration.Bind("AzureAdB2C", options));
services.Configure<JwtBearerOptions>(AzureADB2CDefaults.JwtBearerAuthenticationScheme, options =>
{
options.TokenValidationParameters.ValidateIssuer = false; // accept several tenants (here simplified)
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = AuthenticationFailed
};
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateLifetime = true,
ValidateAudience = true,
ValidAudience = "myAudience"
};
});

Check jwt token when project start in ASP.NET Core

I need to check jwt Token in Asp Core .
I create this extension method for inject in Service :
public static class AddJWTAuthntication
{
public static void AddJWTAuthnticationInjection(this IServiceCollection services,SiteSetting siteSetting)
{
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
var securityKey = Encoding.UTF8.GetBytes(siteSetting.JwtSetting.SecretKey);
var ValidatePrameters = new TokenValidationParameters
{
//Tlorance for Expire Time and Befor Time of Token .
ClockSkew = TimeSpan.Zero,
RequireSignedTokens = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(securityKey),
// I Need Check Expire Token or Not
RequireExpirationTime = true,
ValidateLifetime = true,
ValidateAudience = true,
ValidAudience = siteSetting.JwtSetting.Audience,
ValidateIssuer = true,
ValidIssuer = siteSetting.JwtSetting.Issuer
};
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = ValidatePrameters;
});
}
}
and use it in service extension in StartUp :
services.AddJWTAuthnticationInjection(_siteSetting);
and this is my Configure :
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseCors(builder => builder
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed((host) => true)
.AllowCredentials()
);
app.UseAuthorization();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Now when I run the project it go to the AddJWTAuthnticationInjection for check validation but when I send the request it not go to AddJWTAuthnticationInjection for check Token Validation .
I need to reverse that, when user send a request it check the Validation of Token .
What's the problem? How can I solve it?
This is not about token validation!
You are setting up the ASP.NET Core's Authentication Middleware with your settings so this process needs to be executed once and it happens at the start-up of your application.
The token validation happens internally in the Authentication Middleware (where you have used app.UseAuthentication() in the Configure method of the StartUp.cs).
So you don't need to worry about the process of validation, you just take care of the settings you did in your AddJWTAuthnticationInjection method.
You have misplaced the Authentication Middleware and Authorization Middleware in your configure method. The Authentication Middleware needs to come before Authorization Middleware like this
app.UseAuthentication();
app.UseAuthorization();
Don't forget to add the [Authorize] Attribute on your controller to enable the token validation

Empty claims from JwtBearer middleware

Using ASP.NET Core 3.1. I want to validate a JWT (and the roles in it).
Startup
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(Configuration);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{
options.MetadataAddress = "https://example.com/.well-known/openid-configuration";
});
services.AddScoped<IAuthorizationHandler, MyRoleHandler>();
}
MyRoleHandler
public class MyRoleHandler : IAuthorizationHandler
{
public Task HandleAsync(AuthorizationHandlerContext context)
{
var claims = context.User.Claims;
return Task.CompletedTask;
}
}
https://example.com/.well-known/openid-configuration
{
"issuer": "https://example.com",
"jwks_uri": "https://example.com/.well-known/openid-configuration/jwks",
"authorization_endpoint": "https://example.com/connect/authorize",
"token_endpoint": "https://example.com/connect/token",
"end_session_endpoint": "https://example.com/connect/endsession",
"check_session_iframe": "https://example.com/connect/checksession",
"device_authorization_endpoint": "https://example.com/connect/deviceauthorization",
"frontchannel_logout_supported": true,
"frontchannel_logout_session_supported": true,
"backchannel_logout_supported": true,
"backchannel_logout_session_supported": true,
"response_types_supported": ["code", "token", "id_token", "id_token token", "code id_token", "code token", "code id_token token"],
"subject_types_supported": ["public"],
"id_token_signing_alg_values_supported": ["RS256"],
"code_challenge_methods_supported": ["plain", "S256"],
"upgrade_endpoint": "https://example.com/connect/upgrade",
"end_session_accesstoken_endpoint": "https://example.com/connect/endsession/accesstoken",
"active_session_endpoint": "https://example.com/connect/activesession"
}
claims is empty. What am I doing wrong here? I was under the impression the JwtBearer middleware will configure itself when given the openid-configuration?
I figured out now that the error was in fact that the TokenValidationParameters must be set correctly. I don't exactly know why, but as soon as I add them in any capacity, the claims are correctly decoded.
So now I added them as follows:
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opts =>
{
opts.Authority = Env.Get("AUTHORITY_BASE_URL");
opts.TokenValidationParameters = new TokenValidationParameters
{
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidIssuer = Env.Get("ALLOWED_ISSUER"),
ValidateAudience = true,
ValidAudience = Env.Get("ALLOWED_AUDIENCE"),
ClockSkew = TimeSpan.FromSeconds(Env.GetDouble("CLOCK_SKEW")),
RoleClaimType = "authorities"
};
});
And now, in my MyRoleHandler, the claims are correctly decoded an I can check them.

Categories