Introduction
In this article, we will learn how to implement Token Based Authentication in Web APIs to secure the data.
There are 4 common methods of Web API Authentication
- HTTP Authentication Schemes (Basic & Bearer)
- API Keys
- OAuth (2.0)
- OpenID Connect
Here we will learn OAuth authentication. OAuth is an open standard for token based authentication and authorization on internet. By using OAuth we can create Token Based Authentication API.
What is Token Based Authentication in Web API?
Token-based authentication is a process where the client application first sends a request to Authentication server with a valid credentials. The Authentication server sends an Access token to the client as a response. This token contains enough data to identify a particular user and it has an expiry time. The client application then uses the token to access the restricted resources in the next requests until the token is valid. If the Access token is expired, then the client application can request for a new access token by using Refresh token.
Advantages of Token Based Authentication
- Scalability of Servers
- Loosely Coupling
- Mobile-Friendly
Let’s discuss the step by step procedure to create Token-Based Authentication.
Step 1. Create ASP.NET Web Project in Visual Studio 2019.
We have to create web project in Visual Studio as given in the below image. Choose ASP.Net Web Application from the menu.
Give the project name as WEBAPITOKENAUTHENTICATION.
Now choose the empty template and check the "MVC" and "Web API" on the right hand side.
Step 2. Addition Of References
In this step,we have to add Nuget References like the below image.
Here we have to add the following references.
- Microsoft.Owin.Host.SystemWeb
- Microsoft.Owin.Security.OAuth
- Microsoft.Owin.Cors
Step 3. Create APIAUTHORIZATIONSERVERPROVIDER.cs Class File
Now, let's create the class file to provide credentials to access data depending on username, password, and roles.
Code is given below
public class ApiAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
if (context.UserName == "admin" && context.Password == "admin")
{
identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));
identity.AddClaim(new Claim("username", "admin"));
identity.AddClaim(new Claim(ClaimTypes.Name, "Hi Admin"));
context.Validated(identity);
}
else if (context.UserName == "user" && context.Password == "user")
{
identity.AddClaim(new Claim(ClaimTypes.Role, "user"));
identity.AddClaim(new Claim("username", "user"));
identity.AddClaim(new Claim(ClaimTypes.Name, "Hi User"));
context.Validated(identity);
}
else
{
context.SetError("invalid_grant", "Provided username and password are incorrect");
return;
}
}
}
Step 4. Create a AuthenticationStartup.cs Class File
Here, we need to create a new class file to implement the code configuration provider and create an instance of class APIAUTHORIZATIONSERVERPROVIDER.
Code is given below.
public class AuthenticationStartup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
var myProvider = new ApiAuthorizationServerProvider();
var options = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = myProvider
};
app.UseOAuthAuthorizationServer(options);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
var config = new HttpConfiguration();
WebApiConfig.Register(config);
}
}
Step 5. Create a APIAUTHORIZEATTRIBUTE.cs Class File.
We need to create this class to handle unauthorized access to resources and show the proper message.
Code is given below.
public class ApiAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (!HttpContext.Current.User.Identity.IsAuthenticated)
{
base.HandleUnauthorizedRequest(actionContext);
}
else
{
actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
}
}
}
Step 6. Create a controller with name UserController
Now we have to create an empty web api controller with name usercontroller. In this controller, we will write the actions with different authorization and roles.
The first action "Get" will be available for anonymous users .No authetication or token is needed for this.
[AllowAnonymous]
[HttpGet]
[Route("api/data/forall")]
public IHttpActionResult Get()
{
return Ok("Now server time is: " + DateTime.Now.ToString());
}
The second action "GetForAuthenticate" only allows the authorized user to access it.
[Authorize]
[HttpGet]
[Route("api/data/authenticate")]
public IHttpActionResult GetForAuthenticate()
{
var identity = (ClaimsIdentity)User.Identity;
return Ok("Hello " + identity.Name);
}
The third action "GetForAdmin" checks authorization and allows only admins to access it.
[Authorize(Roles = "admin")]
[HttpGet]
[Route("api/data/authorize")]
public IHttpActionResult GetForAdmin()
{
var identity = (ClaimsIdentity)User.Identity;
var roles = identity.Claims
.Where(c => c.Type == ClaimTypes.Role)
.Select(c => c.Value);
return Ok("Hello " + identity.Name + " Role: " + string.Join(",", roles.ToList()));
}
Step 7. Accessing the controller using Postman
Now we have to access the controller. For that purpose, we are using postman to get data.I n case ofthe first action "Get",we can access the data without generating a token as no authorization is needed for it, by just sending GET request for route "api/data/forall".
But for the rest of the actions, we have to generate a token using credentials. So we have to do post request for the token.
Now once the token is generated for the "user" now we can easily access the actions by using the user token.
Similarly, we can access the action as "admin" by generating token as admin and then using it.
In the same way, the other actions can be accessed by user or admin depending on the way the token is generated.