/// <summary> /// Initializes a new instance of the <see cref="JwtHeader"/> class. With the Header Parameters as follows: /// <para>{ { typ, JWT }, { alg, Mapped( <see cref="System.IdentityModel.Tokens.SigningCredentials.SignatureAlgorithm"/> } } /// See: Algorithm Mapping below.</para> /// </summary> /// <param name="signingCredentials">The <see cref="SigningCredentials"/> that will be or were used to sign the <see cref="JwtSecurityToken"/>.</param> /// <remarks> /// <para>For each <see cref="SecurityKeyIdentifierClause"/> in signingCredentials.SigningKeyIdentifier</para> /// <para>if the clause is a <see cref="NamedKeySecurityKeyIdentifierClause"/> Header Parameter { clause.Name, clause.KeyIdentifier } will be added.</para> /// <para>For example, if clause.Name == 'kid' and clause.KeyIdentifier == 'SecretKey99'. The JSON object { kid, SecretKey99 } would be added.</para> /// <para>In addition, if the <see cref="SigningCredentials"/> is a <see cref="X509SigningCredentials"/> the JSON object { x5t, Base64UrlEncoded( <see cref="X509Certificate.GetCertHashString()"/> } will be added.</para> /// <para>This simplifies the common case where a X509Certificate is used.</para> /// <para>================= </para> /// <para>Algorithm Mapping</para> /// <para>================= </para> /// <para><see cref="System.IdentityModel.Tokens.SigningCredentials.SignatureAlgorithm"/> describes the algorithm that is discoverable by the CLR runtime.</para> /// <para>The { alg, 'value' } placed in the header reflects the JWT specification.</para> /// <see cref="JwtSecurityTokenHandler.OutboundAlgorithmMap"/> contains a signature mapping where the 'value' above will be translated according to this mapping. /// <para>Current mapping is:</para> /// <para>    'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256' => 'RS256'</para> /// <para>    'http://www.w3.org/2001/04/xmldsig-more#hmac-sha256' => 'HS256'</para> /// </remarks> public JwtHeader(SigningCredentials signingCredentials = null) : base(StringComparer.Ordinal) { this.Add(JwtConstants.ReservedHeaderParameters.Type, JwtConstants.HeaderType); if (signingCredentials != null) { this.signingCredentials = signingCredentials; string algorithm = signingCredentials.SignatureAlgorithm; if (JwtSecurityTokenHandler.OutboundAlgorithmMap.ContainsKey(signingCredentials.SignatureAlgorithm)) { algorithm = JwtSecurityTokenHandler.OutboundAlgorithmMap[algorithm]; } this.Add(JwtConstants.ReservedHeaderParameters.Algorithm, algorithm); if (signingCredentials.SigningKeyIdentifier != null) { foreach (SecurityKeyIdentifierClause clause in signingCredentials.SigningKeyIdentifier) { NamedKeySecurityKeyIdentifierClause namedKeyClause = clause as NamedKeySecurityKeyIdentifierClause; if (namedKeyClause != null) { this.Add(namedKeyClause.Name, namedKeyClause.KeyIdentifier); } } } X509SigningCredentials x509SigningCredentials = signingCredentials as X509SigningCredentials; if (x509SigningCredentials != null && x509SigningCredentials.Certificate != null) { this.Add(JwtConstants.ReservedHeaderParameters.X509CertificateThumbprint, Base64UrlEncoder.Encode(x509SigningCredentials.Certificate.GetCertHash())); } } else { this.Add(JwtConstants.ReservedHeaderParameters.Algorithm, JwtConstants.Algorithms.NONE); } }
/// <summary> /// Encodes this instance as a Base64UrlEncoded string. /// </summary> /// <remarks>Returns the current state. If this instance has changed since the last call, the value will be different.</remarks> /// <returns>a string BaseUrlEncoded representing the contents of this header.</returns> public string Encode() { return(Base64UrlEncoder.Encode(this.SerializeToJson())); }
/// <summary> /// Deserializes Base64UrlEncoded JSON into a <see cref="JwtPayload"/> instance. /// </summary> /// <param name="base64UrlEncodedJsonString">base64url encoded JSON to deserialize.</param> /// <returns>an instance of <see cref="JwtPayload"/>.</returns> /// <remarks>use <see cref="JsonExtensions.Deserializer"/> to customize JSON serialization.</remarks> public static JwtPayload Base64UrlDeserialize(string base64UrlEncodedJsonString) { return(JsonExtensions.DeserializeJwtPayload(Base64UrlEncoder.Decode(base64UrlEncodedJsonString))); }
/// <summary> /// Decodes the string into the header, payload and signature /// </summary> /// <param name="jwtEncodedString">Base64Url encoded string.</param> internal void Decode(string jwtEncodedString) { string[] tokenParts = jwtEncodedString.Split(new char[] { '.' }, 4); if (tokenParts.Length != 3) { throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10709, "jwtEncodedString", jwtEncodedString)); } try { this.header = JwtHeader.Base64UrlDeserialize(tokenParts[0]); // if present, "typ" should be set to "JWT" or "http://openid.net/specs/jwt/1.0" string type = this.header.Typ; if (type != null) { if (!(StringComparer.Ordinal.Equals(type, JwtConstants.HeaderType) || StringComparer.Ordinal.Equals(type, JwtConstants.HeaderTypeAlt))) { throw new SecurityTokenException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10702, JwtConstants.HeaderType, JwtConstants.HeaderTypeAlt, type)); } } } catch (Exception ex) { if (DiagnosticUtility.IsFatal(ex)) { throw; } throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10703, "header", tokenParts[0], jwtEncodedString), ex); } try { this.payload = JwtPayload.Base64UrlDeserialize(tokenParts[1]); } catch (Exception ex) { if (DiagnosticUtility.IsFatal(ex)) { throw; } throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10703, "payload", tokenParts[1], jwtEncodedString), ex); } // ensure signature is well-formed, GitIssue 103 if (!string.IsNullOrEmpty(tokenParts[2])) { try { Base64UrlEncoder.Decode(tokenParts[2]); } catch (Exception ex) { if (DiagnosticUtility.IsFatal(ex)) { throw; } throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10703, "signature", tokenParts[1], jwtEncodedString), ex); } } this.rawData = jwtEncodedString; this.rawHeader = tokenParts[0]; this.rawPayload = tokenParts[1]; this.rawSignature = tokenParts[2]; }
/// <summary> /// Encodes this instance as Base64UrlEncoded JSON. /// </summary> /// <returns>Base64UrlEncoded JSON.</returns> /// <remarks>use <see cref="JsonExtensions.Serializer"/> to customize JSON serialization.</remarks> public virtual string Base64UrlEncode() { return(Base64UrlEncoder.Encode(SerializeToJson())); }