In this article, we will learn how to implement Token Based Authentication in Web API to secure the server resources using OAuth.
Introduction
In this article, we will learn how to implement Token Based Authentication in Web API to secure the server resources.
There are 3 Common Methods of Web API Authentication.
- HTTP Basic Authentication
- API Keys
- OAuth
Here I am using OAuth authentication. OAuth is not technically an authentication method, but a method of both authentication and authorization. By using OAuth we can create Token Based Authentication API. First, what is Token Based Authentication in Web API, advantages of Token Based Authentication in Web API and how does it work?
What is Token-Based Authentication in Web API?
Token-based authentication is a process where the user sends his credentials to the server. the server will validate the user details and generate a token which is sent as a response to the users with each and every request. This token is then used to access protected pages or resources instead of the login credentials for a designated period of time. This is called the Token Based Authentication approach.
Advantages of Token-Based Authentication
- Scalability of Servers
- Loosely Coupling
- Mobile Friendly
How Does Token-Based Authentication Work?
When a user enters the name and password into the browser or mobile devices it sends these credentials (username and password) to the Authorization Server. Then the Authorization Server authenticates the username and password and then it generates an access token and returns it as a response to the user. This Access Token contains the identity of a user and also contains the token expiry time. Then the client application includes the Access Token in the Authorization header of the HTTP request to access the restricted resources from the Server until the token is expired.
Creating the Application.
Here I am using Visual Studio 2019 .NetFrameWork 4.7 and Sql Server 2012 to create the example.
Step 1. Creating the Database.
First, we create a table to store user info.
Open SQL Server to create a database with any suitable name and then, create the table.
Here, I am using "OauthApi" as the database name and "ApiUsers" as the table name.
Tables Structure
CREATE DATABASE OauthApi
GO
USE [OauthApi]
CREATE TABLE [dbo].[ApiUsers](
[UserId] [int] IDENTITY(1,1) NOT NULL,
NULL,
NULL,
NULL,
CONSTRAINT [PK_ApiUsers] PRIMARY KEY CLUSTERED
(
[UserId] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT INTO ApiUsers VALUES(1, 'Amit', '123456', 'SuperAdmin')
INSERT INTO ApiUsers VALUES(2, 'Subash', 'abc123', 'User')
INSERT INTO ApiUsers VALUES(3, 'Alok', '123abc123', 'Admin')
GO
Step 2.1. Creating the Project
Open Visual Studio, and click on "Create a new project".
Select the ASP.NET web application from the templates and click on "Next".
Then, give the project name as "OauthApp" and then click "Create".
Now, choose Web API from the template and click on "Create".
Now the application is created.
Step 2.2. Add references from NuGet packages to the application
After creating the application we have to add the following references from NuGet packages to the application.
- Microsoft.Owin.Host.SystemWeb
- Microsoft.Owin.Security.OAuth
- Microsoft.Owin.Cors
- Microsoft.AspNet.Identity.Owen
Step 2.3. Creating the ADO.NET Entity Data Model
To add ADO.NET Entity Data Model right right-click on the "Models" folder then go to "Add" then click on "New Item" and it will show the "Add New Item" dialog box. From the left pannel choose "Data" and then from the right pannel choose "ADO.NET Entity Data Model", named "DataContext" and click on "Add".
It will open the "Entity Data Model Wizard" dialog box. Choose "EF Designer from the database" and click on "Next".
It will open the data connection wizard dialog box. Here, create a new data connection string for data access from the database to the application. Next, click on "New Connection".
It will open the connection properties dialog box. Here, we can see ASO.NET data model provides two types of connection and we can use it as per our requirement. Here, I am using "SQL Server Authentication" connection properties and selecting the database name and test connection. If it succeeds then press the "OK" button.
Now, we can see the created connection string in the below image. Here, check the checkbox for the created connection string and save on the application's web. config file. Then, press Next.
It will open one more dialog box for Database Object and Setting. Here we can see the created database object list. Here, we can select the data table from all available tables give the Model Namespace as "DataContextModel" and click on Finish.
Now, you can see the created "DataContext.edmx" in the "Models" folder. In this created model, you can see the Model class and diagram as shown in the below image.
Step 2.4. Add "Startup" Class and add support for OAuth Bearer Tokens Generation.
Right-click on your project then add a new class named "Startup". To do so, go to the Solution Explorer > Right Click on Project Name from the Solution Explorer > Add > New Item > Select class > Enter the class name as Startup. cs > and then click on the Add button and it will contain the code below:
using Microsoft.Owin;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Security.OAuth;
using OauthApi.Provider;
using Owin;
using System;
using System.Web.Http;
namespace OauthApi
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
public void ConfigureAuth(IAppBuilder app)
{
// This is very important line Cross Origin Source (CORS) it is used to enable cross-site HTTP requests
// For security reasons, browsers restrict cross-origin HTTP requests
app.UseCors(CorsOptions.AllowAll);
var OAuthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30), // Token expiration time
Provider = new OauthProvider()
};
app.UseOAuthBearerTokens(OAuthOptions);
app.UseOAuthAuthorizationServer(OAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config); // Register the request
}
}
}
Here we created a new instance of the "OAuthAuthorizationServerOptions" class and then set the path for generating the tokens as "http://localhost:port/token". We have specified the expiry time for the access token as 30 minutes. We have also specified the implementation on how to validate the client credentials for users asking for the access tokens in the custom class named "OauthProvider". Then we passed the options to the extension method "UseOAuthAuthorizationServer" which will add the authentication middleware to the pipeline.
No need to use Global.asax class and fire up the Application_Start event after we’ve configured our "Startup" class so feel free to delete it.
Step 2.5. Implement the "OauthProvider" class
Add a new folder named "Providers" to the project then add a new class named "OauthProvider", and paste the below code snippet to it.
using Microsoft.Owin.Security.OAuth;
using OauthApi.Models;
using System;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace OauthApi.Provider
{
public class OauthProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
await Task.Run(() => context.Validated());
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
using (var db = new DataContext())
{
if (db != null)
{
var user = db.ApiUsers.Where(o => o.UserName == context.UserName && o.UserPasswd == context.Password).FirstOrDefault();
if (user != null)
{
identity.AddClaim(new Claim(ClaimTypes.Role, user.UserRole));
identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
identity.AddClaim(new Claim("LoggedOn", DateTime.Now.ToString()));
await Task.Run(() => context.Validated(identity));
}
else
{
context.SetError("Wrong Credentials", "Provided username and password is incorrect");
}
}
else
{
context.SetError("Wrong Credentials", "Provided username and password is incorrect");
}
return;
}
}
}
}
In the above code the "OauthProvider" class inherits from class "OAuthAuthorizationServerProvider", we’ve overridden two methods "ValidateClientAuthentication" and "GrantResourceOwnerCredentials". The "ValidateClientAuthentication" method is responsible for validating the "Client" and the "GrantResourceOwnerCredentials" method is responsible for validating the username and password sent to the authorization server’s token endpoint.
Step 3. Modify Web API Controller
Now we will add an action method "GetValues" to "ValueController" so that we can check whether the Token-Based Authentication is working fine or not. To do that open the ValueController and add the below action method to it.
// This method is for all types of role
[Authorize(Roles = "SuperAdmin, Admin, User")]
[HttpGet]
[Route("api/values/getvalues")]
public IHttpActionResult GetValues()
{
var identity = (ClaimsIdentity)User.Identity;
var roles = identity.Claims
.Where(c => c.Type == ClaimTypes.Role)
.Select(c => c.Value);
var LogTime = identity.Claims
.FirstOrDefault(c => c.Type == "LoggedOn").Value;
return Ok("Hello: " + identity.Name + ", " +
"Your Role(s) are: " + string.Join(",", roles.ToList()) +
"Your Login time is :" + LogTime);
}
Testing the Web API Application
To test this first, you need to run your Web API application. Here I am using a client tool called Postman to test web API.
Step 4.1. Test without Access Token
Open the Postman application and provide the necessary details as given in the below image.
Here we will get 401 unauthorized responses.
Step 4.2. Create the Access Token
First, we try to create an Access Token with invalid credentials.
Here we will get the status as 400 Bad Request and also get the error describing that the provided username and password are incorrect. Let’s generate the access token with valid credentials as shown in the below image.
Now we will get status code 200 OK and access token value, token type as Bearer, and the token expiration in seconds in the Response section.
Step 4.3. Test with Access Token
Copy the access token and use it as shown in the below image.
If all is correct we’ll receive HTTP status 200 along with the secured data in the response body.
In this article, we will learn how to create Access Token and how to use it using Token Based Authentication. Hope this article will help the readers. Happy Coding!