I'm trying to create Jwt token authorization. For this purpose I have issuer part with the code like that:
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"*"}); Users user; using (var db = new UserStore()) { user = Task.Run(()=> db.FindUser(context.UserName, context.Password, context.ClientId)).Result; } if (user == null) { context.SetError("invalid_grant", "The user name or password is incorrect"); return Task.FromResult<object>(null); } var identity = new ClaimsIdentity("JWT"); identity.AddClaim(new Claim(ClaimTypes.Name, user.Email)); identity.AddClaim(new Claim("sub", context.UserName)); identity.AddClaim(new Claim(ClaimTypes.Role, user.Roles.Name)); var props = new AuthenticationProperties(new Dictionary<string, string> { { "audience", context.ClientId ?? string.Empty } }); var ticket = new AuthenticationTicket(identity, props); context.Validated(ticket); return Task.FromResult<object>(null); }
And "resource" part that should accept bearer token:
public void ConfigureOAuth(IAppBuilder app) { var issuer = SiteGlobal.Issuer; var audience = SiteGlobal.Audience; var secret = TextEncodings.Base64Url.Decode(SiteGlobal.Secret); app.UseJwtBearerAuthentication( new JwtBearerAuthenticationOptions { AuthenticationMode = AuthenticationMode.Active, AllowedAudiences = new[] { audience }, IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[] { new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret) } }); }
As far as I can see issued token are valid (I did validation on jwt.io), so the problem is somehwere else. When I'm sending token in Postman with the call to controller protected by [Authorize]
attribute it always return 401 code. Could you please advise how to fix this?
P.S. This is how I implement custom Jwt fortmat:
public string Protect(AuthenticationTicket data) { if (data == null) { throw new ArgumentNullException("data"); } string audienceId = data.Properties.Dictionary.ContainsKey(AudiencePropertyKey) ? data.Properties.Dictionary[AudiencePropertyKey] : null; if (string.IsNullOrWhiteSpace(audienceId)) throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience"); Audience audience; using (var store = new AudienceStore()) { audience = Task.Run(()=> store.FindAudience(audienceId)).Result; } var symmetricKeyAsBase64 = audience.Base64Secret; var signingKey = new InMemorySymmetricSecurityKey(Encoding.UTF8.GetBytes(symmetricKeyAsBase64)); var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256Signature, SecurityAlgorithms.Sha256Digest); var issued = data.Properties.IssuedUtc; var expires = data.Properties.ExpiresUtc; var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingCredentials); var handler = new JwtSecurityTokenHandler(); var jwt = handler.WriteToken(token); return jwt; }
P.S. Guys, I'm so sorry, but I forgot to explain that "issuer" part of code that's standalone application, meanwhile "audience" is protected web api. That's two different appliactions running independently.
2 Answers
Answers 1
In Postman ensure you are sending the authorization header using the following format:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
Ensure that you leave the Authorization tab set to Type: No Auth
.
If you continue to have issues, set a breakpoint in your GrantResourceOwnerCredentials
and see if it gets to that point. Also consider overriding the ValidateClientAuthentication method of OAuthAuthorizationServerProvider
which should get called prior to GrantResourceOwnerCredentials
if you want to debug earlier in the chain of events.
Answers 2
I have just tried to run demo project mentioned in SON Web Token in ASP.NET Web API 2 using Owin and all worked as expected.
I noticed that your implementation of Protect
method differs quite a bit. I would suggest you to compare your implementation to an example given in the article. Try make that work first.
Also please make sure that issuer, audience and secret are same on both servers.
If you provide complete source code I can try to investigate more.
0 comments:
Post a Comment