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.

jwt, only withRESTqueries via URL, where request headerAuthorization : Basic <encrypted user:pass>was needed & if something was wrong about that (pass/name/syntax), it threw 401 to me. - TatranskymedvedAuthorization: Bearer <jwt>format. - cchamberlain