Token Based Authentication for Web API where Legacy User Database is used

Introduction

This article gives a detailed explanation on how to use Token Based Authentication using OAuth and OWIN where application is using custom database having user credentials stored in legacy format.

Background

Since many days, I was going through articles about ASP.NET Web API “token based authentication”. Almost all were using ASP.NET Identity for user management features. (Which creates ASPNET* tables to manage users, roles, groups, etc.).

But I was unable to find an article which will show how to use OWIN & OAuth “token based authentication” for existing database having custom User management tables. This is necessary when it comes to apply OAuth authentication to legacy systems having their own user management feature already in place.

So I am writing this article after analyzing a standard template given by Visual Studio for Web API Individual Accounts authentication and tweaking it to use custom DB User tables. I have used Visual Studio 2015 for this.

Using the Code

As discussed above, our problem is, how an existing database User table having UserName, Password stored, can leverage Token based Authentication using OAuth and OWIN. So our typical DB query will look like below. (I have not considered Password encryption for now. I leave it to your application logic.)

Let’s start by creating a standard ASP.NET Web API project as shown below. Please select Web API option from New Project template. Note, we are using “No Authentication” option as we are going to configure it manually.

Since we want to use OAuth for authentication and Entity Framework for DB access, install the below Nuget packages: (They will install their dependants automatically.)

Next, we need to add Entity Framework model connecting to our DB User Table. I won’t go in detail of that as it is a standard procedure of adding ADO.NET Entity Data Model. Resultant EDMX file should look like below:

Next, we need to add OWIN Startup class. It will be a partial class. Add “Startup.Auth.cs” under App_Start folder and paste the below code in it:

Actually, it is the same file which gets generated when we select “Individual Accounts” option in Authentication mode while selecting Web API Project template. The only difference is that we are changing the implementation of “GrantResourceOwnerCredentials” method. Code inside the method should look like below:

Our application is ready to be tested for Token based authentication having a custom user ID/Password table.

Run the application so that API service starts running and is ready to be consumed. Your web page should look like below except the port number after locahost:

Now let’s test standard Web API URL directly if it works without authorization.

Open Chrome Postman and type GET URL for Values Controller. Something like http://localhost:56889/api/Values. It gives Authorization denied error as seen below, obviously because there is no authorization done.

So now, we will obtain a "Bearer Token" after authenticating user credentials. So our Token URL will as follows: http://localhost:56889/Token. Note, “/token” is the path specified as “TokenEndPoint” in “ConfigureAuth” method of Startup class. So if it is configured as “/auth/token”, the complete URL would be http://localhost:56889/Auth/Token likewise.

If you look at the Postman entries, for Token URL, we are passing three parameters with content-type as “x-www-form-urlencoded”. One of the parameters is “grant_type” and its value is “password”. This tells OAuth that user wants token to be issued.

After successful execution of the POST url, we get token issued as below:

What happened here is, this URL has called GrantResourceOwnerCredentials method. In this method, we have written our custom code of User authentication using Entity Framework. If it succeeds, it executes TokenEndpoint method further to issue a bearer token.

Take a note of this token value and re-visit the GET URL of ValuesController. This time, we will be adding a header named “Authorization” and paste token value we have got after authentication as its value with pre-fixing it with “bearer “.

Now this token will be valid till the time we have specified again in OAuthAuthorizationServerOptions in ConfigureAuth method in Startup class.

Comments and Discussions

I have Wrote these all code it's working fine while calling from postman,when i created api project at that time i selected mvc also in that case i am able to see all but how can i get this access_token and expiry time and in mvc project. is there any chance to call "/token" from web and get access-token and expiry time and all information.? am not able to call this api from web.
please help me.

I write my web api step by step with you. and i run this <a href="http://localhost:60523/api/Values"> in post man and its work very god. but when i run http://localhost:60523/token the response is The resource cannot be found. I try many time whit other url. but not work. please if possible connect my computer with teamviewer and help me. this is my mail: hnadi14@gmail.com </a>[<a href="http://localhost:60523/api/Values" target="_blank" title="New Window">^</a>]

Hi
I suppose you are using these roles as custom roles for your application. And it then becomes "Authorization" part of it. This article talks about authentication and not authorization.
For you problem, you can set custom header in Web Request object. And then you may access it using Headers collection in GrantResourceOwnerCredentials method => OAuthGrantResourceOwnerCredentialsContext parameter.
Means, context.Request.Headers will give you all header value collection.
Extract that custom header value (say {"Role":"Admin/User/Group"} from headers collection and use it in your custom code of authentication.
Hope it helps.

Hi,
The solution works when selecting 'individual authorization' while creating web api project.
But it doesn't work when 'no authentication' is selected. I have followed all your steps and tried it twice. Token is generated but the [Authorize] attribute set to the controller doesn't work. That is, it allows access to unauthorized users as well. Is there something missing?
Thanks.