Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Miscellaneous improvements. #2

Merged
merged 1 commit into from
Jan 19, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions JWT.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@
<package>
<metadata>
<id>JWT</id>
<version>1.1.1</version>
<authors>John Sheehan</authors>
<version>1.2.0</version>
<authors>John Sheehan, Michael Lehenbauer</authors>
<description>JWT (JSON Web Token) Implementation for .NET (Public Domain)</description>
<language>en-US</language>
<projectUrl>http://github.com/johnsheehan/jwt</projectUrl>
<tags>jwt json</tags>
<dependencies>
<dependency id="Newtonsoft.Json" />
</dependencies>
</metadata>
</package>
</package>
65 changes: 49 additions & 16 deletions JWT/JWT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Web.Script.Serialization;

namespace JWT
{
Expand All @@ -14,9 +13,13 @@ public enum JwtHashAlgorithm
HS512
}

public class JsonWebToken
/// <summary>
/// Provides methods for encoding and decoding JSON Web Tokens.
/// </summary>
public static class JsonWebToken
{
private static Dictionary<JwtHashAlgorithm, Func<byte[], byte[], byte[]>> HashAlgorithms;
private static JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();

static JsonWebToken()
{
Expand All @@ -28,13 +31,20 @@ static JsonWebToken()
};
}

/// <summary>
/// Creates a JWT given a payload, the signing key, and the algorithm to use.
/// </summary>
/// <param name="payload">An arbitrary payload (must be serializable to JSON via <see cref="System.Web.Script.Serialization.JavaScriptSerializer"/>).</param>
/// <param name="key">The key used to sign the token.</param>
/// <param name="algorithm">The hash algorithm to use.</param>
/// <returns>The generated JWT.</returns>
public static string Encode(object payload, string key, JwtHashAlgorithm algorithm)
{
var segments = new List<string>();
var header = new { typ = "JWT", alg = algorithm.ToString() };

byte[] headerBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(header, Formatting.None));
byte[] payloadBytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(payload, Formatting.None));
byte[] headerBytes = Encoding.UTF8.GetBytes(jsonSerializer.Serialize(header));
byte[] payloadBytes = Encoding.UTF8.GetBytes(jsonSerializer.Serialize(payload));

segments.Add(Base64UrlEncode(headerBytes));
segments.Add(Base64UrlEncode(payloadBytes));
Expand All @@ -50,22 +60,24 @@ public static string Encode(object payload, string key, JwtHashAlgorithm algorit
return string.Join(".", segments.ToArray());
}

public static string Decode(string token, string key)
{
return Decode(token, key, true);
}

public static string Decode(string token, string key, bool verify)
/// <summary>
/// Given a JWT, decode it and return the JSON payload.
/// </summary>
/// <param name="token">The JWT.</param>
/// <param name="key">The key that was used to sign the JWT.</param>
/// <param name="verify">Whether to verify the signature (default is true).</param>
/// <returns>A string containing the JSON payload.</returns>
/// <exception cref="SignatureVerificationException">Thrown if the verify parameter was true and the signature was NOT valid or if the JWT was signed with an unsupported algorithm.</exception>
public static string Decode(string token, string key, bool verify = true)
{
var parts = token.Split('.');
var header = parts[0];
var payload = parts[1];
byte[] crypto = Base64UrlDecode(parts[2]);

var headerJson = Encoding.UTF8.GetString(Base64UrlDecode(header));
var headerData = JObject.Parse(headerJson);
var headerData = jsonSerializer.Deserialize<Dictionary<string,object>>(headerJson);
var payloadJson = Encoding.UTF8.GetString(Base64UrlDecode(payload));
var payloadData = JObject.Parse(payloadJson);

if (verify)
{
Expand All @@ -79,11 +91,26 @@ public static string Decode(string token, string key, bool verify)

if (decodedCrypto != decodedSignature)
{
throw new ApplicationException(string.Format("Invalid signature. Expected {0} got {1}", decodedCrypto, decodedSignature));
throw new SignatureVerificationException(string.Format("Invalid signature. Expected {0} got {1}", decodedCrypto, decodedSignature));
}
}

return payloadData.ToString();
return payloadJson;
}

/// <summary>
/// Given a JWT, decode it and return the payload as an object (by deserializing it with <see cref="System.Web.Script.Serialization.JavaScriptSerializer"/>).
/// </summary>
/// <param name="token">The JWT.</param>
/// <param name="key">The key that was used to sign the JWT.</param>
/// <param name="verify">Whether to verify the signature (default is true).</param>
/// <returns>An object representing the payload.</returns>
/// <exception cref="SignatureVerificationException">Thrown if the verify parameter was true and the signature was NOT valid or if the JWT was signed with an unsupported algorithm.</exception>
public static object DecodeToObject(string token, string key, bool verify = true)
{
var payloadJson = JsonWebToken.Decode(token, key, verify);
var payloadData = jsonSerializer.Deserialize<Dictionary<string,object>>(payloadJson);
return payloadData;
}

private static JwtHashAlgorithm GetHashAlgorithm(string algorithm)
Expand All @@ -93,7 +120,7 @@ private static JwtHashAlgorithm GetHashAlgorithm(string algorithm)
case "HS256": return JwtHashAlgorithm.HS256;
case "HS384": return JwtHashAlgorithm.HS384;
case "HS512": return JwtHashAlgorithm.HS512;
default: throw new InvalidOperationException("Algorithm not supported.");
default: throw new SignatureVerificationException("Algorithm not supported.");
}
}

Expand Down Expand Up @@ -125,4 +152,10 @@ private static byte[] Base64UrlDecode(string input)
}
}

public class SignatureVerificationException : Exception
{
public SignatureVerificationException(string message) : base(message)
{
}
}
}
14 changes: 3 additions & 11 deletions JWT/JWT.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
<AssemblyName>JWT</AssemblyName>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<TargetFrameworkProfile>
</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
Expand All @@ -32,23 +33,14 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.4.0.5\lib\net35\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="System.Web.Extensions" />
</ItemGroup>
<ItemGroup>
<Compile Include="JWT.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
Expand Down
4 changes: 2 additions & 2 deletions JWT/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.1.1.0")]
[assembly: AssemblyFileVersion("1.1.1.0")]
[assembly: AssemblyVersion("1.2.0.0")]
[assembly: AssemblyFileVersion("1.2.0.0")]
4 changes: 0 additions & 4 deletions JWT/packages.config

This file was deleted.

47 changes: 41 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,47 @@
# JSON Web Token (JWT) Implementation for .NET

See [the spec][0]
This library supports generating and decoding [JSON Web Tokens](http://tools.ietf.org/html/draft-jones-json-web-token-10).

## Usage (coming soon)
## Installation
The easiest way to install is via NuGet. See [here](https://nuget.org/packages/JWT). Else, you can download and compile it yourself.

using JWT;
JsonWebToken.Encode()
JsonWebToken.Decode()
## Usage
### Creating Tokens
var payload = new Dictionary<string, object>() {
{ "claim1", 0 },
{ "claim2", "claim2-value" }
};
var secretKey = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
string token = JWT.JsonWebToken.Encode(payload, secretKey, JWT.JwtHashAlgorithm.HS256);
Console.Out.WriteLine(token);

Output will be:

[0]: http://self-issued.info/docs/draft-jones-json-web-token-01.html
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjbGFpbTEiOjAsImNsYWltMiI6ImNsYWltMi12YWx1ZSJ9.8pwBI_HtXqI3UgQHQ_rDRnSQRxFL1SR8fbQoS-5kM5s

### Verifying and Decoding Tokens

var token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjbGFpbTEiOjAsImNsYWltMiI6ImNsYWltMi12YWx1ZSJ9.8pwBI_HtXqI3UgQHQ_rDRnSQRxFL1SR8fbQoS-5kM5s";
var secretKey = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
try
{
string jsonPayload = JWT.JsonWebToken.Decode(token, secretKey);
Console.Out.WriteLine(jsonPayload);
}
catch (JWT.SignatureVerificationException)
{
Console.Out.WriteLine("Invalid token!");
}

Output will be:

{"claim1":0,"claim2":"claim2-value"}

You can also deserialize the JSON payload directly to a .Net object with DecodeToObject:

var payload = JWT.JsonWebToken.DecodeToObject(token, secretKey) as IDictionary<string, object>;
Console.Out.WriteLine(payload["claim2"]);

which will output:

claim2-value
Binary file not shown.
Loading