14
\$\begingroup\$

Please review my code for bearer token (JWT) authentication of Web API 2 (Self Hosted using OWIN)

Are there any security issues in the implementation?

Quick overview:

  • Token creation and validation using JWT Handler
  • Symmetric key encryption
  • CORS support not yet checked for the authorization header
  • Web traffic will be on SSL.
  • The key cannot be auto-generated as it will break during a load balanced scenario. Can I save the key in config? Or switch to X509 certificates?

This is the main class to create and validate tokens:

public class TokenManager
{
 public static string CreateJwtToken(string userName, string role)
 {
 var claimList = new List<Claim>()
 {
 new Claim(ClaimTypes.Name, userName),
 new Claim(ClaimTypes.Role, role) //Not sure what this is for
 };
 var tokenHandler = new JwtSecurityTokenHandler() { RequireExpirationTime = true };
 var sSKey = new InMemorySymmetricSecurityKey(SecurityConstants.KeyForHmacSha256);
 var jwtToken = tokenHandler.CreateToken(
 makeSecurityTokenDescriptor(sSKey, claimList));
 return tokenHandler.WriteToken(jwtToken);
 }
 public static ClaimsPrincipal ValidateJwtToken(string jwtToken)
 {
 var tokenHandler = new JwtSecurityTokenHandler() { RequireExpirationTime = true };
 // Parse JWT from the Base64UrlEncoded wire form 
 //(<Base64UrlEncoded header>.<Base64UrlEncoded body>.<signature>)
 JwtSecurityToken parsedJwt = tokenHandler.ReadToken(jwtToken) as JwtSecurityToken;
 TokenValidationParameters validationParams =
 new TokenValidationParameters()
 {
 AllowedAudience = SecurityConstants.TokenAudience,
 ValidIssuer = SecurityConstants.TokenIssuer,
 ValidateIssuer = true,
 SigningToken = new BinarySecretSecurityToken(SecurityConstants.KeyForHmacSha256),
 };
 return tokenHandler.ValidateToken(parsedJwt, validationParams);
 }
 private static SecurityTokenDescriptor makeSecurityTokenDescriptor(
 InMemorySymmetricSecurityKey sSKey, List<Claim> claimList)
 {
 var now = DateTime.UtcNow;
 Claim[] claims = claimList.ToArray();
 return new SecurityTokenDescriptor
 {
 Subject = new ClaimsIdentity(claims),
 TokenIssuerName = SecurityConstants.TokenIssuer,
 AppliesToAddress = SecurityConstants.TokenAudience,
 Lifetime = new Lifetime(now, now.AddMinutes(SecurityConstants.TokenLifetimeMinutes)),
 SigningCredentials = new SigningCredentials(sSKey,
 "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
 "http://www.w3.org/2001/04/xmlenc#sha256"),
 };
 }
}

I have a message handler to intercept the requests and I verify the validity of token except for the route for log in, using TokenManager.ValidateJwtToken() above.

To create the token, in the LoginController, I have the following code:

[Route("login")]
[HttpPost]
public HttpResponseMessage Login(LoginBindingModel login)
{
 if (login.Username == "admin" && login.Password == "password") //Do real auth
 {
 string role = "Librarian";
 var jwtToken = TokenManager.CreateJwtToken(login.Username, role);
 return new HttpResponseMessage(HttpStatusCode.OK)
 {
 Content = new ObjectContent<object>(new
 {
 UserName = login.Username,
 Roles = role,
 AccessToken = jwtToken
 }, Configuration.Formatters.JsonFormatter)
 };
 }
 return new HttpResponseMessage(HttpStatusCode.BadRequest);
}

The full working code is available here and the instructions to run the sample are in the Wiki.

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Apr 1, 2014 at 18:57
\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

Instead of keeping KEY in config, I would keep it with user records. A unique key for each user.

I admit, I don't get why creating keys dynamically would break the load balancing scenario. We can have a key created at the back-end where we have a single service serving all the load balances servers (such as a database).

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
answered Jun 26, 2014 at 23:03
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.