Reputation: 29
Sorry, it's a long message but it's to be clear (I hope) I have followed this article to set up an AuthorizationServerProvider and let anyone, who has a JWT Token, to call a certain API in my code. BUT, when I try to invoke any controller or API Controller method of my MVC Project, I get an Unauthorized message.
This is When I Request the Token (Updated)
This is when I try to Invoke a Method with [authorize attribute]
Here are my ValidateClientAuthentication and GrantResourceOwnerCredentials method:
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security.OAuth;
using System.Security.Claims;
using System.Threading.Tasks;
using MyProject.Models;
using Microsoft.Owin.Security;
public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var allowedOrigin = "*";
//
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { allowedOrigin });
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT"); // maybe this is the problem
// oAuthIdentity.AddClaim(new Claim(ClaimTypes.Role, "User"));
// oAuthIdentity.AddClaim(new Claim(ClaimTypes.Authentication, "AudienceID"));
var ticket = new AuthenticationTicket(oAuthIdentity, null);
context.Validated(ticket);
}
}
In my Startup.Auth.cs I have put two methods to let that Api controllers with an [Authorize]
attribute can be validated with JWT.
Here the partial class:
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Owin.Security.OAuth;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Threading.Tasks;
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(10),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
/*Other Types of Authentication*/
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(3),
Provider = new AuthorizationServerProvider(),
AccessTokenFormat = new CustomJwtFormat("https://localhost:44391")
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
private void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
var issuer = "https://localhost:44391";
string audienceId = ConfigurationManager.AppSettings["AudienceID"]; //its value is "AudienceID"
byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["SecretKey"]);
string[] AllowedAud = new[] { audienceId };
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = AllowedAud,
// IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[],
IssuerSecurityKeyProviders = new IIssuerSecurityKeyProvider[]
{
new SymmetricKeyIssuerSecurityKeyProvider(issuer, audienceSecret)
}
}) ;
}
}
I invoke these methods in ConfigureAuth(IAppBuilder app). So after all this, I can't understand why I am not able to be authorized. Any Idea?
If this can help:
I am using Microsoft.Owin:Security.Jwt v4.1.1
I generate The token with this method:
using Microsoft.Owin.Security;
using System;
using System.Configuration;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.IdentityModel.Tokens;
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private readonly string _issuer = string.Empty;
public CustomJwtFormat(string issuer)
{
_issuer = issuer;
}
/*This Generate JWT*/
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
string username = data.Identity.Name;
string audienceId = ConfigurationManager.AppSettings["AudienceID"]; // "AudienceID"
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["SecretKey"];
var keyByteArray = Convert.FromBase64String(symmetricKeyAsBase64);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var securityKey = new SymmetricSecurityKey(keyByteArray);
var signingCredentials = new SigningCredentials(securityKey, algorithm: SecurityAlgorithms.HmacSha256Signature);
var token = new JwtSecurityToken(issuer:_issuer, audience: audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingCredentials) ;
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
public AuthenticationTicket Unprotect(string protectedText)
{
throw new NotImplementedException();
}
}
This is The StartUp
using Microsoft.Owin;
using Owin;
using System.Web.Http;
[assembly: OwinStartupAttribute(typeof(MyProject.Startup))]
namespace MyProject
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
var config = new HttpConfiguration();
WebApiConfig.Register(config);
app.UseWebApi(config);
}
}
}
Upvotes: 2
Views: 3916
Reputation: 1726
Unless specifically configured otherwise, there are some mandatory checks that happen as part of token authentication.
You should always double check your configuration for 1) and 2), use a token viewer like https://jwt.ms/ to understand the payload.
From looking at that, I can see your audience in your token is for AudienceId
{
"alg": "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
"typ": "JWT"
}.{
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "199c43cc-c189-4d72-a21e-0c4828f37c8f",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "[email protected]",
"http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider": "ASP.NET Identity",
"AspNet.Identity.SecurityStamp": "5cb5b86f-9580-44eb-9a8f-a188262d849d",
"nbf": 1603013411,
"exp": 1603013591,
"iss": "https://localhost:44391",
"aud": "AudienceID"
}.[Signature]
At your token validation parameters, you're saying
string audienceId = ConfigurationManager.AppSettings["ClientID"];
You've mentioned that this value is AccountTest, however your token has the value AudienceID. For this to work, the value of your app setting ClientID must be AudienceID. Make sure these 2 values match - the aud claim value in your token, and what you are setting for AllowedAudiences in config.
Your validation settings must be exactly as is what is in the token payload, or the request will be rejected. You can add some logging to the validation of the token to find out exactly what's being rejected, have a look at this link
https://stackoverflow.com/a/52370255/1538039
Upvotes: 2