Mapping JWT token in C# [duplicate] - c#

I don't understand how this library works. Could you help me please ?
Here is my simple code :
public void TestJwtSecurityTokenHandler()
{
var stream =
"eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJJU1MiLCJzY29wZSI6Imh0dHBzOi8vbGFyaW0uZG5zY2UuZG91YW5lL2NpZWxzZXJ2aWNlL3dzIiwiYXVkIjoiaHR0cHM6Ly9kb3VhbmUuZmluYW5jZXMuZ291di5mci9vYXV0aDIvdjEiLCJpYXQiOiJcL0RhdGUoMTQ2ODM2MjU5Mzc4NClcLyJ9";
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(stream);
}
This is the error :
The string needs to be in compact JSON format, which is of the form: Base64UrlEncodedHeader.Base64UrlEndcodedPayload.OPTIONAL,Base64UrlEncodedSignature'.
If you copy the stream in jwt.io website, it works fine :)

I found the solution, I just forgot to Cast the result:
var stream = "[encoded jwt]";
var handler = new JwtSecurityTokenHandler();
var jsonToken = handler.ReadToken(stream);
var tokenS = jsonToken as JwtSecurityToken;
Or, without the cast:
var token = "[encoded jwt]";
var handler = new JwtSecurityTokenHandler();
var jwtSecurityToken = handler.ReadJwtToken(token);
I can get Claims using:
var jti = tokenS.Claims.First(claim => claim.Type == "jti").Value;

new JwtSecurityTokenHandler().ReadToken("") will return a SecurityToken
new JwtSecurityTokenHandler().ReadJwtToken("") will return a JwtSecurityToken
If you just change the method you are using you can avoid the cast in the above answer

You need the secret string which was used to generate encrypt token.
This code works for me:
protected string GetName(string token)
{
string secret = "this is a string used for encrypt and decrypt token";
var key = Encoding.ASCII.GetBytes(secret);
var handler = new JwtSecurityTokenHandler();
var validations = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
var claims = handler.ValidateToken(token, validations, out var tokenSecure);
return claims.Identity.Name;
}

var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Email, model.UserName),
new Claim(JwtRegisteredClaimNames.NameId, model.Id.ToString()),
};
var token = new JwtSecurityToken(_config["Jwt:Issuer"],
_config["Jwt:Issuer"],
claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
Then extract content
var handler = new JwtSecurityTokenHandler();
string authHeader = Request.Headers["Authorization"];
authHeader = authHeader.Replace("Bearer ", "");
var jsonToken = handler.ReadToken(authHeader);
var tokenS = handler.ReadToken(authHeader) as JwtSecurityToken;
var id = tokenS.Claims.First(claim => claim.Type == "nameid").Value;

Using .net core jwt packages, the Claims are available:
[Route("api/[controller]")]
[ApiController]
[Authorize(Policy = "Bearer")]
public class AbstractController: ControllerBase
{
protected string UserId()
{
var principal = HttpContext.User;
if (principal?.Claims != null)
{
foreach (var claim in principal.Claims)
{
log.Debug($"CLAIM TYPE: {claim.Type}; CLAIM VALUE: {claim.Value}");
}
}
return principal?.Claims?.SingleOrDefault(p => p.Type == "username")?.Value;
}
}

I write this solution and it's work for me
protected Dictionary<string, string> GetTokenInfo(string token)
{
var TokenInfo = new Dictionary<string, string>();
var handler = new JwtSecurityTokenHandler();
var jwtSecurityToken = handler.ReadJwtToken(token);
var claims = jwtSecurityToken.Claims.ToList();
foreach (var claim in claims)
{
TokenInfo.Add(claim.Type, claim.Value);
}
return TokenInfo;
}

Extending on cooxkie answer, and dpix answer, when you are reading a jwt token (such as an access_token received from AD FS), you can merge the claims in the jwt token with the claims from "context.AuthenticationTicket.Identity" that might not have the same set of claims as the jwt token.
To Illustrate, in an Authentication Code flow using OpenID Connect,after a user is authenticated, you can handle the event SecurityTokenValidated which provides you with an authentication context, then you can use it to read the access_token as a jwt token, then you can "merge" tokens that are in the access_token with the standard list of claims received as part of the user identity:
private Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage,OpenIdConnectAuthenticationOptions> context)
{
//get the current user identity
ClaimsIdentity claimsIdentity = (ClaimsIdentity)context.AuthenticationTicket.Identity;
/*read access token from the current context*/
string access_token = context.ProtocolMessage.AccessToken;
JwtSecurityTokenHandler hand = new JwtSecurityTokenHandler();
//read the token as recommended by Coxkie and dpix
var tokenS = hand.ReadJwtToken(access_token);
//here, you read the claims from the access token which might have
//additional claims needed by your application
foreach (var claim in tokenS.Claims)
{
if (!claimsIdentity.HasClaim(claim.Type, claim.Value))
claimsIdentity.AddClaim(claim);
}
return Task.FromResult(0);
}

Use this:
public static string Get_Payload_JWTToken(string token)
{
var handler = new JwtSecurityTokenHandler();
var DecodedJWT = handler.ReadJwtToken(token);
string payload = DecodedJWT.EncodedPayload; // Gives Payload
return Encoding.UTF8.GetString(FromBase64Url(payload));
}
static byte[] FromBase64Url(string base64Url)
{
string padded = base64Url.Length % 4 == 0
? base64Url : base64Url + "====".Substring(base64Url.Length % 4);
string base64 = padded.Replace("_", "/").Replace("-", "+");
return Convert.FromBase64String(base64);
}

Though this answer is not answering the original question but its a really very useful feature for C# developers, so adding it as the answer.
Visual Studio 2022 has added a feature to decode the value of a token at runtime.
You can check the feature in Visual Studio 2022 preview (version 17.5.0 preview 2.0)
Mouse over the variable containing the JWT and then select the string manipulation as JWT Decode, and you can see the token value.

Related

JWT Header algorithm: is "hs256" the same as "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256"

I'm trying to sign a JWT using HS256. I'm using System.IdentityModel.Tokens.Jwt . When decoding the token using jwt.io I get invalid signature and I've noticed that my headers read:
{
"alg": "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256",
"typ": "JWT"
}
rather than {"alg":"HS256","typ":"JWT"} as I expected.
Is this what's causing the invalid signature? Also any ideas on a fix? Please note that I need to include custom claims as well.
var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(Encoding.UTF8.GetBytes(clientsecret));
var credentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256Signature);
var header = new JwtHeader(credentials);
You can create your JSON Web Token (JWT) as follows using System.IdentityModel.Tokens.Jwt, which should set all fields correctly (secret is the key you use to sign your JWT):
var now = DateTime.UtcNow;
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[] { new Claim("sub", "customer") }),
Issuer = "Who issued the token",
Claims = new Dictionary<string, object>
{
["email"] = Email,
},
IssuedAt = now,
NotBefore = now,
Expires = now + TimeSpan.FromDays(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(secret), SecurityAlgorithms.HmacSha256Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
var serializedToken = tokenHandler.WriteToken(token);
serializedToken finally contains the serialized JWT.
Please note that the SecurityTokenDescriptorclass is from the Microsoft.IdentityModel.Tokens namespace of the same NuGet package, not from System.IdentityModel.Tokens namespace.
SecurityAlgorithms.HmacSha256Signature
change
SecurityAlgorithms.HmacSha256

Get JWT claims directly from the token, ASP Net Core 2.1

I working on an ASP Net Core 2.1 Web API. I've implemented successfully JWT within my project. Everything with the Authorization works fine.
Normally, when I need user claims, I know I can get them like this (E.g. Email claim):
var claimsIdentity = User.Identity as ClaimsIdentity;
var emailClaim = claimsIdentity.Claims.FirstOrDefault(x => x.Type == ClaimTypes.Email);
The thing is, I am not in a controller that inherits from ControllerBase class, so I don't have any User object or [Authorize] attributes.
What I have though is the token itself.
e.g.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbiIsIm5iZiI6MTU2ODYzNjYxMywiZXhwIjoxNTY4NjQ3NDEzLCJpYXQiOjE1Njg2MzY2MTN9.ED9x_AOvkLQqutb09yh3Huyv0ygHp_i3Eli8WG2S9N4
I want to get the claims directly from the token, because:
I have access to the token.
I am not located in a Controller class and the request is not going through any [Authorize] attributes, so IHttpContextAccessor can't be used as well.
How can I achieve this in ASP Net Core 2.1? In case someone wants to see how I add the user claims:
var tokenDescriptor = new SecurityTokenDescriptor
{
Expires = DateTime.UtcNow.AddHours(3),
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, email),
new Claim(ClaimTypes.Email, email)
}),
SigningCredentials = new SigningCredentials(key: new SymmetricSecurityKey(key), algorithm: SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
I'm located in a class that derives from IDocumentFilter (Swagger class)
Here is a simple workaround:
var tokenDescriptor = new SecurityTokenDescriptor
{
Expires = DateTime.UtcNow.AddHours(3),
Subject = new ClaimsIdentity(new[]
{
new Claim(ClaimTypes.Name, "user#hotmail.com"),
new Claim(ClaimTypes.Email, "user#hotmail.com")
}),
SigningCredentials = new SigningCredentials(key: new SymmetricSecurityKey(key), algorithm: SecurityAlgorithms.HmacSha256Signature)
};
var Securitytoken = new JwtSecurityTokenHandler().CreateToken(tokenDescriptor);
var tokenstring = new JwtSecurityTokenHandler().WriteToken(Securitytoken);
var token = new JwtSecurityTokenHandler().ReadJwtToken(tokenstring);
var claim = token.Claims.First(c => c.Type == "email").Value;
return claim;
For example in my current project I get claims by validation. Its refresh token, so I cant use [Authorize] attribute.
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
public ClaimsPrincipal ValidateRefreshToken(string refreshToken)
{
try
{
var validationParams = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(tokenSecurityKey),
ValidateLifetime = true
};
return new JwtSecurityTokenHandler().ValidateToken
(
refreshToken,
validationParams,
out SecurityToken token
);
}
catch (Exception e)
{
Log.Error(e.Message);
return null;
}
}
and then
var claims = ValidateRefreshToken(refreshToken);
...
var userIdString = claims.Claims.FirstOrDefault(x => x.Type == "userId")?.Value;
Here is an easy way to extract the claims:
public IEnumerable<Claim> ExtractClaims(string jwtToken)
{
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
JwtSecurityToken securityToken = (JwtSecurityToken)tokenHandler.ReadToken(jwtToken);
IEnumerable<Claim> claims = securityToken.Claims;
return claims;
}

Manually validating a JWT token in C#

I am having some trouble manually validating a JWT token issued by Identity Server 4. Using the
ClientId: "CLIENT1"
ClientSecret: "123456"
The exception I keep getting is: IDX10501: Signature validation failed. Unable to match keys: '[PII is hidden by default. Set the 'ShowPII' flag in IdentityModelEventSource.cs to true to reveal it.]'
Is anyone able to advise me where I am going wrong.
private static void ValidateJwt(string jwt, DiscoveryResponse disco)
{
var parameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
ValidIssuer = disco.Issuer,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("123456")),
ValidAudience = "CLIENT1",
//IssuerSigningKeys = keys,
// ValidateAudience = true,
// ValidateLifetime = true,
};
SecurityToken validatedToken;
var handler = new JwtSecurityTokenHandler();
handler.InboundClaimTypeMap.Clear();
try
{
var user = handler.ValidateToken(jwt, parameters, out validatedToken);
}
catch(Exception ex)
{
var error = ex.Message;
}
}
Check out ValidateJwt() in this sample:
https://github.com/IdentityServer/IdentityServer4/blob/master/samples/Clients/old/MvcManual/Controllers/HomeController.cs
The bit you're missing is loading the public key from the discovery document.
Try changing the length of your private key. Your private key is too small to be encoded I suppose.
For manual verification, you could just use
static byte[] FromBase64Url(string base64Url)
{
string padded = base64Url.Length % 4 == 0
? base64Url : base64Url + "====".Substring(base64Url.Length % 4);
string base64 = padded.Replace("_", "/")
.Replace("-", "+");
return Convert.FromBase64String(base64);
}
This also answers #henk-holterman 's question
Encoding.UTF8.GetBytes( can't be the right way to do this.
Although realistically a better way to do this is via the OIDC discovery-endpoint
Auth0 has a good article about this using standard NuGet packages. Basically, you load everything needed from the discovery end-point.
IConfigurationManager<OpenIdConnectConfiguration> configurationManager = new ConfigurationManager<OpenIdConnectConfiguration>($"{auth0Domain}.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever());
OpenIdConnectConfiguration openIdConfig = await configurationManager.GetConfigurationAsync(CancellationToken.None);
TokenValidationParameters validationParameters =
new TokenValidationParameters
{
ValidIssuer = auth0Domain,
ValidAudiences = new[] { auth0Audience },
IssuerSigningKeys = openIdConfig.SigningKeys
};
SecurityToken validatedToken;
JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
var user = handler.ValidateToken("eyJhbGciOi.....", validationParameters, out validatedToken);
You can read more about it here Or their GitHub sample page about this here
In my case, I did not have a discovery endpoint. Just a JWKS endpoint.
So I opted to do this.
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using RestSharp;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Threading.Tasks;
public class ExpectedJwksResponse
{
[JsonProperty(PropertyName = "keys")]
public List<JsonWebKey> Keys { get; set; }
}
private static async Task<List<SecurityKey>> GetSecurityKeysAsync()
{
// Feel free to use HttpClient or whatever you want to call the endpoint.
var client = new RestClient("<https://sample-jwks-endpoint.url>");
var request = new RestRequest(Method.GET);
var result = await client.ExecuteTaskAsync<ExpectedJwksResponse>(request);
if (result.StatusCode != System.Net.HttpStatusCode.OK)
{
throw new Exception("Wasnt 200 status code");
}
if (result.Data == null || result.Data.Keys == null || result.Data.Keys.Count == 0 )
{
throw new Exception("Couldnt parse any keys");
}
var keys = new List<SecurityKey>();
foreach ( var key in result.Data.Keys )
{
keys.Add(key);
}
return keys;
}
private async Task<bool> ValidateToken(token){
TokenValidationParameters validationParameters = new TokenValidationParameters
{
RequireExpirationTime = true,
RequireSignedTokens = true,
ValidateLifetime = true,
ValidIssuer = "https://sample-issuer.com",
ValidAudiences = new[] { "https://sample-audience/resource" },
IssuerSigningKeys = await GetSecurityKeysAsync()
};
var user = null as System.Security.Claims.ClaimsPrincipal;
SecurityToken validatedToken;
try
{
user = handler.ValidateToken(token, validationParameters, out validatedToken);
}
catch ( Exception e )
{
Console.Write($"ErrorMessage: {e.Message}");
return false;
}
var readToken = handler.ReadJwtToken(token);
var claims = readToken.Claims;
return true;
}
You have specified:
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret"))
but the JwtSecurityTokenHandler could not match it with the key which can be part of jwt header itself. Basically it means that your configuration has mismatch[es] with configuration of the real issuer. The error suggests that this relates to the signature keys.
Please, check the configuration of that issuer (if you can), find out missed parts, and try again.
You can use jwt.io to debug your jwt online.
IdentityServer signs the JWT using RS256. This means you need to use a public key to verify the JWT (you can get this from the discovery document).
The client id & client secret are client credentials used for requesting tokens. They have no part in validating them.
You are trying to use SymmetricKey for JWT validation. Try looking your token in JWT.io and if algorithm is"RS256" then SymmetricKey won't work.
Please check when you create JWT token make sure that you added SigningCredentials.
var token = new JwtSecurityToken(
Constants.Audiance,Constants.Issuer,claims
notBefore:DateTime.Now,
expires:DateTime.Now.AddHours(1),
**signinCredential**
);

Verify Firebase JWT in c# .net

I am trying to verify a json web token obtained by a firebase android client and passed to a server running .net
Following the answer here I created these methods to validate the token and extract the uid:
public static async Task<string> GetUserNameFromTokenIfValid(string jsonWebToken)
{
const string FirebaseProjectId = "testapp-16ecd";
try
{
// 1. Get Google signing keys
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://www.googleapis.com/robot/v1/metadata/");
HttpResponseMessage response = await client.GetAsync("x509/securetoken#system.gserviceaccount.com");
if (!response.IsSuccessStatusCode) { return null; }
var x509Data = await response.Content.ReadAsAsync<Dictionary<string, string>>();
SecurityKey[] keys = x509Data.Values.Select(CreateSecurityKeyFromPublicKey).ToArray();
// Use JwtSecurityTokenHandler to validate the JWT token
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
// Set the expected properties of the JWT token in the TokenValidationParameters
TokenValidationParameters validationParameters = new TokenValidationParameters()
{
ValidAudience = FirebaseProjectId,
ValidIssuer = "https://securetoken.google.com/" + FirebaseProjectId,
ValidateIssuerSigningKey = true,
IssuerSigningKeys = keys
};
SecurityToken validatedToken;
ClaimsPrincipal principal = tokenHandler.ValidateToken(jsonWebToken, validationParameters, out validatedToken);
var jwt = (JwtSecurityToken)validatedToken;
return jwt.Subject;
}
catch (Exception e)
{
return null;
}
}
static SecurityKey CreateSecurityKeyFromPublicKey(string data)
{
return new X509SecurityKey(new X509Certificate2(Encoding.UTF8.GetBytes(data)));
}
When I run the code I get the response:
{"IDX10501: Signature validation failed. Unable to match 'kid': 'c2154b0435d58fc96a4480bd7655188fd4370b07', \ntoken: '{"alg":"RS256","typ":"JWT","kid":"c2154b0435d58fc96a4480bd7655188fd4370b07"}......
Calling https://www.googleapis.com/robot/v1/metadata/x509/securetoken#system.gserviceaccount.com does return a certificate with a matching id:
{
"c2154b0435d58fc96a4480bd7655188fd4370b07": "-----BEGIN CERTIFICATE-----\nMIIDHDCCAgSgAwIBAgIIRZGQCmoKoNQwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE\nAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTYx\nMTIxMDA0NTI2WhcNMTYxMTI0MDExNTI2WjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl\nbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAKHbxqFaNQyrrrv8gocpQjES+HCum8XRQYYLRqstJ12FGtDN\np32qagCbc0x94TaBZF7tCPMgyFU8pBQP7CvCxWxoy+Xdv+52lcR0sG/kskr23E3N\nJmWVHT3YwiMwdgsbWDIpWEbvJdn3DPFaapvD9BJPwNoXuFCO2vA2rhi1LuNWsaHt\nBj5jTicGCnt2PGKUTXJ9q1hOFi90wxTVUVMfFqDa4g9iKqRoaNaLOo0w3VgsFPlr\nMBca1fw1ArZpEGm3XHaDOiCi+EZ2+GRvdF/aPNy1+RdnUPMEEuHErULSxXpYGIdt\n/Mo7QvtFXkIl6ZHvEp5pWkS8mlAJyfPrOs8RzXMCAwEAAaM4MDYwDAYDVR0TAQH/\nBAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ\nKoZIhvcNAQEFBQADggEBAJYXDQFIOC0W0ZwLO/5afSlqtMZ+lSiFJJnGx/IXI5Mi\n0sBI3QA7QXmiNH4tVyEiK+HsFPKAYovsbh7HDypEnBGsz9UmEU6Wn6Qu9/v38+bo\nLant6Ds9ME7QHhKJKtYkso0F2RVwu220xZQl1yrl4bjq+2ZDncYthILjw5t+8Z4c\nQW5UCr2wlVtkflGtIPR1UrvyU13eiI5SPkwOWPZvG2iTabnLfcRIkhQgIalkznMe\niz8Pzpk9eT8HFeZYiB61GpIWHG4oEb1/Z4Q//os+vWDQ+X0ARTYhTEbwLLQ0dcjW\nfg/tm7J+MGH5NH5MwjO+CI4fA3NoGOuEzF1vb7/hNdU=\n-----END CERTIFICATE-----\n"
I have successfully validated this token using the Java call (made in kotlin)
FirebaseAuth.getInstance().verifyIdToken(idToken).addOnSuccessListener { decodedToken ->
val uid = decodedToken.uid
}
I'm sure by now you have figured out the solution for this, but for future people who come across this question.
Set the KeyId for the X509SecurityKey
x509Data.Select(cert => new X509SecurityKey(new X509Certificate2(Encoding.UTF8.GetBytes(cert.Value)))
{
KeyId = cert.Key
})
.ToArray()
This will allow the TokenValidationParameters to look up which issuerKey to validate against.

Generate JWT with certificate thumbprint with JSON Web Token Handler for .Net

I'm starting a new task where I have to process thumbprint from JWT. We use JSON Web Token Handler For the Microsoft .Net Framework. There is already an implementation used in tests that generates JWT without x5t filed in header. It looks like this:
var handler = new JwtSecurityTokenHandler();
var securityKey = new InMemorySymmetricSecurityKey(Any.Array<byte>(1024));
var desc = new SecurityTokenDescriptor
{
TokenIssuerName = "MSI",
Lifetime = new Lifetime(null, DateTime.UtcNow.AddDays(10)),
SigningCredentials = new SigningCredentials(securityKey, "http://www.w3.org/2001/04/xmldsig-more#hmac-sha256", "http://www.w3.org/2001/04/xmlenc#sha256"),
};
var identity = new ClaimsIdentity();
identity.AddClaim(new Claim("scope", "msi_unsapi_presence.watch"));
identity.AddClaim(new Claim("scope", "msi_unsapi_location.watch"));
identity.AddClaim(new Claim("scope", "msi_unsapi_groupmgt.read"));
identity.AddClaim(new Claim("scope", "msi_unsapi_groupmgt.write"));
var jwtToken = handler.CreateToken(desc);
return jwtToken;
And the token it produces: {"typ":"JWT","alg":"HS256"}.{"scope":["msi_unsapi_presence.watch","msi_unsapi_location.watch","msi_unsapi_groupmgt.read","msi_unsapi_groupmgt.write"]} I try to set AttachedReference property of SecurityTokenDescriptor as the following AttachedReference = new X509ThumbprintKeyIdentifierClause(Any.Array<byte>(1024)) to have x5t field filled in the token (I don't care about the exact value, I just need it to exist in token for test purpose) but the token produced still doesn't have this field set. How can I generate the token with not empty x5t filed in header, preferably modifying the existing code?
here's the implementation for your customJsonWebTokenFormat :
you can really add anything to it with the payload.add().
public class yourJsonWebTokenFormat: ISecureDataFormat<AuthenticationTicket>
{
public string Protect(AuthenticationTicket data)
{
DateTime notBefore = DateTime.UtcNow;
DateTime expires = notBefore + TimeSpan.FromHours(1); //validity timer.
SigningCredentials cred= new SigningCredentials(); // your signing credentials.
JwtHeader header = new JwtHeader(cred);
header.add("x5t","your value");
JwtPayload payload = newJwtPayload(ConfigurationManager.AppSettings["Issuer"],data.Properties.Dictionary["audience"], data.Identity.Claims, notBefore, expires);
payload.add("x5t","your x5t to json property");
var jwtToken = new JwtSecurityToken(header, payload);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(jwtToken);
return jwt;
}
}
then in your OAuth Config :
OAuthAuthorizationServerOptions OAuthServerOptions = new
OAuthAuthorizationServerOptions()
{
// provider configuration, token authentication expiracy, etc...
Provider = new SampleAuthorizationServerProvider()
AccessTokenFormat = new JsonWebTokenFormat()
};
requesting a token will now call your yourJsonWebTokenFormat.protect() method.
you should set the identity you built in your sample in a AuthenticationTicket in your own OAuthAuthorizationServerProvider.
something like that :
public class SampleAuthorizationServerProvider : OAuthAuthorizationServerProvider, IOAuthAuthorizationServerProvider
{
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
// do AD check or other stuff needed to validate the user here
var ticket = new AuthenticationTicket(identity, props); // props here is a AuthenticationProperties Dictionnary with other stuff that you want in your JwtToken
context.Validated(ticket);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
//do some check...
context.Validated();
}
}
so you endup with 2 class you need to implement : ISecureDataFormat<AuthenticationTicket>
and
OAuthAuthorizationServerProvider, IOAuthAuthorizationServerProvider

Categories

Resources