In the previous post Decouple OWIN Authorization Server from Resource Server we
saw how we can separate the Authorization Server and the Resource
Server by unifying the “decryptionKey” and “validationKey” key values
in machineKey node in the web.config file for the
Authorization and the Resource server. So once the user request an
access token from the Authorization server, the
Authorization server will use this unified key to encrypt the access
token, and at the other end when the token is sent to the Resource
server, it will use the same key to decrypt this access token and
extract the authentication ticket from it.
This way works well if you have control on your Resource
servers (Audience) which will rely on your Authorization server (Token
Issuer) to obtain access tokens from, in other words you are fully
trusting those Resource servers so you are sharing with them the same
“decryptionKey” and “validationKey” values.
But in some situations you might have big number of Resource
servers rely on your Authorization server, so sharing the same
“decryptionKey” and “validationKey” keys with all those parties become
inefficient process as well insecure, you are using the same keys for
multiple Resource servers, so if a key is compromised all the other
Resource servers will be affected.
To overcome this issue we need to configure the
Authorization server to issue access tokens using JSON Web Tokens format
(JWT) instead of the default access token format, as well on the
Resource server side we need to configure it to consume this new JWT
access tokens, as well you will see through out this post that there is
no need to unify the “decryptionKey” and “validationKey” key values
anymore if we used JWT.
What is JSON Web Token (JWT)?
JSON Web Token is a security token which acts as a container
for claims about the user, it can be transmitted easily between the
Authorization server (Token Issuer), and the Resource server (Audience),
the claims in JWT are encoded using JSON which make it easier to use
especially in applications built using JavaScript.
JSON Web Tokens can be signed following the JSON Web
Signature (JWS) specifications, as well it can be encrypted following
the JSON Web Encryption (JWE) specifications, in our case we will not
transmit any sensitive data in the JWT payload, so we’ll only sign this
JWT to protect it from tampering during the transmission between
parties.
JSON Web Token (JWT) Format
Basically the JWT is a string which consists of three parts
separated by a dot (.) The JWT parts are:
The header part is JSON object which contains 2 nodes always and looks as the following:
{ "typ": "JWT", "alg": "HS256" } The
“type” node has always “JWT” value, and the node “alg” contains the
algorithm used to sign the token, in our case we’ll use “HMAC-SHA256″
for signing.
The payload part is JSON object as well which contains all
the claims inside this token, check the example shown in the snippet
below:
1
2
3
4
5
6
7
8
9
10
11
12
|
{
"unique_name": "SysAdmin",
"sub": "SysAdmin",
"role": [
"Manager",
"Supervisor"
],
"iss": "http://myAuthZServer",
"aud": "379ee8430c2d421380a713458c23ef74",
"exp": 1414283602,
"nbf": 1414281802
}
|
All those claims are not mandatory in order to build JWT, you can read more about
JWT claims here. In our case we’ll always use those set of claims in the JWT we are going to issue, those claims represent the below:
- The “sub” (subject) and “unique_claim” claims represent the user name this token issued for.
- The “role” claim represents the roles for the user.
- The “iss” (issuer) claim represents the Authorization server (Token Issuer) party.
- The “aud” (audience) claim represents the recipients that
the JWT is intended for (Relying Party – Resource Server). More on this
unique string later in this post.
- The “exp” (expiration time) claim represents the expiration time of the JWT, this claim contains UNIX time value.
- The “nbf” (not before) claim represent the time which this JWT must not be used before, this claim contains UNIX time vale.
Lastly the signature part of the JWT is created by taking
the header and payload parts, base 64 URL encode them, then concatenate
them with “.”, then use the “alg” defined in the
part to
generate the signature, in our case “HMAC-SHA256″. The resulting part of
this signing process is byte array which should be base 64 URL encoded
then concatenated with the . to produce a
complete JWT.
JSON Web Tokens support in ASP.NET Web API and Owin middleware.
There is no direct support for issuing JWT in ASP.NET Web
API or ready made Owin middleware responsible for doing this, so in
order to start issuing JWTs we need to implement this manually by
implementing the interface “ISecureDataFormat” and implement the method
“Protect”. More in this later. But for consuming the JWT in a Resource
server there is ready middleware named “Microsoft.Owin.Security.Jwt”
which understands validates, and and de-serialize JWT tokens with
minimal number of line of codes.
So most of the heavy lifting we’ll do now will be in implementing the Authorization Server.
What we’ll build in this tutorial?
We’ll build a single Authorization server which issues JWT using
ASP.NET Web API 2 on top of Owin middleware, the Authorization server is
hosted on Azure (
http://JwtAuthZSrv.azurewebsites.net)
so you can test it out by adding new Resource servers. Then we’ll build
a single Resource server (audience) which will process JWTs issued by
our Authorization server only.
I’ll split this post into two sections, the first section
will be for creating the Authorization server, and the second section
will cover creating Resource server.
The source code for this tutorial is available on GitHub.
Section 1: Building the Authorization Server (Token Issuer)
Step 1.1: Create the Authorization Server Web API Project
Create an empty solution and name it “JsonWebTokensWebApi”
then add a new ASP.NET Web application named “AuthorizationServer.Api”,
the selected template for the project will be “Empty” template with no
core dependencies. Notice that the authentication is set to “No
Authentication”.
Step 1.2: Install the needed NuGet Packages:
Open package manger console and install the below Nuget packages:
|
|
Install-Package Microsoft.AspNet.WebApi -Version 5.2.2
Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.2.2
Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.0
Install-Package Microsoft.Owin.Cors -Version 3.0.0
Install-Package Microsoft.Owin.Security.OAuth -Version 3.0.0
Install-Package System.IdentityModel.Tokens.Jwt -Version 4.0.0
Install-Package Thinktecture.IdentityModel.Core Version 1.2.0
|
You can refer to the
previous post
if you want to know what each package is responsible for. The package
named “System.IdentityModel.Tokens.Jwt” is responsible for validating,
parsing and generating JWT tokens. As well we’ve used the package
“Thinktecture.IdentityModel.Core” which contains class named “
HmacSigningCredentials” which will be used to facilitate creating signing keys.
Step 1.3: Add Owin “Startup” Class:
Right click on your project then add a new class named “Startup”. It will contain the code below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
// Web API routes
config.MapHttpAttributeRoutes();
ConfigureOAuth(app);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth2/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat("http://jwtauthzsrv.azurewebsites.net")
};
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
}
|
Here we’ve created new instance from class “OAuthAuthorizationServerOptions” and set its option as the below:
- The path for generating JWT will be as :”http://jwtauthzsrv.azurewebsites.net/oauth2/token”.
- We’ve specified the expiry for token to be 30 minutes
- We’ve specified the implementation on how to validate the client and
Resource owner user credentials in a custom class named
“CustomOAuthProvider”.
- We’ve specified the implementation on how to generate the access
token using JWT formats, this custom class named “CustomJwtFormat” will
be responsible for generating JWT instead of default access token using
DPAPI, note that both are using bearer scheme.
We’ll come to the implementation of both class later in the next steps.
Step 1.4: Resource Server (Audience) Registration:
Now we need to configure our Authorization server to allow
registering Resource server(s) (Audience), this step is very important
because we need a way to identify which Resource server (Audience) is
requesting the JWT token, so the Authorization server will be able to
issue JWT token for this audience only.
The minimal needed information to register a Recourse server
into an Authorization server are a unique Client Id, and shared
symmetric key. For the sake of keeping this tutorial simple I’m
persisting those information into a volatile dictionary so the values
for those Audiences will be removed from the memory if IIS reset toke
place, for production scenario you need to store those
values permanently on a database.
Now add new folder named “Entities” then add new class named “Audience” inside this class paste the code below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class Audience
{
[Key]
[MaxLength(32)]
public string ClientId { get; set; }
[MaxLength(80)]
[Required]
public string Base64Secret { get; set; }
[MaxLength(100)]
[Required]
public string Name { get; set; }
}
|
Then add new folder named “Models” the add new class named “AudienceModel” inside this class paste the code below:
|
|
public class AudienceModel
{
[MaxLength(100)]
[Required]
public string Name { get; set; }
}
|
Now add new class named “AudiencesStore” and paste the code below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
public static class AudiencesStore
{
public static ConcurrentDictionary<string, Audience> AudiencesList = new ConcurrentDictionary<string, Audience>();
static AudiencesStore()
{
AudiencesList.TryAdd("099153c2625149bc8ecb3e85e03f0022",
new Audience { ClientId = "099153c2625149bc8ecb3e85e03f0022",
Base64Secret = "IxrAjDoa2FqElO7IhrSrUJELhUckePEPVpaePlS_Xaw",
Name = "ResourceServer.Api 1" });
}
public static Audience AddAudience(string name)
{
var clientId = Guid.NewGuid().ToString("N");
var key = new byte[32];
RNGCryptoServiceProvider.Create().GetBytes(key);
var base64Secret = TextEncodings.Base64Url.Encode(key);
Audience newAudience = new Audience { ClientId = clientId, Base64Secret = base64Secret, Name = name };
AudiencesList.TryAdd(clientId, newAudience);
return newAudience;
}
public static Audience FindAudience(string clientId)
{
Audience audience = null;
if (AudiencesList.TryGetValue(clientId, out audience))
{
return audience;
}
return null;
}
}
|
Basically this class acts like a repository for the Resource servers
(Audiences), basically it is responsible for two things, adding new
audience and finding exiting one.
Now if you take look on method “AddAudience” you will notice that we’ve implemented the following:
- Generating random string of 32 characters as an identifier for the audience (client id).
- Generating 256 bit random key using the
“RNGCryptoServiceProvider” class then base 64 URL encode it, this key
will be shared between the Authorization server and the Resource server only.
- Add the newly generated audience to the in-memory “AudiencesList”.
- The “FindAudience” method is responsible for finding an audience based on the client id.
- The constructor of the class contains fixed audience for the demo purpose.
Lastly we need to add an end point in our Authorization server which
allow registering new Resource servers (Audiences), so add new folder
named “Controllers” then add new class named “AudienceController” and
paste the code below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[RoutePrefix("api/audience")]
public class AudienceController : ApiController
{
[Route("")]
public IHttpActionResult Post(AudienceModel audienceModel)
{
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
Audience newAudience = AudiencesStore.AddAudience(audienceModel.Name);
return Ok<Audience>(newAudience);
}
}
|
This end point can be accessed by issuing HTTP POST request to the URI
http://jwtauthzsrv.azurewebsites.net/api/audience as
the image below, notice that the Authorization server is responsible
for generating the client id and the shared symmetric key. This
symmetric key should not be shared with any party except the Resource
server (Audience) requested it.
Note: In real world scenario the Resource
server (Audience) registration process won’t be this trivial, you might
go through workflow approval. Sharing the key will take place using a
secure admin portal, as well you might need to provide the audience with
the ability to regenerate the key in case it get compromised.
Step 1.5: Implement the “CustomOAuthProvider” Class
Now we need to implement the code responsible for issuing JSON Web Token when the requester issue HTTP POST request to the URI:
http://jwtauthzsrv.azurewebsites.net/oauth2/token the
request will look as the image below, notice how we are setting the
client id for for the Registered resource (audience) from the previous
step using key (client_id).
To implement this we need to add new folder named
“Providers” then add new class named “CustomOAuthProvider”, paste the
code snippet below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
public class CustomOAuthProvider : OAuthAuthorizationServerProvider
{
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
string clientId = string.Empty;
string clientSecret = string.Empty;
string symmetricKeyAsBase64 = string.Empty;
if (!context.TryGetBasicCredentials(out clientId, out clientSecret))
{
context.TryGetFormCredentials(out clientId, out clientSecret);
}
if (context.ClientId == null)
{
context.SetError("invalid_clientId", "client_Id is not set");
return Task.FromResult<object>(null);
}
var audience = AudiencesStore.FindAudience(context.ClientId);
if (audience == null)
{
context.SetError("invalid_clientId", string.Format("Invalid client_id '{0}'", context.ClientId));
return Task.FromResult<object>(null);
}
context.Validated();
return Task.FromResult<object>(null);
}
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
//Dummy check here, you need to do your DB checks against memebrship system http://bit.ly/SPAAuthCode
if (context.UserName != context.Password)
{
context.SetError("invalid_grant", "The user name or password is incorrect");
//return;
return Task.FromResult<object>(null);
}
var identity = new ClaimsIdentity("JWT");
identity.AddClaim(new Claim(ClaimTypes.Name, context.UserName));
identity.AddClaim(new Claim("sub", context.UserName));
identity.AddClaim(new Claim(ClaimTypes.Role, "Manager"));
identity.AddClaim(new Claim(ClaimTypes.Role, "Supervisor"));
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{
"audience", (context.ClientId == null) ? string.Empty : context.ClientId
}
});
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
return Task.FromResult<object>(null);
}
}
|
As you notice this class inherits from class
“OAuthAuthorizationServerProvider”, we’ve overridden two methods
“ValidateClientAuthentication” and “GrantResourceOwnerCredentials”
- The first method “ValidateClientAuthentication” will be responsible
for validating if the Resource server (audience) is already registered
in our Authorization server by reading the client_id value from the
request, notice that the request will contain only the client_id without
the shared symmetric key. If we take the happy scenario and
the audience is registered we’ll mark the context as a valid context
which means that audience check has passed and the code flow can proceed
to the next step which is validating that resource owner credentials
(user who is requesting the token).
- The second method “GrantResourceOwnerCredentials” will be
responsible for validating the resource owner (user) credentials, for
the sake of keeping this tutorial simple I’m considering that each
identical username and password combination are valid, in read world
scenario you will do your database checks against membership system such
as ASP.NET Identity, you can check this in the previous post.
- Notice that we are setting the authentication type for
those claims to “JWT”, as well we are passing the the audience client id
as a property of the “AuthenticationProperties”, we’ll use the audience
client id in the next step.
- Now the JWT access token will be generated when we call
“context.Validated(ticket), but we still need to implement the class
“CustomJwtFormat” we talked about in step 1.3.
Step 1.5: Implement the “CustomJwtFormat” Class
This class will be responsible for generating the JWT access
token, so what we need to do is to add new folder named “Formats” then
add new class named “CustomJwtFormat” and paste the code below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket>
{
private const string AudiencePropertyKey = "audience";
private readonly string _issuer = string.Empty;
public CustomJwtFormat(string issuer)
{
_issuer = issuer;
}
public string Protect(AuthenticationTicket data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
string audienceId = data.Properties.Dictionary.ContainsKey(AudiencePropertyKey) ? data.Properties.Dictionary[AudiencePropertyKey] : null;
if (string.IsNullOrWhiteSpace(audienceId)) throw new InvalidOperationException("AuthenticationTicket.Properties does not include audience");
Audience audience = AudiencesStore.FindAudience(audienceId);
string symmetricKeyAsBase64 = audience.Base64Secret;
var keyByteArray = TextEncodings.Base64Url.Decode(symmetricKeyAsBase64);
var signingKey = new HmacSigningCredentials(keyByteArray);
var issued = data.Properties.IssuedUtc;
var expires = data.Properties.ExpiresUtc;
var token = new JwtSecurityToken(_issuer, audienceId, data.Identity.Claims, issued.Value.UtcDateTime, expires.Value.UtcDateTime, signingKey);
var handler = new JwtSecurityTokenHandler();
var jwt = handler.WriteToken(token);
return jwt;
}
public AuthenticationTicket Unprotect(string protectedText)
{
throw new NotImplementedException();
}
}
|
What we’ve implemented in this class is the following:
- The class “CustomJwtFormat” implements the interface
“ISecureDataFormat”, the JWT generation will
take place inside method “Protect”.
- The constructor of this class accepts the “Issuer” of this JWT which
will be our Authorization server, this can be string or URI, in our
case we’ll fix it to URI with the value
“http://jwtauthzsrv.azurewebsites.net”
- Inside “Protect” method we are doing the following:
- Reading the audience (client id) from the Authentication Ticket properties, then getting this audience from the In-memory store.
- Reading the Symmetric key for this audience and Base64
decode it to byte array which will be used to create a HMAC265 signing
key.
- Preparing the raw data for the JSON Web Token which will be
issued to the requester by providing the issuer, audience, user claims,
issue date, expiry date, and the signing Key which will sign the JWT
payload.
- Lastly we serialize the JSON Web Token to a string and return it to the requester.
- By doing this requester for an access token from our
Authorization server will receive a signed token which contains claims
for a certain resource owner (user) and this token intended to certain
Resource server (audience) as well.
So if we need to request a JWT from our Authorization server for a
user named “SuperUser” that needs to access the Resource server
(audience) “099153c2625149bc8ecb3e85e03f0022″, all we need to do is to
issue HTTP POST to the token end point (
http://jwtauthzsrv.azurewebsites.net/oauth2/token) as the image below:

The result for this will be the below JSON Web Token:
|
|
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1bmlxdWVfbmFtZSI6IlN1cGVyVXNlciIsInN1YiI6IlN1cGVyVXNlciIsInJvbGUiOlsiTWFuYWdlciIsIlN1cGVydmlzb3IiXSwiaXNzIjoiaHR0cDovL2p3dGF1dGh6c3J2LmF6dXJld2Vic2l0ZXMubmV0IiwiYXVkIjoiMDk5MTUzYzI2MjUxNDliYzhlY2IzZTg1ZTAzZjAwMjIiLCJleHAiOjE0MTQzODEyODgsIm5iZiI6MTQxNDM3OTQ4OH0.pZffs_TSXjgxRGAPQ6iJql7NKfRjLs1WWSliX5njSYU
|
There is an online JWT debugger tool named
jwt.io that
allows you to paste the encoded JWT and decode it so you can interpret
the claims inside it, so open the tool and paste the JWT above and you
should receive response as the image below, notice that all the claims
are set properly including the iss, aud, sub,role, etc…
One thing to notice here that there is red label which
states that the signature is invalid, this is true because this tool
doesn’t know about the shared symmetric key issued for the audience
(099153c2625149bc8ecb3e85e03f0022).
So if we decided to share this symmetric key with the tool
and paste the key in the secret text box; we should receive green label
stating that signature is valid, and this is identical to the
implementation we’ll see in the Resource server when it receives
a request containing a JWT.

Now the Authorization server (Token issuer) is able to register
audiences and issue JWT tokens, so let’s move to adding a Resource
server which will consume the JWT tokens.
Section 2: Building the Resource Server (Audience)
Step 2.1: Creating the Resource Server Web API Project
Add a new ASP.NET Web application named “ResourceServer.Api”, the
selected template for the project will be “Empty” template with no core
dependencies. Notice that the authentication is set to “No
Authentication”.
Step 2.2: Installing the needed NuGet Packages:
Open package manger console and install the below Nuget packages:
|
|
Install-Package Microsoft.AspNet.WebApi -Version 5.2.2
Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.2.2
Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.0
Install-Package Microsoft.Owin.Cors -Version 3.0.0
Install-Package Microsoft.Owin.Security.Jwt -Version 3.0.0
|
The package “Microsoft.Owin.Security.Jwt” is responsible for
protecting the Resource server resources using JWT, it only validate
and de-serialize JWT tokens.
Step 2.3: Add Owin “Startup” Class:
Right click on your project then add a new class named “Startup”. It will contain the code below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
ConfigureOAuth(app);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
var issuer = "http://jwtauthzsrv.azurewebsites.net";
var audience = "099153c2625149bc8ecb3e85e03f0022";
var secret = TextEncodings.Base64Url.Decode("IxrAjDoa2FqElO7IhrSrUJELhUckePEPVpaePlS_Xaw");
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audience },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
}
});
}
}
|
This is the most important step in
configuring the Resource server to trust tokens issued by our
Authorization server (http://jwtauthzsrv.azurewebsites.net), notice how
we are providing the values for the issuer, audience (client id), and
the shared symmetric secret we obtained once we registered the resource
with the authorization server.
By providing those values to
JwtBearerAuthentication middleware, this Resource server will be able to consume only JWT tokens
issued by the trusted Authorization server and
issued for this audience only.
Note: Always store keys in config files not directly in source code.
Step 2.4: Add new protected controller
Now we want to add a controller which will serve as our protected
resource, this controller will return list of claims for the
authorized user, those claims for sure are encoded within the JWT we’ve
obtained from the Authorization Server. So add new controller named
“ProtectedController” under “Controllers” folder and paste the code
below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
[Authorize]
[RoutePrefix("api/protected")]
public class ProtectedController : ApiController
{
[Route("")]
public IEnumerable<object> Get()
{
var identity = User.Identity as ClaimsIdentity;
return identity.Claims.Select(c => new
{
Type = c.Type,
Value = c.Value
});
}
}
|
Notice how we attribute the controller with
[Authorize] attribute
which will protect this resource and only will authentic HTTP GET
requests containing a valid JWT access token, with valid I mean:
- Not expired JWT.
- JWT issued by our Authorization server (http://jwtauthzsrv.azurewebsites.net).
- JWT issued for the audience (099153c2625149bc8ecb3e85e03f0022) only.
Conclusion
Using signed JSON Web Tokens facilitates and standardize
the way of separating the Authorization server and the Resource server,
no more need for unifying machineKey values nor having the risk of
sharing the “decryptionKey” and “validationKey” key values among
different Resource servers.
Keep in mind that the JSON Web Token we’ve created in this tutorial
is signed only, so do not put any sensitive information in it
The source code for this tutorial is available on GitHub.
That’s it for now folks, hopefully this short walk
through helped in understanding how we can configure the Authorization
Server to issue JWT and how we can consume them in a Resource Server.
If you have any comment, question or enhancement please drop me a comment, I do not mind if you star the
GitHub Repo too
Follow me on Twitter @tjoudeh
References
Comments
Post a Comment