-
Notifications
You must be signed in to change notification settings - Fork 462
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Evolving project to version 2.0 (#67)
* Adding .editorconfig * Setting version to 2.0.0.0 * Removing reference to System.Web.Extensions, DefaultJsonSerializer. Adding Json.Net, JsonNetSerializer. Updating nuget packages for Tests * Moving algorithm to separate classes. Adding AlgorithmFactory * Adding JwtEncoder, moving Encode() methods to it * Replacing MSTest with xUnit * Moving serializers to the Serializers folder * Refactoring tests * Adding JwtDecoder, moving Decode() methods to it * Moving validation to JwtValidator * Calling JwtDecoder from static API * Making verify parameter mandatory * Upgrading to .NET 4.6.1 * Marking all static API as obsolete * Sorting files in project file * Updating nuspec, package.cmd, nuget.exe * Adding IDateTimeProvider, DateTimeProvider. Using it in JwtValidator. Sealing all classes but exceptions. * Bumping nuget package to 2.0.0-beta2 * Updating .gitignore * Updating sln * Moving Customer to Internal folder * Adding JwtDecoderTest * Adding JwtEncoderTest * Do not instantiating new dictionary when no extra headers were passed to Encode() * Passing verify as named parameter for readability. Other refactoring. * Updating readme * Renaming IAlgorithm to IJwtAlgorithm * Removing Lazy<AlgorithmFactory>to make it just AlgorithmFactory * Returning IDictionary<string, object> from non-generic DecodeToObject() * Making AlgorithmFactory static field
- Loading branch information
1 parent
89d0e50
commit 6f398dc
Showing
38 changed files
with
1,494 additions
and
854 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
root = true; | ||
|
||
[*] | ||
end_of_line = crlf; | ||
|
||
[*.cs] | ||
indent_style = space; | ||
indent_size = 4; | ||
insert_final_newline = false; | ||
trim_trailing_whitespace = true; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,64 @@ | ||
|
||
#ignore thumbnails created by windows | ||
Thumbs.db | ||
#Ignore files build by Visual Studio | ||
*.user | ||
*.vspscc | ||
*.suo | ||
*.bak | ||
[Bb]in | ||
[Dd]ebug*/ | ||
obj/ | ||
[Rr]elease*/ | ||
_ReSharper*/ | ||
[Tt]est[Rr]esult* | ||
package/ | ||
packages/ | ||
*.nupkg | ||
## Ignore Visual Studio temporary files, build results, and | ||
## files generated by popular Visual Studio add-ons. | ||
## | ||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore | ||
|
||
# User-specific files | ||
*.suo | ||
*.user | ||
*.userosscache | ||
*.sln.docstates | ||
|
||
# User-specific files (MonoDevelop/Xamarin Studio) | ||
*.userprefs | ||
|
||
# Build results | ||
[Dd]ebug/ | ||
[Dd]ebugPublic/ | ||
[Rr]elease/ | ||
[Rr]eleases/ | ||
x64/ | ||
x86/ | ||
bld/ | ||
[Bb]in/ | ||
[Oo]bj/ | ||
[Ll]og/ | ||
|
||
# Build Results of an ATL Project | ||
[Dd]ebugPS/ | ||
[Rr]eleasePS/ | ||
dlldata.c | ||
|
||
# .NET Core | ||
project.lock.json | ||
project.fragment.lock.json | ||
artifacts/ | ||
**/Properties/launchSettings.json | ||
|
||
# ReSharper is a .NET coding add-in | ||
_ReSharper*/ | ||
*.[Rr]e[Ss]harper | ||
*.DotSettings.user | ||
|
||
# NuGet Packages | ||
*.nupkg | ||
# The packages folder can be ignored because of Package Restore | ||
package | ||
**/packages/* | ||
# except build/, which is used as an MSBuild target. | ||
!**/packages/build/ | ||
# Uncomment if necessary however generally it will be regenerated when needed | ||
#!**/packages/repositories.config | ||
# NuGet v3's project.json files produces more ignorable files | ||
*.nuget.props | ||
*.nuget.targets | ||
|
||
# | ||
# Backup & report files from converting an old project file | ||
# to a newer Visual Studio version. Backup files are not needed, | ||
# because we have git ;-) | ||
_UpgradeReport_Files/ | ||
Backup*/ | ||
UpgradeLog*.XML | ||
UpgradeLog*.htm | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,34 +1,37 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio 14 | ||
VisualStudioVersion = 14.0.25420.1 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWT", "src\JWT\JWT.csproj", "{A80B51B8-DDF6-4026-98A4-B59653E50B38}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWT.Tests", "tests\JWT.Tests\JWT.Tests.csproj", "{BF568781-D576-4545-A552-4DC839B1AF14}" | ||
EndProject | ||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{513CE2B5-E0D6-43BC-998A-A02CB2875479}" | ||
ProjectSection(SolutionItems) = preProject | ||
JWT.nuspec = JWT.nuspec | ||
package.cmd = package.cmd | ||
EndProjectSection | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{A80B51B8-DDF6-4026-98A4-B59653E50B38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{A80B51B8-DDF6-4026-98A4-B59653E50B38}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{A80B51B8-DDF6-4026-98A4-B59653E50B38}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{A80B51B8-DDF6-4026-98A4-B59653E50B38}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{BF568781-D576-4545-A552-4DC839B1AF14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{BF568781-D576-4545-A552-4DC839B1AF14}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{BF568781-D576-4545-A552-4DC839B1AF14}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{BF568781-D576-4545-A552-4DC839B1AF14}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
EndGlobal | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio 14 | ||
VisualStudioVersion = 14.0.25420.1 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWT", "src\JWT\JWT.csproj", "{A80B51B8-DDF6-4026-98A4-B59653E50B38}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JWT.Tests", "tests\JWT.Tests\JWT.Tests.csproj", "{BF568781-D576-4545-A552-4DC839B1AF14}" | ||
EndProject | ||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{513CE2B5-E0D6-43BC-998A-A02CB2875479}" | ||
ProjectSection(SolutionItems) = preProject | ||
.editorconfig = .editorconfig | ||
.gitignore = .gitignore | ||
JWT.nuspec = JWT.nuspec | ||
package.cmd = package.cmd | ||
README.md = README.md | ||
EndProjectSection | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{A80B51B8-DDF6-4026-98A4-B59653E50B38}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{A80B51B8-DDF6-4026-98A4-B59653E50B38}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{A80B51B8-DDF6-4026-98A4-B59653E50B38}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{A80B51B8-DDF6-4026-98A4-B59653E50B38}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{BF568781-D576-4545-A552-4DC839B1AF14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{BF568781-D576-4545-A552-4DC839B1AF14}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{BF568781-D576-4545-A552-4DC839B1AF14}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{BF568781-D576-4545-A552-4DC839B1AF14}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,95 +1,119 @@ | ||
# JSON Web Token (JWT) implementation for .NET | ||
|
||
This library supports generating and decoding [JSON Web Tokens](http://tools.ietf.org/html/draft-jones-json-web-token-10). | ||
|
||
## Installation | ||
The easiest way to install is via NuGet. See [here](https://nuget.org/packages/JWT). Else, you can download and compile it yourself. | ||
|
||
## Usage | ||
### Creating Tokens | ||
|
||
```csharp | ||
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.WriteLine(token); | ||
``` | ||
|
||
Output will be: | ||
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjbGFpbTEiOjAsImNsYWltMiI6ImNsYWltMi12YWx1ZSJ9.8pwBI_HtXqI3UgQHQ_rDRnSQRxFL1SR8fbQoS-5kM5s | ||
|
||
### Verifying and Decoding Tokens | ||
|
||
```csharp | ||
var token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjbGFpbTEiOjAsImNsYWltMiI6ImNsYWltMi12YWx1ZSJ9.8pwBI_HtXqI3UgQHQ_rDRnSQRxFL1SR8fbQoS-5kM5s"; | ||
var secretKey = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk"; | ||
try | ||
{ | ||
string jsonPayload = JWT.JsonWebToken.Decode(token, secretKey); | ||
Console.WriteLine(jsonPayload); | ||
} | ||
catch (JWT.SignatureVerificationException) | ||
{ | ||
Console.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: | ||
|
||
```csharp | ||
var payload = JWT.JsonWebToken.DecodeToObject(token, secretKey) as IDictionary<string, object>; | ||
Console.WriteLine(payload["claim2"]); | ||
``` | ||
|
||
which will output: | ||
|
||
claim2-value | ||
|
||
#### exp claim | ||
|
||
As described in the [JWT RFC](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32#section-4.1.4) the `exp` "claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing." If an `exp` claim is present and is prior to the current time the token will fail verification. The exp (expiry) value must be specified as the number of seconds since 1/1/1970 UTC. | ||
|
||
```csharp | ||
var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); | ||
var now = Math.Round((DateTime.UtcNow - unixEpoch).TotalSeconds); | ||
var payload = new Dictionary<string, object>() | ||
{ | ||
{ "exp", now } | ||
}; | ||
var secretKey = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk"; | ||
string token = JWT.JsonWebToken.Encode(payload, secretKey, JWT.JwtHashAlgorithm.HS256); | ||
|
||
string jsonPayload = JWT.JsonWebToken.Decode(token, secretKey); // JWT.SignatureVerificationException! | ||
``` | ||
|
||
### Configure JSON Serialization | ||
|
||
By default JSON Serialization is done by System.Web.Script.Serialization.JavaScriptSerializer. To configure a different one first implement the IJsonSerializer interface. | ||
|
||
```csharp | ||
public class CustomJsonSerializer : IJsonSerializer | ||
{ | ||
public string Serialize(object obj) | ||
{ | ||
// Implement using favorite JSON Serializer | ||
} | ||
|
||
public T Deserialize<T>(string json) | ||
{ | ||
// Implement using favorite JSON Serializer | ||
} | ||
} | ||
``` | ||
|
||
Next configure this serializer as the JsonSerializer. | ||
```cs | ||
JsonWebToken.JsonSerializer = new CustomJsonSerializer(); | ||
``` | ||
# Jwt.Net, a JWT (JSON Web Token) implementation for .NET | ||
|
||
This library supports generating and decoding [JSON Web Tokens](http://tools.ietf.org/html/draft-jones-json-web-token-10). | ||
|
||
## Installation | ||
Package is avaliable via [NuGet](https://nuget.org/packages/JWT). Or you can download and compile it yourself. | ||
|
||
## Supported .NET Framework versions | ||
As of version 2.0, the lowest Supported version is 4.6.1 | ||
|
||
## Usage | ||
### Creating (Encoding) Tokens | ||
|
||
```csharp | ||
var payload = new Dictionary<string, object> | ||
{ | ||
{ "claim1", 0 }, | ||
{ "claim2", "claim2-value" } | ||
}; | ||
var secret = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk"; | ||
|
||
IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); | ||
IJsonSerializer serializer = new JsonNetSerializer(); | ||
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer); | ||
|
||
var token = encoder.Encode(payload, secret); | ||
Console.WriteLine(token); | ||
``` | ||
|
||
Output will be: | ||
|
||
>eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjbGFpbTEiOjAsImNsYWltMiI6ImNsYWltMi12YWx1ZSJ9.8pwBI_HtXqI3UgQHQ_rDRnSQRxFL1SR8fbQoS-5kM5s | ||
### Parsing (Decoding) and Verifying Tokens | ||
|
||
```csharp | ||
var token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjbGFpbTEiOjAsImNsYWltMiI6ImNsYWltMi12YWx1ZSJ9.8pwBI_HtXqI3UgQHQ_rDRnSQRxFL1SR8fbQoS-5kM5s"; | ||
var secret = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk"; | ||
try | ||
{ | ||
IJsonSerializer serializer = new JsonNetSerializer(); | ||
IDateTimeProvider provider = new UtcDateTimeProvider(); | ||
IJwtValidator validator = new JwtValidator(serializer, provider); | ||
IJwtDecoder decoder = new JwtDecoder(serializer, validator); | ||
|
||
var json = decoder.Decode(token, secret, verify: true); | ||
Console.WriteLine(json); | ||
} | ||
catch (TokenExpiredException) | ||
{ | ||
Console.WriteLine("Token has expired"); | ||
} | ||
catch (SignatureVerificationException) | ||
{ | ||
Console.WriteLine("Token has invalid signature"); | ||
} | ||
``` | ||
|
||
Output will be: | ||
|
||
>{ "claim1": 0, "claim2": "claim2-value" } | ||
You can also deserialize the JSON payload directly to a .NET type with `DecodeToObject<T>`: | ||
|
||
```csharp | ||
var payload = decoder.DecodeToObject<IDictionary<string, object>>(token, secret); | ||
Console.WriteLine(payload["claim2"]); | ||
``` | ||
|
||
Output will be: | ||
|
||
>claim2-value | ||
#### exp claim | ||
|
||
As described in the [JWT RFC](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32#section-4.1.4), the `exp` "claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing." If an `exp` claim is present and is prior to the current time the token will fail verification. The exp (expiry) value must be specified as the number of seconds since 1/1/1970 UTC. | ||
|
||
```csharp | ||
IDateTimeProvider provider = new UtcDateTimeProvider(); | ||
var now = provider.GetNow(); | ||
|
||
var unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); | ||
var secondsSinceEpoch = Math.Round((now - unixEpoch).TotalSeconds); | ||
|
||
var payload = new Dictionary<string, object> | ||
{ | ||
{ "exp", secondsSinceEpoch } | ||
}; | ||
var secret = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk"; | ||
var token = encoder.Encode(payload, secret); | ||
|
||
var json = decoder.Decode(token, secret); // TokenExpiredException | ||
``` | ||
|
||
### Custom JSON serializer | ||
|
||
By default JSON serialization is done by JsonNetSerializer implemented using [Json.Net](https://www.json.net). To configure a different one first implement the `IJsonSerializer` interface: | ||
|
||
```csharp | ||
public class CustomJsonSerializer : IJsonSerializer | ||
{ | ||
public string Serialize(object obj) | ||
{ | ||
// Implement using favorite JSON Serializer | ||
} | ||
|
||
public T Deserialize<T>(string json) | ||
{ | ||
// Implement using favorite JSON Serializer | ||
} | ||
} | ||
``` | ||
|
||
And then pass this serializer as a dependency to JwtEncoder constructor: | ||
```csharp | ||
IJwtAlgorithm algorithm = new HMACSHA256Algorithm(); | ||
IJsonSerializer serializer = new CustomJsonSerializer(); | ||
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer); | ||
``` |
Oops, something went wrong.