Authentication is a vital process in system programming. Authentication means verifying the user who is accessing the system. Today, we are using modern devices that have different types of apps or software and sometimes, we directly access the website from the browser. To access this application, we probably need to pass our credentials and these systems verify it. If you are a valid user, then it will allow accessing the system otherwise not.
We have available different types of authentication in .NET programming like Windows Authentication, Forms Authentication, Claim Based Authentication, Token Based Authentication etc. Today, we will discuss Token Based Authentication in detail.
What is Token Based Authentication?
Token Based Authentication is not very different from other authentication mechanisms but yes, it is more secure, more reliable, and makes your system loosely coupled. It will be a better choice to create REST APIs using token-based authentication if your API has reached a broad range of devices, like mobiles, tablets, and traditional desktops.
In token based authentication, you pass your credentials [user name and password], which go to the authentication server. The server verifies your credentials and if it is a valid user, then it will return a signed token to the client system, which has an expiration time. The client can store this token for locally using any mechanism like local storage, session storage etc. and if the client makes any other call to the server for data, then it does not need to pass its credentials every time. The client can directly pass the token to the server, which will be validated by the server and if the token is valid, then you will able to access your data.
How to implement
In this demonstration, we will use Web API as a service and Angular JS as a client. So, let me create dummy database “Test” and two tables “Users” and “Employee” respectively. Users table will store the user related information like name, username, and password. Employee table is basically for dummy data. You can use the following SQL script to generate this database and tables.
CREATE DATABASE TEST
GO
USE TEST
GO
CREATE TABLE Users(Id INT IDENTITY(1,1) PRIMARY KEY, Name varchar(255) NOT NULL, UserName varchar(50), Password varchar(50))
INSERT INTO [TEST].[dbo].[Users](Name, UserName, Password) VALUES('Mukesh Kumar', 'Mukesh', AAAAAA');
CREATE TABLE Employees(Id INT IDENTITY(1,1) PRIMARY KEY, Name varchar(255) NOT NULL, Address varchar(500))
INSERT INTO Employees (Name, Address) VALUES('Mukesh Kumar', 'New Delhi')
INSERT INTO Employees (Name, Address) VALUES('John Right', 'England')
INSERT INTO Employees (Name, Address) VALUES('Chris Roy', 'France')
INSERT INTO Employees (Name, Address) VALUES('Anand Mahajan', 'Canada')
INSERT INTO Employees (Name, Address) VALUES('Prince Singh', 'India')
Move to the next part and create a service that will implement token-based authentication. So, we're going to create a Web API project and for the client application, we will use AngularJS from where we will pass user credentials.
To create Web API project, first, open Visual Studio 2015 and go to File >> New >> Project. It will open New Project window. Select "Web" from Installed Template and then from the right pane, choose “ASP.NET Web Application”. Provide the name like “EmployeeService” and click OK.
The next window will provide you options to choose web application template. Here, you need to choose Web API with No Authentication and click OK. Therefore, your application is ready to run.
Before moving on, to implement token-based authentication, we have to add fthe ollowing packages as a references from NuGet Package Manager. So, just right click on references in solution and select Manage NuGet Packages. It will open NuGet Package Manager Windows; you can search these packages one by one from search box in Browse tab. Once these packages are able to find out in NuGet click to install; After Installation, these packages will be available in references.
- Microsoft.Owin
- Microsoft.Owin.Host.SystemWeb
- Microsoft.Owin.Security.OAuth
- Microsoft.Owin.Security
- Microsoft.AspNet.Identity.Owin
In this demonstration, we will not use Global.asax file. So, first, delete the Global.asax from solution and add new class “Startup.cs” at the same location of Global.asax file and add following code.
using EmployeeService.Provider;
using Microsoft.Owin;
using Microsoft.Owin.Security.OAuth;
using Owin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
[assembly: OwinStartup(typeof(EmployeeService.Startup))]
namespace EmployeeService
{
public class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
var OAuthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(20),
Provider = new SimpleAuthorizationServerProvider()
};
app.UseOAuthBearerTokens(OAuthOptions);
app.UseOAuthAuthorizationServer(OAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
}
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
}
In the above code, you can see, we are using OWIN [Open Web Interface for .Net] that is an interface between your web server and web application. So, it works as a middleware in applications, which process your incoming request and validate it. Here we are using SimpleAuthorizationServerProvider, which is nothing but a class which validate user based on their credentials. You can find this class code at the last.
Now it’s time to create a model where we can perform database operations like fetching the user information based on credentials and employee data. We can use different ways here to get data like Repository pattern with Unit of work or Dapper. But we want to make this example simple and keep the main focus on Token Based Authentication only. So, right click on solution and Click to add and then New Item and choose Ado.Net Entity Model.
Next window will provide you several options to connect your code with database. Here, we are selecting the first one, "EF Designer from database". It will create POCO classes for database's tables.
?
In the next window, you need to choose New Connection and it provides all the details to access your database. Once you will be provided all details, just click on Test Connection to check if everything is correct and move to Next.
Once your connection is created with database, you will find all your database components like tables, views and SPs. So, here you just need to select only Tables and click to finish.
Once you click to finish, it will generate all database components as model in EmployeeModel.edmx file like the following image.
Now it’s time to create a new controller to get employee data; so, you will need to add new controller as EmployeeController and add following code.
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace EmployeeService.Controllers
{
public class EmployeeController : ApiController
{
[HttpGet]
[Authorize]
public List<Employee> GetEmployees()
{
using (var db = new TESTEntities())
{
var employees = db.Employees.ToList();
return employees;
}
}
}
}
As we discussed above, to validate user, we are using "SimpleAuthorizationServerProvider" class which inherits from OAuthAuthorizationServerProver. Here we are overriding two methods. First one is ValidateClientAuthentication, which will validate the request. And second one is GrantResourceOwnerCredentials, which will grant to access application based on your credentials. So, basically in this method, we are validating to user. So, it validates every request and verifies your credentials and returns the token.
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.OAuth;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web.Http.Cors;
namespace EmployeeService.Provider
{
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated(); //
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
using (var db = new TESTEntities())
{
if (db != null)
{
var empl = db.Employees.ToList();
var user = db.Users.ToList();
if (user != null)
{
if (!string.IsNullOrEmpty(user.Where(u => u.UserName == context.UserName && u.Password == context.Password).FirstOrDefault().Name))
{
identity.AddClaim(new Claim("Age", "16"));
var props = new AuthenticationProperties(new Dictionary<string, string>
{
{
"userdisplayname", context.UserName
},
{
"role", "admin"
}
});
var ticket = new AuthenticationTicket(identity, props);
context.Validated(ticket);
}
else
{
context.SetError("invalid_grant", "Provided username and password is incorrect");
context.Rejected();
}
}
}
else
{
context.SetError("invalid_grant", "Provided username and password is incorrect");
context.Rejected();
}
return;
}
}
}
}
At the end, you just need to Enable CORS in WebAPIConfig file.
using Newtonsoft.Json.Serialization;
using System.Linq;
using System.Net.Http.Formatting;
using System.Web.Http;
using System.Web.Http.Cors;
namespace EmployeeService
{
public 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 }
);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
}
}
So, everything is setup and looks good. Let's move to test our service. To test this open PostMan Chrome Extension and choose GET method and provide the API URL and click to Send. You can see with below image that your request has been denied by the server.
Now, it’s time to validate user first and get the token. And this token will be passed with next call in the header. So, select the method as POST and pass TOKEN URL as following image shows and provide your credentials. For me, username ="Mukesh" and password="*******". Don't forget to mention grant_type as password. If everything will be set up, click to send button.
Once server validates your credentials it will correct then it will return an access_token with expiry time as following.
Now you need to call same API call as we have called earlier but this time you will need to pass your token in Headers using "Authorization" key. Token should be passed followed by "bearer yourtoken". Now you can see that we are able to get the employee data. It is because we are a valid user.
Conclusion
So, we have seen how to implement Token Based Authentication in Web API and in the next part we will see how to use this token in angular js applications.
I hope this post helps you. Please put your feedback using comments which will help me improve for the next post. If you have any doubts, please ask your doubts or query in the comments section.
Posted Comments :
sharafath Posted : 7 Years Ago
Not working. Token Error . Its Says band request for token request
Nick Posted : 7 Years Ago
How do you add .expires, .issued, and username properties in the returned token? the other examples i see online all have these 3 properties but I don't see it here?
Bhavik Posted : 7 Years Ago
Great :)
Jorge Vera Posted : 7 Years Ago
Mukehs thank you for your sample, it really help me a lot, I will add the following if you let me please. I used VS 2015 and create the project by default it went to .net 4.5 the current version of of the OWIN lib is 4.0.0 so I have to run these commands in the Package Manage Console to make it work. Install-Package Microsoft.AspNet.WebApi.Cors Install-Package Microsoft.AspNet.Identity.Owin -Version 2.2.1 Install-Package Microsoft.Owin.Security -Version 3.1.0 Install-Package Microsoft.Owin.Security.OAuth -Version 3.1.0 Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.1.0 Install-Package Microsoft.Owin -Version 3.1.0 Thanks a lot!
Tayyaba Posted : 7 Years Ago
Error ....Internal Server Error... I have implemented same code in my project
Muhammad Awais Posted : 7 Years Ago
Perfect Article In case you are getting problem in "System.Web.Http.Cors" Please install "Install-Package Microsoft.AspNet.WebApi.Cors" package
Muhammad Awais Posted : 7 Years Ago
Perfect Article In case you are getting problem in "System.Web.Http.Cors" Please install "Install-Package Microsoft.AspNet.WebApi.Cors" package
Dukhi Atma Posted : 6 Years Ago
Its Not Working. Please share code if available otherwise go to hell
Umesh Posted : 6 Years Ago
Hi Mukesh, I am getting below error, HTTP Error 403.14 - Forbidden The Web server is configured to not list the contents of this directory. Can you help me to resolve it? Thanks
Pradip Chavhan Posted : 6 Years Ago
Hi Mukesh, Have you created class for "EnableCorsAttribute" because it's showing an error. If yes please share details, if no why it is showing error. please elaborate more details.
kashave kumar Posted : 6 Years Ago
Hi Mukesh i have implement token based authentication. i am facing one issue, the issue is that when return collection from database, it convert firstletter to small. like Id to id, Name to name and Address to address. I want same collection ( same format) as declare in code.
Bill Posted : 6 Years Ago
It is working perfectly. However your need to follow each step carefully. Another issue is that the nuget installation is a bit annoying.
Upendra Posted : 6 Years Ago
Hi Mukesh, Nice article. Working properly.
Nibir Posted : 6 Years Ago
Hi, nice and clean article, working fine. Could you please provide some pointer for similar authentication in ASP.NET webform please.
mohammad reza Posted : 6 Years Ago
tank u veryyyyyyy much
sushant Posted : 6 Years Ago
token call not declare
Tam Nguyen Posted : 6 Years Ago
Thank you very much!
Przemek Posted : 6 Years Ago
Hello, Everything works as described. I have only one question: How do you configure all this using the https protocol? regards
aitzaz ahsan Posted : 6 Years Ago
how i can Logout functionality. After Token generation how i can logout or delete functionality can you tell me please
aitzaz ahsan Posted : 6 Years Ago
how i can Logout functionality. After Token generation how i can logout or delete functionality can you tell me please
Sachin V Posted : 6 Years Ago
Nice Article, Setup successfully and working for me. Thanks!!! Could you please give us an example to validating via roles on method like [Authorize(Roles = "admin")]?
Reza Posted : 6 Years Ago
Thanks very much...good example...work...
John Kraft Posted : 6 Years Ago
Great article... it saved me hours and hours of research and trial / error. Adapted your example to my existing app, and it worked great.
ankush Posted : 6 Years Ago
not working
Jaynit Posted : 6 Years Ago
In Startup.cs Class file .Put ConfigureAuth Method down the configuration.
Rekha Posted : 6 Years Ago
THANK YOU , this code really works
sumen Posted : 6 Years Ago
Thanks, it is working fine.
Arunkumar Posted : 6 Years Ago
Hi Mukesh, I am getting below error, HTTP Error 403.14 - Forbidden The Web server is configured to not list the contents of this directory. Can you help me to resolve it? Please any one fix this problem.
Rajalakshmy Posted : 6 Years Ago
Works Perfectly
Siva Posted : 6 Years Ago
Nice ji.but its showing invalid grant type
Akram Ali Posted : 6 Years Ago
Thanks Mukesh,Really helped me... If any one face issue on grant type then put "application/x-www-form-urlencoded"(without quote) in content-type header key.I have tested this in Postman
jyotiram Posted : 5 Years Ago
Hi sir, I am try this code in my project and its working fine, but its working when i am passing username and password then token has created, but i want to generate token at the Registration time. please help me on this. how we can generate token at registration time in web api.
shahbaz hussain Posted : 5 Years Ago
Excellent article, Everything is perfect!
Swati Posted : 5 Years Ago
I am not able to get the access token. It is displaying null reference exception in the postman. Can somebody please help me?
Srinivas Puli Posted : 5 Years Ago
It woking fine great article
Srinivasulu Puli Posted : 5 Years Ago
Hi Swathi You can follow this https://stackoverflow.com/questions/29360349/getting-error-unsupported-grant-type-when-trying-to-get-a-jwt-by-calling-an
Ali Abbas Posted : 5 Years Ago
Facing this issue when I run the application HTTP Error 403.14 - Forbidden The Web server is configured to not list the contents of this directory.
Anonymous Posted : 5 Years Ago
what is user of Grant type Parameter when we post
Curious Posted : 5 Years Ago
What is the use Of 'grant_type' when we perform Post Method
Saurabh Maheshwari Posted : 5 Years Ago
Hi Mukesh, First of all, thanks for this excellent article. It helped me to build an api I was trying to build since a week. But the code is not working when I am passing a incorrect password. The code fails at this step in SimpleAuthorizationServerProvider class: if (!string.IsNullOrEmpty(user.Where(u => u.UserName == context.UserName && u.Password == context.Password).FirstOrDefault().Name)) Error: Object reference not set to an instance of an object. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Exception Details: System.NullReferenceException: Object reference not set to an instance of an object. I see that many other people are also facing the error but I have not seen any replies from your side. Appreciate if you can be more involved with your visitors when they have doubts in your code and help them accordingly. Thanks & Cheers buddy! You are doing a great work.
Dinesh kumar Posted : 5 Years Ago
Hi Mukesh kumar it's good tutorial to learn but i have small doubt. can you make it this application in two project one will be MVC Application and another in WEBAPI2 because i want to send all request from WEB application even the token generation request should also go from web, and token expiry job also appear in web application if token is going to expire just before one minute show alert message for continue and, all controller should be based on role and users Authorized and Authenticate if this kind of project you have done then please let me know. my email id is dineshkumar9890@gmail.com
Randeep Posted : 5 Years Ago
Thanks. Wonder if you can provide example as per request by Dinesh.
Fidele Posted : 4 Years Ago
It is verry good, it's work perfectly. Thanks!
Bhavdip Posted : 4 Years Ago
too many error return can you please give me your code in git
BHAVDIP Posted : 4 Years Ago
I need your help, I have already implemented this article (http://www.programmingwithmukesh.com/articles/web-api/token-based-authentication-in-web-api) and delete the global.asax file then my web API not working. please check error image: https://www.screenpresso.com/=xBpWe if you give your contact number then its well and good.
Swapna Thomas Posted : 3 Years Ago
Good article which explained Token based authentication step by step. I got some dll related errors which I have solved by installing below OWIN packages by using Package Manager Console. Install-Package Microsoft.AspNet.WebApi.Cors Install-Package Microsoft.AspNet.Identity.Owin Install-Package Microsoft.Owin.Security Install-Package Microsoft.Owin.Security.OAuth Install-Package Microsoft.Owin.Host.SystemWeb Install-Package Microsoft.Owin
Bilalkareem Posted : 3 Years Ago
Hi. I have developed the web api dll with authorization token and using the self hosting server , i hosted the site in my local PC ex:localhost:8080 and while trying ti get token using localhost:8080/token , it no working and says site not found
deva Posted : 7 Years Ago
It is giving error while i retriving the token,Is there any other password that mention in database