JWT Bearer Token based Authentication in .Net Core

By | September 7, 2017

In my previous posts, i have explained bearer token based authentication and authorization which is just a string, potentially arbitrary, that is used for authorization.

Now, In this post we will implement JSON Web Token (JWT). It is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA. Therefore, a JWT typically looks like the following.

xxxxx.yyyyy.zzzzz

JWT consist of three parts separated by dots (.) which are:

Header : It consists of two parts: the type of the token, which is JWT, and the hashing algorithm being used, such as HMAC SHA256 or RSA.
For example:

{
"alg": "HS256",
"typ": "JWT"
}

Payload : It contains the claims that are statements about an entity (typically, the user) and additional metadata.
There are three types of claims: reserved, public, and private claims.
For example:

{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}

 

Signature : To create the signature part you have to take the encoded header, the encoded payload, a secret, the algorithm specified in the header, and sign that.
For example:

HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)

Now, come to the implementation in Asp.Net Core 1.1.0. In Asp.Net Core 1.1.0, there is no option to select individual user account authentication as you can see in below image, that option is disabled.

PM> Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 1.1.2

PM> Install-Package Microsoft.AspNetCore.Authentication.Cookies -Version 1.1.2

Middleware exists in the Microsoft.AspNetCore.Authentication.JwtBearer package that does most of the work for us!

Create partial Starup as Starup.Auth.cs and paste the below code:

public partial class Startup
    {
        // The secret key every token will be signed with.
        // Keep this safe on the server!
        private static readonly string secretKey = "mysupersecret_secretkey!123";

        private void ConfigureAuth(IApplicationBuilder app)
        {
            var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(secretKey));

            app.UseSimpleTokenProvider(new TokenProviderOptions
            {
                Path = "/api/token",
                Audience = "ExampleAudience",
                Issuer = "ExampleIssuer",
                SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256),
                IdentityResolver = GetIdentity
            });

            var tokenValidationParameters = new TokenValidationParameters
            {
                // The signing key must match!
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = signingKey,

                // Validate the JWT Issuer (iss) claim
                ValidateIssuer = true,
                ValidIssuer = "ExampleIssuer",

                // Validate the JWT Audience (aud) claim
                ValidateAudience = true,
                ValidAudience = "ExampleAudience",

                // Validate the token expiry
                ValidateLifetime = true,

                // If you want to allow a certain amount of clock drift, set that here:
                ClockSkew = TimeSpan.Zero
            };

            app.UseJwtBearerAuthentication(new JwtBearerOptions
            {
                AutomaticAuthenticate = true,
                AutomaticChallenge = true,
                TokenValidationParameters = tokenValidationParameters
            });

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AutomaticAuthenticate = true,
                AutomaticChallenge = true,
                AuthenticationScheme = "Cookie",
                CookieName = "access_token",
                TicketDataFormat = new CustomJwtDataFormat(
                    SecurityAlgorithms.HmacSha256,
                    tokenValidationParameters)
            });
        }

        private Task GetIdentity(string username, string password)
        {
            // Don't do this in production, obviously!
            if (username == "TEST" || username == "TEST1" && password == "TEST123")
            {
                return Task.FromResult(new ClaimsIdentity(new GenericIdentity(username, "Token"), new Claim[] { }));
            }

            // Credentials are invalid, or account doesn't exist
            return Task.FromResult(null);
        }
    }

Call the above method in partial startup class like below:

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            ConfigureAuth(app);

            app.UseMvc();
        }

Download some configuration file via this link.

Now, add the below code in Value Controller for authentication and role based authorization

 // GET api/values
        [HttpGet]
        [Authorize(Roles = "Admin")]
        public IEnumerable Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        [Authorize(Roles = "User")]
        public string Get(int id)
        {
            return "value";
        }

 

Finally hit the API’s through Postman as below images.

 

If you want to play with JWT and put these concepts into practice, you can use https://jwt.io/ Debugger to decode, verify, and generate JWTs.

Download Sample Source Code

I hope you will enjoy the JWT Bearer Token based Authentication in .Net Core. I would like to have feedback from my blog readers. Your valuable feedback, question, or comments about this article are always welcome.

 

Like it? Share it