I have a working implementation of a Claims based authentication system implemented with WIF and .NET 4.5. It contains the usual pieces:
- Custom STS with Passive and Active endpoints
- Backend WCF service
- Frontend MVC application
- Frontend WebApi application
The calls from the frontend applications to the backedn WCF service use Delegated authentication, so the user authenticates in the Frontend app, the app requests a new token with ActAs=BootstrapToken and then calls the WCF service.
This is all working correctly with SAML tokens.
Now I want to use a JWT token to talk to the WebApi, so I installed the JSON Web Token Handler For the Microsoft .Net Framework 4.5 Nuget package in my STS and WebApi projects.
So I have my STS correctly issuing signed JWT tokens and my WebApi Relying Party validating the same token. All fine.
The problem:
If I use the JWT token in the ActAs field of my RST, it will be sent without the signature, so its naturally rejected by the STS. It seems that the token returned by the SecurityTokenHandler.ReadToken() method returns a token without any signature info.
Now my dilemma is this: Is this a supported scenario for a JWT token? As far as I understand, a JWT token doesn't carry all the information to validate the signature, as opposed to a SAML token, so is there any other limitations?
On the other hand, if this is indeed supported, does anyone implemented this before, or has any ideas? This is a developer preview, so could it be a bug?
Edit
This is a sample to illustrate the issue. The code produces the same results when run in the STS (with access to the signing key) and on a Relying Party (with access to the certificate's public key:
System.Diagnostics.Debug.WriteLine("Raw Token : {0}", (object)rawToken);
var readToken = this.identityConfiguration.SecurityTokenHandlers.ReadToken(rawToken);
this.identityConfiguration.SecurityTokenHandlers.ValidateToken(readToken);
var serializedToken = this.identityConfiguration.SecurityTokenHandlers.WriteToken(readToken);
System.Diagnostics.Debug.WriteLine("Serialized Token: {0}", (object)serializedToken);
Produces the following
Raw Token : eyJAi(...)x3a9.eyJvYXB(...)DYzWiJ9.y-lT(...)PyBUTw
Serialized Token: eyJAi(...)x3a9.eyJvYXB(...)DYzWiJ9.
So, clearly, a Read/Write roundtrip loses the signing information. I could understand why this happens in the RP, but not in the STS.
Edit 2
So here's the current JWTSecurityTokenHandler.WriteToken(SecurityToken token)
implementation:
public override string WriteToken(SecurityToken token)
{
Utility.VerifyNonNullArgument("token", token);
JWTSecurityToken jWTSecurityToken = token as JWTSecurityToken;
if (jWTSecurityToken == null)
{
throw new SecurityTokenException(string.Format(CultureInfo.InvariantCulture, "JWT10200: This instance of JWTSecurityTokenHandler can only write SecurityTokens of type '{0}', a SecurityToken of type '{1}' was received.", new object[]
{
typeof(JWTSecurityToken),
token.GetType()
}));
}
string text = string.Empty;
string text2 = string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[]
{
jWTSecurityToken.EncodedHeader,
jWTSecurityToken.EncodedPayload
});
if (jWTSecurityToken.SigningCredentials != null)
{
text = this.Sign(text2, jWTSecurityToken.SigningCredentials);
}
return string.Format(CultureInfo.InvariantCulture, "{0}.{1}", new object[]
{
text2,
text
});
}
By looking into it, it's clear that the written token will never have its signature when in a RP, as we don't have the Signing Credentials. So this doesn't look like a bug, but rather an implementation decision. I just don't understand why.
Thanks