Is it possible to implement windows and jwt authentication schemes in same project?
I need windows authentication to catch user without any login page and jwt to handle roles with any other page and wep api.
Yes, you can add multiple Authentication schemes to your application. Refer to the following link
I finally got the both working. I didn't find anything solved example on internet, hopefully this would help anyone looking for answers.
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IISDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = "Bearer";
}).AddJwtBearer("Bearer", options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false,
//ValidAudience = "the audience you want to validate",
ValidateIssuer = false,
//ValidIssuer = "the isser you want to validate",
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("myapisecretkey")),
ValidateLifetime = true, //validate the expiration and not before values in the token
ClockSkew = TimeSpan.FromMinutes(5) //5 minute tolerance for the expiration date
};
});
services.AddAuthorization(auth =>
{
auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
.RequireClaim(ClaimTypes.Name, "MyAPIUser").Build());
});
Then select the authentication scheme you want to use on particular controller by decorating it.
[Route("api/MyController")]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class MyController : Controller
Related
I've been using Ocelot lately to build an API Gateway. Are rate limits based on the requester client id? Because i've been asked to build an api gateway in an architecture that will look like this
And all the requests will have the same id since they are passing through the proxy.
I can however, identify the different requesting clients using an header token. So my question is: can i limit the number of request made by a client using the header token rather than the request id? Thanks in advance.
You could use Ocelot as a Rate Limiter based on ClientId.
"RateLimitOptions": {
"DisableRateLimitHeaders": false,
"QuotaExceededMessage": "Customize Tips!",
"HttpStatusCode": 999,
"ClientIdHeader" : "MY-CLIENT-ID"
}
The last line in Ocelot's rate limiting documentation refers to this:
ClientIdHeader - Allows you to specifiy the header that should be used to identify clients. By default it is “ClientId”
You could also implement your own middleware and use Ocelots rate limitng. So You could be able to read other Headers and get your customized client-id:
Just take a look at default rate limiting middleware provided by Ocelot: ClientRateLimitMiddleware.cs
public virtual ClientRequestIdentity SetIdentity(HttpContext httpContext, RateLimitOptions option)
{
var clientId = "client";
if (httpContext.Request.Headers.Keys.Contains(option.ClientIdHeader))
{
clientId = httpContext.Request.Headers[option.ClientIdHeader].First();
}
return new ClientRequestIdentity(
clientId,
httpContext.Request.Path.ToString().ToLowerInvariant(),
httpContext.Request.Method.ToLowerInvariant()
);
}
An easy and good solution for me was to add the "ClientId" in the header as soon as I got the JWT token validation.
// Authentication
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = builder.Configuration.GetSection("OAuthSettings:Authority").Get<string>();
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidAudiences = builder.Configuration.GetSection("OAuthSettings:Audiences").Get<string>().Split(';')
};
options.RequireHttpsMetadata = false;
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
return Task.CompletedTask;
},
OnTokenValidated = context =>
{
// Adding the ClientId in the header
// It is used by the rate limiting
string clientId = context.Principal.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.ClientId).Value;
context.HttpContext.Request.Headers.Add("ClientId", clientId);
return Task.CompletedTask;
},
};
});
I literally read the internet through, tried multiple approaches and so on - with no luck.
I am trying to make a pretty small WebApi project with a few controllers protected by a jwt token.
I generate the token using following code:
var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("may the force"));
var tokenHandler = new JwtSecurityTokenHandler();
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims.ToArray()),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
I have setup the authentication (in Startup.cs) bits like
services.AddAuthentication(x => {
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}
)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("may the force"))
};
});
Using my AuthController I can generate the Token(first code block in this question) - and the Controllers needed to be "protected" is annotated with [Authorize]
If I take the result from AuthController and paste it at https://jwt.io the signature is valid.
I am testing the controllers using postman and setting the request header Authorization to Bearer <the token>
Can anyone point me in the right direction?
Thanks alot!
UPDATE: I misused the jwt.io site initially, thus some of the comments underneath here are no longer valid.
UPDATE 2: Realized that the server tried to use cookie based authentication. Changing the annotation to [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] made the trick - but still not sure why
I have web api project (ASP.Net 4.7) where i am Jwt Bearer Token for authentication and i would like to hook to an event when token is successfully validated call user information endpoint and add custom logic and add claims to identity.
I know we can do something similar with dotnet core https://www.jerriepelser.com/blog/aspnetcore-jwt-saving-bearer-token-as-claim/
Asp.Net 4.x
var configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(issuer + "/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever(), new HttpDocumentRetriever());
var discoveryDocument = Task.Run(() => configurationManager.GetConfigurationAsync()).GetAwaiter().GetResult();
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
TokenValidationParameters = new TokenValidationParameters()
{
ValidAudience = "Any",
ValidIssuer = issuer,
IssuerSigningKeyResolver = (token, securityToken, identifier, parameters) =>
{
return discoveryDocument.SigningKeys;
}
},
});
Please advise ?
This question already has answers here:
JWT Token authentication, expired tokens still working, .net core Web Api
(4 answers)
Closed 1 year ago.
I am trying to implement Token Based Authentication through refresh tokens and JWT in .NET Core 2.1.
This is how I am implementing the JWT Token:
Startup.cs
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 = Configuration["Jwt:Site"],
ValidIssuer = Configuration["Jwt:Site"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:SigningKey"]))
};
options.Events = new JwtBearerEvents
{
OnAuthenticationFailed = context =>
{
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("Token-Expired", "true");
}
return Task.CompletedTask;
}
};
});
Token Generation:
var jwt = new JwtSecurityToken(
issuer: _configuration["Jwt:Site"],
audience: _configuration["Jwt:Site"],
expires: DateTime.UtcNow.AddMinutes(1),
signingCredentials: new SigningCredentials(signinKey, SecurityAlgorithms.HmacSha256)
);
return new TokenReturnViewModel()
{
token = new JwtSecurityTokenHandler().WriteToken(jwt),
expiration = jwt.ValidTo,
currentTime = DateTime.UtcNow
};
I am getting he correct values in Response.
But after a minute I set the same token for authorization in Postman and it works.
If the token has expired it shouldn't.
I am using bearer tokens as authentication.
What am I doing wrong? Need direction.
There is a token validation parameter called ClockSkew, it gets or sets the clock skew to apply when validating a time. The default value of ClockSkew is 5 minutes. That means if you haven't set it, your token will be still valid for up to 5 minutes.
If you want to expire your token on the exact time; you'd need to set ClockSkew to zero as follows,
options.TokenValidationParameters = new TokenValidationParameters()
{
//other settings
ClockSkew = TimeSpan.Zero
};
Another way, create custom AuthorizationFilter and check it manually.
var principal = ApiTokenHelper.GetPrincipalFromToken(token);
var expClaim = principal.Claims.First(x => x.Type == "exp").Value;
var tokenExpiryTime = Convert.ToDouble(expClaim).UnixTimeStampToDateTime();
if (tokenExpiryTime < DateTime.UtcNow)
{
//return token expired
}
Here, GetPrincipalFromToken is a custom method of the ApiTokenHelper class, and it will return the ClaimsPrincipal value that you've stored while issuing a token.
I'm trying to create an ASP.Net Core app which contains both MVC and API controllers in single project. For authenticating I use IdentityServer4.
Currently when the user is not authorized for a request he is always redirected to Account/AccessDenied path regardless of authentication scheme. But I want to keep this behavior only for MVC controllers. For API requests I just want to return 403 status code.
Configuration:
services
.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddInMemoryApiResources(ApiResourceProvider.GetAllResources())
.AddAspNetIdentity<ApplicationUser>()
.AddInMemoryClients(clientStore.AllClients);
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = tokenAuth.Issuer,
ValidateAudience = true,
ValidAudience = tokenAuth.Audience,
ValidateLifetime = true,
IssuerSigningKey = tokenAuth.SecurityKey,
ValidateIssuerSigningKey = true
};
});
How can I achieve that?
If you're using cookies you can override the AccessDeniedPath like the following
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
}).AddCookie("Cookies", (options) =>
{
options.AccessDeniedPath = "/Authorization/AccessDenied";
})
Actually it was quite simple but not obvious: it's needed to explicitly specify authentication scheme in [Authorize] attribute.
I tried to specify [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] on a controller level but it seems that setting [Authorize(Roles = RoleHelper.MobileWorker)] on the action level overrides the auth schema.
So I created a custom attribute which is derived from Authorize but with properly set auth scheme.