Background:
I am attempting to support an authorization code flow to enable SSO from my app to a third party application.
Now I am stuck on the implementation of the Unprotect method which is supposed to return an AuthenticationTicket.
OAuth2 Server Configuration:
var allowInsecureHttp = bool.Parse(ConfigurationManager.AppSettings["AllowInsecureHttp"]);
var oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = allowInsecureHttp,
TokenEndpointPath = new PathString("/oauth2/token"),
AuthorizeEndpointPath = new PathString("/oauth2/authorize"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new CustomOAuthProvider(HlGlobals.Kernel),
AccessTokenFormat = new CustomJwtFormat(_baseUrl, HlGlobals.Kernel),
AuthorizationCodeProvider = new SimpleAuthenticationTokenProvider(),
AuthorizationCodeFormat = new CustomJwtFormat(_baseUrl, HlGlobals.Kernel)
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(oAuthServerOptions);
JWT Token Generation / Protect method:
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
// Get the client and assign to GUID -- the audience is api this token will be valid against
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
Guid clientId;
bool isValidAudience = Guid.TryParse(audienceId, out clientId);
// Check for a valid Client Guid in the Auth ticket properties
if (!isValidAudience)
{
throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience");
}
// Create the JWT token
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
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, signingKey);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
// Return the JWT Token
return jwt;
}
Finally, the 'Unprotect' method which is responsible for validation of the JWT and returning and authentication ticket:
public AuthenticationTicket Unprotect(string protectedText)
{
string symmetricKeyAsBase64 = ConfigurationManager.AppSettings["as:AudienceSecret"];
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
Guid clientId;
bool isValidAudience = Guid.TryParse(audienceId, out clientId);
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var tokenValidationParameters = new TokenValidationParameters
{
ValidAudience = audienceId,
ValidIssuer = _issuer,
IssuerSigningKey = signingKey // Cannot convert HMAC Signing Credentials to System.IdentityModel.Tokens.SecurityKey
ValidateLifetime = true,
ValidateAudience = true,
ValidateIssuer = true,
RequireSignedTokens = true,
RequireExpirationTime = true,
ValidateIssuerSigningKey = true
};
var handler = new JwtSecurityTokenHandler();
SecurityToken token = null;
var principal = handler.ValidateToken(protectedText, tokenValidationParameters, out token);
var identity = principal.Identities;
return new AuthenticationTicket(identity.First(), new AuthenticationProperties());
}
One issue right off the jump is the issuer signing key. I am having trouble coming up with an acceptable parameter. I am seeing the error message:
Cannot convert HMAC Signing Credentials to System.IdentityModel.Tokens.SecurityKey
To be honest, I am unsure why the Protect method needs to fire. I thought the flow would end with the returning of the JWT token, but apparently not. Now I am struggling with the implementation of the Unprotect method as it is something I have never had to struggle with previously.
Even if I set all of the options to 'false' on the tokenValidationParamters I am still getting the following error on validation:
An exception of type 'System.IdentityModel.SignatureVerificationFailedException' occurred in System.IdentityModel.Tokens.Jwt.dll but was not handled in user code
Additional information: IDX10503: Signature validation failed. Keys tried: ''.
Exceptions caught:
''.
token: '{"typ":"JWT","alg":"HS256"}.{"iss":"http://myissuer.com","aud":"346e886acabf457cb9f721f615ff996c","exp":1510925372,"nbf":1510925072}'
When I compare the values to the decrypted token using JWT.IO all of the values match as expected.
Any guidance on what I may be doing wrong here, or how to call validateToken with a valid signing key on the tokenvalidationparamters would be most helpful and appreciated.
Thanks in advance!
EDIT:
I am curious why the Unprotect is firing at all... I thought I should be returning a JWT token to the client. The method to return a JWT fires before the Unprotect method and the JWT is never returned to the client.
Do I have something configured incorrectly?