Validating ADAL JWT token in C# REST service - c#

I have a web application which uses the ADAL library for authentication through Azure Active Directory.
This web application makes a call to a C# REST service by passing the ADAL token string as a parameter. In my REST service, I want to validate this token. If the token is valid only then the service will perform the operation.
I searched a lot but could not find a way to validate the JWT token in my rest service. Can you guys please help me on this?

You have two options:
1. Use OWIN middleware
Use middleware that will handle token validation for you. A common case will be the OWIN middleware, which does all the magic for you. Usually, this is the best approach, as it allows you to focus your code on the business logic for your API, not on low-level token validation. For a sample REST API that uses OWIN, check out these two samples:
https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect
https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnet5
2. Manual JWT validation
You can use the JSON Web Token Handler for ASP.NET to do manual JWT token validation. (Ok, so it's not entirely manual, but it is manually invoked.) There's also a sample for this:
https://github.com/Azure-Samples/active-directory-dotnet-webapi-manual-jwt-validation (the actual JWT validation happens in Global.asax.cs and looks something like this:
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
TokenValidationParameters validationParameters = new TokenValidationParameters
{
ValidAudience = audience,
ValidIssuer = issuer,
IssuerSigningTokens = signingTokens,
CertificateValidator = X509CertificateValidator.None
};
try
{
// Validate token.
SecurityToken validatedToken = new JwtSecurityToken();
ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(jwtToken, validationParameters, out validatedToken);
// Do other validation things, like making claims available to controller...
}
catch (SecurityTokenValidationException)
{
// Token validation failed
HttpResponseMessage response = BuildResponseErrorMessage(HttpStatusCode.Unauthorized);
return response;
}

Related

Is it okay to embed username in BEARER Authorization Header?

I have an API endpoint created using Web API to create a security Token. So the user passes username:password in a Basic Authorization header. The username/password is verified and a Json Web Token is returned.
Now all my other endpoints that do GETs or POSTs I will pass in the JWT in the Authorization header as a BEARER type. I know typically this is BEARER + (jwt) but would it be just as okay to pass
BEARER + username:(jwt)
The reason I want to pass the username:(jwt) is when I verify the jwt I also want to pull out the username from the jwt claim and compare it to the username passed in the auth header as an extra check.
Does this approach sound good or should I forget about doing the username check altogether because it doesn't add any extra security?
There is nothing preventing you from adding the username outside of the token, however
you can add as many claims to your token as you need and can include the username. These claims can be retrieved from your client application or Web API through the IHttpContextAccessor.
In your client/API you can then do something like this to retrieve the claims:
List<Claim> claims = _context.Request.HttpContext.User.Claims.ToList();
Where _context is of type IHttpContextAccessor.
This obtains the Subject property of your encoded token, which is a ClaimsIdentity consisting of a list of the Claims that have been added when creating your token.
You can add the username outside of the token, however everything you need can be stored more securely and retrieved from the token itself after the client/API has authenticated the bearer token.
In addition, you can use the claims to add extra authorization when accessing other classes within your client/API.
All the other claims types like sub, iat and so on are properties within the token after it is authenticated on your client/API end. What you need to do during token creation is to use the SecurityTokenDescriptor to create the token descriptor like this (abbreviated):
SecurityTokenDescriptor descriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[] {
new Claim(ClaimTypes.Name, username),
new Claim(JwtRegisteredClaimNames.Sub, username)}),
Expires = DateTime.Now.AddMinutes(expiration_in_minutes),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
SecurityAlgorithms.HmacSha256Signature)
};
You will need to ensure the namespaces are in your source:
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
When I run this to generate the token and then decode the token in https://jwt.io/ in get:
{
"unique_name": "usernam#xxxx.xxx",
"sub": "usernam#xxxx.xxx",
"nbf": 1622285741,
"exp": 1622287503,
"iat": 1622285741
}
Adding the claim using JwtRegisteredClaimNames.Sub exposes the sub in the token.
Try that and see if it works.
You can send the username/userid in the sub claim.
The claims inside of the token are signed. The username/userid(sub) is signed, no need to verify if the username/userid is ok/valid.
In your case the BEARER Username:Token
Username(No signed, can be changed, can't be validated):
Token(claims/header/signature - all content is signed/validated)>
Username/userid outside token don't add extra security.
System.IdentityModel.Tokens.Jwt.JwtRegisteredClaimNames.Sub to avoid write "sub" in the claim name. This namespace is located in System.IdentityModel.Tokens.Jwt nuget package.

.Net Core API JWT Token Validation

Implemented the JWT Bearer Token validation in .Net Core WEB API as mentioned below:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(opt =>
{
opt.Audience = Configuration["AAD:ResourceId"];
opt.Authority = $"{Configuration["AAD:Instance"]}{Configuration["AAD:TenantId"]}";
});
Doubt here is the above mentioned code will validate only the audience and authority ? or it will validate all the parameters like expiration and signature etc. ?
Do we need to validate the signature explicitly to check the payload has been tampered ?
I think you're looking for this:
https://zhiliaxu.github.io/how-do-aspnet-core-services-validate-jwt-signature-signed-by-aad.html
Here zhiliaxu explains in details how and what is actually validated when using .AddJwtBearer() and their conclusions are:
Now it is clear that
JWT signature is validated without providing any key or certification
in our service’s source code.
JWT signing key is retrieved from the well-known URL https://login.microsoftonline.com/common/discovery/keys, based on
JwtBearerOptions.Authority property.
The signing key is cached in the JwtBearerHandler singleton instance, and so our ASP.NET Core service only needs to retrieve it
once throughout its lifecycle.
Also based on this article we can take a look at the ValidateToken() documentation on MSDN: https://learn.microsoft.com/en-us/dotnet/api/system.identitymodel.tokens.jwt.jwtsecuritytokenhandler.validatetoken?view=azure-dotnet Where you can find the different exceptions the method throws:
SecurityTokenDecryptionFailedException: token was a JWE was not able to be decrypted.
SecurityTokenEncryptionKeyNotFoundException: token 'kid' header claim is not null AND decryption fails.
SecurityTokenException: token 'enc' header claim is null or empty.
SecurityTokenExpiredException: token 'exp' claim is < DateTime.UtcNow.
SecurityTokenInvalidAudienceException: token 'aud' claim did not match either ValidAudience or one of ValidAudiences.
SecurityTokenInvalidLifetimeException: token 'nbf' claim is > 'exp' claim.
SecurityTokenInvalidSignatureException: token.signature is not properly formatted.
SecurityTokenNoExpirationException: TokenReplayCache is not null and expirationTime.HasValue is false. When a TokenReplayCache is set, tokens require an expiration time.
SecurityTokenNotYetValidException: token 'nbf' claim is > DateTime.UtcNow.
SecurityTokenReplayAddFailedException: token could not be added to the TokenReplayCache.
SecurityTokenReplayDetectedException: token is found in the cache.
It will validate issuer, audience and lifetime by default. There's a bunch of properties in TokenValidationParameters. If you create a new instance of that class, you'll see which fields are set to true/false. Or, you could add the following to your code, breakpoint and investigate yourself.
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>
{ ...
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false, ...
}; ..
} ...
NB authority and issuer are pretty much the same concept. Also, mind the difference between ValidIssuer and ValidateIssuer.

Why IdentityModel JWT library generates the same token when the same Expires is provided?

I have the following code in my application to generate a JWT for authentication purposes in a REST API:
private string GenerateToken(List<Claim> identityFields)
{
var key = Convert.FromBase64String(__SECRET);
var securityKey = new SymmetricSecurityKey(key);
var descriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(identityFields.ToArray()),
Expires = DateTime.UtcNow.AddDays(1),
SigningCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature)
};
var handler = new JwtSecurityTokenHandler();
var token = handler.CreateJwtSecurityToken(descriptor);
return handler.WriteToken(token);
}
The "identityFields" parameter is an object with values from the user (which are not relevant here).
My main problem is that, when I sent two request to that method in the same second (I mean, for example, 2019-01-23 14:57:59.827 and 2019-01-23 14:57:59.350), it generates the same JWT for both session (taking in mind that the "identityFields are the same, of course), because the "Expires" property doesn't concern about the milliseconds.
How can solve that issue?
I'm using the official JWT library (System.IdentityModel.Tokens.Jwt), is not custom code.
Thank you!
I recommend a look at https://blogs.msdn.microsoft.com/webdev/2016/10/27/bearer-token-authentication-in-asp-net-core/
Depending on your specific use case you should be able to add custom claims to your token so that you can extrac the needed information directly from the token.
If you need to keep the information secret (since anyone can decode a JWT token) you could add a unique identifier to as a custom claim and use that to look up information in your database.

How to issue and consume JWT using ServiceStack's JwtAuthProvider

Looking at the JwtAuthProvider documentation for ServiceStack, it seems that a lot of JWT functionality is given out-of-the-box. However I really need to look at some working example. I could not find any in the example directory for ServiceStack.
What I'd like to see, is an example code that shows:
How to issue a token with some claims.
How to decode the token and inspect the claims.
Just using some "Hello world" service. Does anyone have some code that shows this or know where to look?
Ideally, the signing would use RSA, but right now this is not that important...
Thanks.
The JWT AuthProvider is what Issues the JWT token which it populates based on the User Session. You can add your own metadata in the tokens and inspect it with the CreatePayloadFilter and PopulateSessionFilter.
JWT is enabled in both the AngularJS http://techstacks.io Example by just making a call to /session-to-token after the user successfully authenticates with their OAuth Provider, e.g:
$http.post("/session-to-token");
This converts their currently authenticated session into a JWT Token which it uses for future subsequent requests.
Likewise JWT is also used in http://gistlyn.com which uses a Customized JwtAuthProvider to embed the Github OAuth Access Token Secret into the JWT Token then uses the PopulateSessionFilter to extract it from the JWT Token and populate it back in the Users Session:
appHost.Plugins.Add(new AuthFeature(() => new AuthUserSession(),
new IAuthProvider[] {
new GithubAuthProvider(appHost.AppSettings),
//Use JWT so sessions survive across AppDomain restarts, redeployments, etc
new JwtAuthProvider(appHost.AppSettings)
{
CreatePayloadFilter = (payload, session) =>
{
var githubAuth = session.ProviderOAuthAccess.Safe()
.FirstOrDefault(x => x.Provider == "github");
payload["ats"] = githubAuth != null
? githubAuth.AccessTokenSecret : null;
},
PopulateSessionFilter = (session, obj, req) =>
{
session.ProviderOAuthAccess = new List<IAuthTokens>
{
new AuthTokens { Provider = "github", AccessTokenSecret = obj["ats"] }
};
}
},
}));
Gistlyn uses a similar approach to TechStacks to using JWT Tokens by calling /session-to-token after the User has authenticated with Github OAuth using JavaScript's new fetch API
fetch("/session-to-token", { method:"POST", credentials:"include" });
JWT Stateless Auth Tests
For other examples you can look at JWT RSA Tests which uses CreateJwtPayload which shows examples of manually creating JWT Tokens in code.

Verify Access Token - Asp.Net Identity

I'm using ASP.Net Identity to implement external logins. After user logins in with Google I get google's external access token. I then make a second api call to ObtainLocalAccessToken() which trades the external access token for a new local one.
ObtainLocalAccessToken() calls VerifyExternalAccessToken() which verifies the external access token with the provider by manually making http calls and parsing the user_id.
How can I leverage ASP.NET identity to remove the entire method VerifyExternalAccessToken()?
I believe that's what [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)] is for isn't it? I want to decorate ObtainLocalAccessToken() endpoint with that attribute and send the external_access_token in the header ({'Authorization' : 'Bearer xxx' }), and it should populate User.Identity without needing to manually verify the external access token? I believe that’s the purpose, however I cannot get it working. I send a valid external access token from google and it gets rejected with a 401.
I have this line in Startup.Auth btw:
app.UseOAuthBearerTokens(new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(),
AuthorizeEndpointPath = new PathString("/AccountApi/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
});
Alternatively, it is possible to use "/Token" endpoint to trade an external access token for a local one? Which approach is correct?
Studying the implementation by Taiseer Joudeh
the /ExternalLogin endpoint replaces the OWIN Authentication Challenge.
The AngularJS LoginController makes a call to the authService.obtainAccessToken when an externally authenticated user has not been found in Identity Provider:
if (fragment.haslocalaccount == 'False') {
...
}
else {
//Obtain access token and redirect to orders
var externalData = { provider: fragment.provider,
externalAccessToken: fragment.external_access_token };
authService.obtainAccessToken(externalData).then(function (response) {
$location.path('/orders');
It uses the VerifyExternalAccessToken to perform a reverse lookup against Google and Facebook API's to get claim info for the bearer token.
if (provider == "Facebook")
{
var appToken = "xxxxxx";
verifyTokenEndPoint = string.Format("https://graph.facebook.com/debug_token?input_token={0}&access_token={1}", accessToken, appToken);
}
else if (provider == "Google")
{
verifyTokenEndPoint = string.Format("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token={0}", accessToken);
}
else
{
return null;
}
If token is found, it returns a new ASP.NET bearer token
var accessTokenResponse = GenerateLocalAccessTokenResponse(user.UserName);
return Ok(accessTokenResponse);
With [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)] the OWIN Middleware uses the external bearer token to access the 3rd party's Cookie and Register a new account (Or find existing).
OWIN Middleware cannot be configured to accept external bearer token instead of local authority tokens. External bearer tokens are only used for Authentication and Registration.

Categories