Search This Blog

Sunday 16 December 2018

Refresh Token in Web API using OWIN


Step 1: - Open Visual Studio 2015 => Go to File Menu => New => Project...

Step 2: - In the Installed Templates list, select Visual C# => Web

Step 3: - Select ASP.Net Web Application (.NET Framework) from the Web list => Type TokenAuthentication in the Name box and click OK

Step 4: - Select Empty template from ASP.NET Templates List and Check Web API check box under Add folders and core references for:































Step 5: - Right Click on Models folder => Add => New Items... => Expand Visual C# from Left Pane and Select Code => Select Class from Middle Pane => Type Author.cs in Name box => Click Add

Copy Past following code in Author.cs

namespace TokenAuthentication.Models
{
    public class Author
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Address { get; set; }
        public string Status { get; set; }

    }
}

Step 6: - Right Click on Controllers folder => Add => Controller... => Select Web API Controller - Empty => Click Add => Type DefaultController in Controller Name box => Click Add

Copy Past following code in DefaultController

using System.Collections.Generic;
using System.Web.Http;
using TokenAuthentication.Models;

namespace TokenAuthentication.Controllers
{
    public class DefaultController : ApiController
    {
        [HttpGet]
        [Authorize]
        public List<Author> GetAuthor()
        {
            List<Author> author = new List<Author>() {
                new Author() {Id=1,FirstName="Ram",LastName="G",Address="Malad",Status="A" },
                new Author() {Id=2,FirstName="Shyam",LastName="G",Address="Kandivali",Status="A" },
                new Author() {Id=3,FirstName="Ghanshyam",LastName="G",Address="Borivali",Status="A" }
            };
            return author;
        }
    }
}

Step 7: - Right click on References => Click on Manage NuGet Packages... => Click on Browse => Search bellow list one by one => Select result => Click on Install

Microsoft.Owin























Microsoft.Owin.Host.SystemWeb
























Microsoft.Owin.Security.OAuth
Microsoft.Owin.Security
























Microsoft.AspNet.Identity.Owin
























Microsoft.AspNet.WebApi.Cors
























Step 8: - Right Click on Project Root folder => Add => New Folder => Name "Provider"

Step 9: - Right Click on Provider folder => Add => New Items... => Expand Visual C# from Left Pane and Select Code => Select Class from Middle Pane => Type AuthorizationServerProvider.cs in Name box => Click Add

Copy Past following code in AuthorizationServerProvider.cs

using Microsoft.Owin.Security;
using Microsoft.Owin.Security.OAuth;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web.Http.Cors;

namespace TokenAuthentication.Provider
{
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
    {
        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
        }

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

            //Write you DB logic here
            if (!context.UserName.Equals("Ram") && !context.Password.Equals("password@123"))
            {
                context.SetError("invalid_grant", "The user name or password is incorrect.");
            }
            else
            {
                var propertyDictionary = new Dictionary<string, string> {
                {
                    "userName", context.UserName
                }};
                var identity = new ClaimsIdentity(context.Options.AuthenticationType);
                var properties = new AuthenticationProperties(propertyDictionary);
                var ticket = new AuthenticationTicket(identity, properties);
                context.Validated(ticket);
            }
        }
    }
}

Step 10: - Right Click on Provider folder => Add => New Items... => Expand Visual C# from Left Pane and Select Code => Select Class from Middle Pane => Type RefreshTokenProvider.cs in Name box => Click Add

Copy Past following code in RefreshTokenProvider.cs

using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Infrastructure;
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

namespace TokenAuthentication.Provider
{
    public class RefreshTokenProvider : IAuthenticationTokenProvider
    {
        private static ConcurrentDictionary<string, AuthenticationTicket> _refreshTokens = new ConcurrentDictionary<string, AuthenticationTicket>();

        public void Create(AuthenticationTokenCreateContext context)
        {
            throw new NotImplementedException();
        }

        public async Task CreateAsync(AuthenticationTokenCreateContext context)
        {
            var guid = Guid.NewGuid().ToString();

            // Set lifetime of refresh token 
            var refreshTokenProperties = new AuthenticationProperties(context.Ticket.Properties.Dictionary)
            {
                IssuedUtc = context.Ticket.Properties.IssuedUtc,
                ExpiresUtc = DateTime.UtcNow.AddMinutes(60)
            };

            var refreshTokenTicket = new AuthenticationTicket(context.Ticket.Identity, refreshTokenProperties);

            _refreshTokens.TryAdd(guid, refreshTokenTicket);

            context.SetToken(guid);
        }

        public void Receive(AuthenticationTokenReceiveContext context)
        {
            throw new NotImplementedException();
        }

        public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {
            AuthenticationTicket ticket;
            string header = context.OwinContext.Request.Headers["Authorization"];

            if (_refreshTokens.TryRemove(context.Token, out ticket))
            {
                context.SetTicket(ticket);
            }
        }
    }
}

Step 11: - Right Click on Project Root folder => Add => New Items... => Expand Visual C# from Left Pane and Select Code => Select Class from Middle Pane => Type Startup.cs in Name box => Click Add

Copy Past following code in Startup.cs

using Microsoft.Owin;
using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
using System.Web.Http;
using TokenAuthentication.Provider;

namespace TokenAuthentication
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            ConfigureAuth(app);
        }

        public void ConfigureAuth(IAppBuilder app)
        {
            var OAuthOptions = new OAuthAuthorizationServerOptions
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(20),
                Provider = new AuthorizationServerProvider(),
  RefreshTokenProvider = new RefreshTokenProvider()
            };

            app.UseOAuthBearerTokens(OAuthOptions);
            app.UseOAuthAuthorizationServer(OAuthOptions);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

            HttpConfiguration config = new HttpConfiguration();
            WebApiConfig.Register(config);
        }
    }
}

Step 12: - Open/Expand App_Start folder => Open WebApiConfig.cs file => Add following line

using System.Web.Http;
using System.Web.Http.Cors;

namespace TokenAuthentication
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");
            config.EnableCors(cors);

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}
All Done

Run Project

Step 13: - Launch Postman

Step 14: - Copy Past following URL in URI and Value in Body tab and Hit Send button

username   -    Ram
password   -    password@123
grant_type -    password



Note: -

If following error occurred open Manage NuGet Packages... and Search Newtonsoft.Json in Browse tab and update it.

Server Error in '/' Application.

Could not load file or assembly 'Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)





















Step 15: - Copy Past following URL in URI and Copy Past Step 13 access_token in Header tab and Hit Send button


Authorization   -   Bearer PJzq0Miq4T6vPMMg-SSRJGbKdNcD7Cscib1t_Sa1msY1lwzHV1Sm8QAwd1wk8e_PkTwLTnl6jDBcnTaCePYXaFxRC02Nfdt8zRT-b5wNX4MNAzFTSbUSECB-we_6ojI2acW01a6lJXAlpT6O1jVtaJvziRgNJGLo9GNrHrKLCm2u_0oK3G0YKxabGiq7MFCZuVwhv-ImlZCHxOrLJGQZSw























Note: -

Token expired in 20 minutes and Refresh Token expired in 60 minutes. After 20 minutes Token will be expired and you need to sign in again. In that case use refresh token to sign in instead of passing username and password again.

Step 16: - Copy Past following URL in URI and Value in Body tab and Hit Send button

username         -            Ram
refresh_token -            d343d805-341d-491d-b5dd-ff87ddf9b5d2
grant_type                 refresh_token