diff --git a/src/JsonWebTokens/JsonWebToken.cs b/src/JsonWebTokens/JsonWebToken.cs
index ac00d6f..4f7da09 100644
--- a/src/JsonWebTokens/JsonWebToken.cs
+++ b/src/JsonWebTokens/JsonWebToken.cs
@@ -6,7 +6,7 @@
namespace Jwt
{
///
- /// Provides methods for encoding and decoding JSON Web Tokens.
+ /// Encoding and decoding for JSON Web Tokens.
///
public static class JsonWebToken
{
@@ -17,6 +17,15 @@ public static class JsonWebToken
private static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
+ ///
+ /// Creates a JWT using the specified payload and key hashed with .
+ ///
+ /// An arbitrary payload (must be serializable to JSON).
+ /// The key bytes used to sign the token.
+ /// The generated JWT.
+ public static string Encode(object payload, byte[] key)
+ => Encode(new JwtData { Payload = payload, KeyBytes = key, Algorithm = JwtHashAlgorithm.HS256 });
+
///
/// Creates a JWT using the specified payload, key and algorithm.
///
@@ -25,9 +34,16 @@ public static class JsonWebToken
/// The hash algorithm to use.
/// The generated JWT.
public static string Encode(object payload, byte[] key, JwtHashAlgorithm algorithm)
- {
- return Encode(new JwtData { Payload = payload, KeyBytes = key, Algorithm = algorithm });
- }
+ => Encode(new JwtData { Payload = payload, KeyBytes = key, Algorithm = algorithm });
+
+ ///
+ /// Creates a JWT using the specified payload and key hashed with .
+ ///
+ /// An arbitrary payload (must be serializable to JSON).
+ /// The key used to sign the token.
+ /// The generated JWT.
+ public static string Encode(object payload, string key)
+ => Encode(new JwtData { Payload = payload, Key = key, Algorithm = JwtHashAlgorithm.HS256 });
///
/// Creates a JWT using the specified payload, key and algorithm.
@@ -37,9 +53,7 @@ public static string Encode(object payload, byte[] key, JwtHashAlgorithm algorit
/// The hash algorithm to use.
/// The generated JWT.
public static string Encode(object payload, string key, JwtHashAlgorithm algorithm)
- {
- return Encode(new JwtData { Payload = payload, Key = key, Algorithm = algorithm });
- }
+ => Encode(new JwtData { Payload = payload, Key = key, Algorithm = algorithm });
///
/// Creates a JWT using the specified .
@@ -92,17 +106,15 @@ public static string Encode(JwtData data)
/// When the given doesn't consist of 3 parts delimited by dots.
///
public static string Decode(string token, string key, bool verify = true)
- {
- return Decode(token, Encoding.UTF8.GetBytes(key), verify);
- }
+ => Decode(token, Encoding.UTF8.GetBytes(key), verify);
///
- /// Decodes the specified JWT and returns the JSON payload.
+ /// Decodes the JWT token and deserializes JSON payload to a dictionary.
///
/// The JWT.
- /// The key bytes that were used to sign the JWT.
+ /// The key that was used to sign the JWT.
/// Whether to verify the signature (default is true).
- /// A string containing the JSON payload.
+ /// An object representing the payload.
///
/// If the parameter was true and the signature was not valid
/// or if the JWT was signed with an unsupported algorithm.
@@ -110,43 +122,11 @@ public static string Decode(string token, string key, bool verify = true)
///
/// When the given doesn't consist of 3 parts delimited by dots.
///
- public static string Decode(string token, byte[] key, bool verify = true)
- {
- var parts = token.Split('.');
- if (parts.Length != 3)
- {
- throw new ArgumentException($"Token must consist of 3 parts delimited by dot. Given token: '{token}'.");
- }
-
- var header = parts[0];
- var payload = parts[1];
- var crypto = Base64UrlDecode(parts[2]);
-
- var headerBytes = Base64UrlDecode(header);
- var headerJson = Encoding.UTF8.GetString(headerBytes, 0, headerBytes.Length);
-
- var payloadBytes = Base64UrlDecode(payload);
- var payloadJson = Encoding.UTF8.GetString(payloadBytes, 0, payloadBytes.Length);
-
- var headerData = JsonSerializer.Deserialize>(headerJson);
-
- if (verify)
- {
- var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));
- var algorithm = (string)headerData["alg"];
-
- var signature = ComputeHash(GetHashAlgorithm(algorithm), key, bytesToSign);
- var decodedCrypto = Convert.ToBase64String(crypto);
- var decodedSignature = Convert.ToBase64String(signature);
-
- Verify(decodedCrypto, decodedSignature, payloadJson);
- }
-
- return payloadJson;
- }
+ public static Dictionary DecodeToObject(string token, string key, bool verify = true)
+ => DecodeToObject>(token, key, verify);
///
- /// Decodes the JWT token and deserializes JSON payload to an .
+ /// Decodes the JWT token and deserializes JSON payload to a dictionary.
///
/// The JWT.
/// The key that was used to sign the JWT.
@@ -159,14 +139,13 @@ public static string Decode(string token, byte[] key, bool verify = true)
///
/// When the given doesn't consist of 3 parts delimited by dots.
///
- public static object DecodeToObject(string token, string key, bool verify = true)
- {
- return DecodeToObject(token, Encoding.UTF8.GetBytes(key), verify);
- }
+ public static Dictionary DecodeToObject(string token, byte[] key, bool verify = true)
+ => DecodeToObject>(token, key, verify);
///
- /// Decodes the JWT token and deserializes JSON payload to an .
+ /// Decodes the JWT token and deserializes JSON payload to .
///
+ /// The type of the object.
/// The JWT.
/// The key that was used to sign the JWT.
/// Whether to verify the signature (default is true).
@@ -178,17 +157,13 @@ public static object DecodeToObject(string token, string key, bool verify = true
///
/// When the given doesn't consist of 3 parts delimited by dots.
///
- public static object DecodeToObject(string token, byte[] key, bool verify = true)
- {
- var payloadJson = Decode(token, key, verify);
- var payloadData = JsonSerializer.Deserialize>(payloadJson);
- return payloadData;
- }
+ public static T DecodeToObject(string token, string key, bool verify = true)
+ => DecodeToObject(token, Encoding.UTF8.GetBytes(key), verify);
///
/// Decodes the JWT token and deserializes JSON payload to .
///
- /// The type of the object.
+ /// The to return
/// The JWT.
/// The key that was used to sign the JWT.
/// Whether to verify the signature (default is true).
@@ -200,19 +175,16 @@ public static object DecodeToObject(string token, byte[] key, bool verify = true
///
/// When the given doesn't consist of 3 parts delimited by dots.
///
- public static T DecodeToObject(string token, string key, bool verify = true)
- {
- return DecodeToObject(token, Encoding.UTF8.GetBytes(key), verify);
- }
+ public static T DecodeToObject(string token, byte[] key, bool verify = true)
+ => JsonSerializer.Deserialize(Decode(token, key, verify));
///
- /// Decodes the JWT token and deserializes JSON payload to .
+ /// Decodes the specified JWT and returns the JSON payload.
///
- /// The to return
/// The JWT.
- /// The key that was used to sign the JWT.
+ /// The key bytes that were used to sign the JWT.
/// Whether to verify the signature (default is true).
- /// An object representing the payload.
+ /// A string containing the JSON payload.
///
/// If the parameter was true and the signature was not valid
/// or if the JWT was signed with an unsupported algorithm.
@@ -220,33 +192,63 @@ public static T DecodeToObject(string token, string key, bool verify = true)
///
/// When the given doesn't consist of 3 parts delimited by dots.
///
- public static T DecodeToObject(string token, byte[] key, bool verify = true)
+ public static string Decode(string token, byte[] key, bool verify = true)
{
- var payloadJson = Decode(token, key, verify);
- var payloadData = JsonSerializer.Deserialize(payloadJson);
- return payloadData;
+ var parts = token.Split('.');
+ if (parts.Length != 3)
+ {
+ throw new ArgumentException($"Token must consist of 3 parts delimited by dot. Given token: '{token}'.", nameof(token));
+ }
+
+ // Decode JWT payload
+ var payload = parts[1];
+ var payloadBytes = Base64UrlDecode(payload);
+ var payloadJson = Encoding.UTF8.GetString(payloadBytes);
+
+ if (verify)
+ {
+ // Decode JWT header.
+ var header = parts[0];
+ var headerBytes = Base64UrlDecode(header);
+ var headerJson = Encoding.UTF8.GetString(headerBytes);
+
+ // Decode the signature from the JWT.
+ var jwtSignature = UrlDecode(parts[2]);
+
+ // Compute the signature for the JWT.
+ var headerData = JsonSerializer.Deserialize>(headerJson);
+ var algorithm = (string)headerData["alg"];
+ var bytesToSign = Encoding.UTF8.GetBytes(string.Concat(header, ".", payload));
+ var signature = ComputeHash(GetHashAlgorithm(algorithm), key, bytesToSign);
+ var computedSignature = Convert.ToBase64String(signature);
+
+ Verify(jwtSignature, computedSignature, payloadJson);
+ }
+
+ return payloadJson;
}
- private static void Verify(string decodedCrypto, string decodedSignature, string payloadJson)
+ private static void Verify(string jwtSignature, string computedSignature, string payloadJson)
{
- if (decodedCrypto != decodedSignature)
+ // Compare the signature from the JWT and the computed signature.
+ if (jwtSignature != computedSignature)
{
- throw new SignatureVerificationException($"Invalid signature. Expected '{decodedCrypto}' got '{decodedSignature}'.");
+ throw new SignatureVerificationException($"Invalid signature. Expected '{jwtSignature}' got '{computedSignature}'.");
}
// Verify exp claim: https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32#section-4.1.4
var payloadData = JsonSerializer.Deserialize>(payloadJson);
- if (payloadData.ContainsKey("exp") && payloadData["exp"] != null)
+ if (payloadData.TryGetValue("exp", out var expObj) && expObj != null)
{
// Safely unpack a boxed int.
int exp;
try
{
- exp = Convert.ToInt32(payloadData["exp"]);
+ exp = Convert.ToInt32(expObj);
}
catch (Exception)
{
- throw new SignatureVerificationException($"Claim 'exp' must be an integer. Given claim: '{payloadData["exp"]}'.");
+ throw new SignatureVerificationException($"Claim 'exp' must be an integer. Given claim: '{expObj}'.");
}
var secondsSinceEpoch = Math.Round((DateTime.UtcNow - UnixEpoch).TotalSeconds);
@@ -292,25 +294,36 @@ private static JwtHashAlgorithm GetHashAlgorithm(string algorithm)
case "HS512":
return JwtHashAlgorithm.HS512;
default:
- throw new SignatureVerificationException("Algorithm not supported.");
+ throw new SignatureVerificationException($"Algorithm '{algorithm}' not supported.");
}
}
+ private static readonly char[] _padding = new [] { '=' };
+
private static string Base64UrlEncode(byte[] input)
{
var output = Convert.ToBase64String(input);
- output = output.Split('=')[0]; // Remove any trailing '='s
+ output = output.TrimEnd(_padding); // Remove any trailing '='s
output = output.Replace('+', '-'); // 62nd char of encoding
output = output.Replace('/', '_'); // 63rd char of encoding
return output;
}
private static byte[] Base64UrlDecode(string input)
+ {
+ var output = UrlDecode(input);
+ var converted = Convert.FromBase64String(output);
+ return converted;
+ }
+
+ private static string UrlDecode(string input)
{
var output = input;
output = output.Replace('-', '+'); // 62nd char of encoding
output = output.Replace('_', '/'); // 63rd char of encoding
- switch (output.Length % 4) // Pad with trailing '='s
+
+ // Pad with trailing '='s
+ switch (output.Length % 4)
{
case 0:
break; // No pad chars in this case
@@ -321,11 +334,10 @@ private static byte[] Base64UrlDecode(string input)
output += "=";
break; // One pad char
default:
- throw new Exception($"Illegal base64url string: '{input}'.");
+ throw new Exception($"Illegal base-64 string: '{input}'.");
}
- var converted = Convert.FromBase64String(output);
- return converted;
+ return output;
}
}
}
diff --git a/src/JsonWebTokens/JsonWebTokens.csproj b/src/JsonWebTokens/JsonWebTokens.csproj
index b205494..5509901 100644
--- a/src/JsonWebTokens/JsonWebTokens.csproj
+++ b/src/JsonWebTokens/JsonWebTokens.csproj
@@ -1,10 +1,10 @@
- JSON Web Tokens implementation for .NET Core.
- Copyright 2017 Henk Mollema
- 2.0.0
+ JSON Web Tokens implementation for .NET Standard.
+ Copyright 2018 Henk Mollema
+ 3.0.0
Henk Mollema
- netstandard1.3
+ netstandard1.3;netstandard2.0
true
JsonWebTokens
JsonWebTokens
@@ -17,4 +17,4 @@
-
\ No newline at end of file
+
diff --git a/src/JsonWebTokens/JwtBuilder.cs b/src/JsonWebTokens/JwtBuilder.cs
index d711f35..1fd51a1 100644
--- a/src/JsonWebTokens/JwtBuilder.cs
+++ b/src/JsonWebTokens/JwtBuilder.cs
@@ -95,9 +95,12 @@ public JwtBuilder WithHeaders(IDictionary dict)
/// Builds the data to a object.
///
/// A object.
- public JwtData Build()
- {
- return _data;
- }
+ public JwtData Build() => _data;
+
+ ///
+ /// Builds and encodes the current object.
+ ///
+ /// An encoded JSON Web Token.
+ public string Encode() => JsonWebToken.Encode(Build());
}
-}
\ No newline at end of file
+}