Saturday, 15 August 2020

Securing Web API with user authentication and token authorization using custom database

 WebAPI Security, which is most widely popular and needed feature for every developer who is working on services for their client devices. You might have seen many topics on API security over the web but many of them misleading you the actual point where authenticating your users against custom database, issuing a token, authorizing the requests against the issued token and providing the way to generate the refresh token.


This is exactly what we are going to walk through in simple steps without complicating the things.

WebAPI Security

We are going to discuss on below points to fulfil our need on API security in ASP.NET MVC.
  •         OWIN Setup
  •         User Authentication
  •          Token Generation
  •         Refresh Token Generation
  •         Secure API Methods

The affected areas for your project are as shown below. You might not have the providers now, but you will be end up creating them while going through the topic.

Web API Project Files

OWIN Setup:

Microsoft OWIN provides the core features of security for your Web API, which includes the token generation and authorization.

Before you start anything in API security, install the below packages using Package Manager Console or NuGet Package Manager from your Visual Studio in case if you don’t have them now.
  •         Microsoft.AspNet.WebApi.Owin
  •         Microsoft.Owin.Host.SystemWeb
  •          Microsoft.AspNet.Identity.Owin

Add the below code to Startup.Auth.cs which is under App_Start folder. If such file is not found, then add the code which is under ConfigureAuth method to your Startup.cs

public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
//Configure the application for OAuth based flow
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/token"),
Provider = new ApplicationOAuthProvider(),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
RefreshTokenProvider=new ApplicationRefreshTokenProvider(),
AllowInsecureHttp = true
};
//Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
}
The above code snippet will execute upon start of the API project and which enables the bearer authentication to accept the tokens.

You can notice that,
  •         The endpoint URL to generate the token is /token
  •          Initialized the OAuth provider called ApplicationOAuthProvider and refresh token provider called ApplicationRefreshTokenProvider. We will talk about them more in coming section.

User Authentication:

Though we use the OWIN for token generation and authorization, but we are going to have user authentication against our custom database.

Typically, you can have a standard method anywhere in your project to validate the user credentials. For demonstration purpose I am going to have a method with name AuthenticateUserAgainstDB under the Token generation section which describes below.

Token Generation:

For user authentication and generating the token, let us have a provider called ApplicationOAuthProvider which is the same provider told to OWIN in the above code.

The purpose of this provider is to validate the user against the database (first method from below code) and generating the token (second method in below code)

As mentioned in the token endpoint path under OWIN setup, the URL to generate the token is,

public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
public bool AuthenticateUserAgainstDB(string username, string password)
{
//here validate user credentials against your database
//return the bool flag based on valiation
return (username == "user1" && password == "1234!");
}
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
return Task.Factory.StartNew(() =>
{
string userName = context.UserName;
string password = context.Password;
bool flag = AuthenticateUserAgainstDB(userName, password);
if (flag)
{
var claims = new List<Claim>()
{
new Claim(ClaimTypes.Sid, Convert.ToString(userName)),
new Claim(ClaimTypes.Name, userName)
};
ClaimsIdentity oAuthIdentity = new ClaimsIdentity(claims, Startup.OAuthOptions.AuthenticationType);
var properties = CreateProperties("username", userName);
var ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
}
else
{
context.SetError("invalid_grant", "The user name or password is incorrect");
}
});
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// Resource owner password credentials does not provide a client ID.
if (context.ClientId == null)
{
context.Validated();
}
return Task.FromResult<object>(null);
}
public static AuthenticationProperties CreateProperties(string propName, string propValue)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ propName, propValue }
};
return new AuthenticationProperties(data);
}
}
Generate Token

Refresh Token Generation:

As shown in the above OWIN setup section, the validity of the token is about 30 mins and after that the token is no more valid. If you make any API calls with invalid token, you will end up with 401 Unauthorized error.

To generate the refresh token, let us have another provider called ApplicationRefreshTokenProvider which is the same one we passed to OWIN setup.

Generating the refresh token is also like the token generation, except grand type and passing refresh token string which is part of token generation response. The same token generation URL can be used to generate the refresh token.

public class ApplicationRefreshTokenProvider : AuthenticationTokenProvider
{
public override void Create(AuthenticationTokenCreateContext context)
{
context.Ticket.Properties.ExpiresUtc = new DateTimeOffset(DateTime.Now.AddMinutes(30));
context.SetToken(context.SerializeTicket());
}
public override void Receive(AuthenticationTokenReceiveContext context)
{
context.DeserializeTicket(context.Token);
}
}
Refresh Token

 Secure API Methods:

The methods which you don’t want to have anonymous access, just mark them with [Authorize] attribute. If you would like to protect all the methods in the controller, then mark the controller with [Authorize] attribute.

You must get supply the access token to each request to get the response as shown below:

WebAPI Success Call

Your API requests will fail when your access token is expired or invalid as shown below:

WebAPI Failure Call

That’s all now what you need for securing Web APIs. I hope it helps to you in a way you need.

No comments:

Post a Comment