ASP.NET
Web API is a service which can be accessed over the HTTP by any client.
So, providing the security to the Web API is very important, which can
be easily done with the process called Token based authentication.
Token-based authentication is a process where the user send his
credential to the server, server will validate the user details and
generate a token which is send as response to the users, and user store
the token in client side, so client do further HTTP call using this
token which can be added to the header and server validates the token
and send a response. This article will give you a step by step process
to implement the token-based authentication in ASP.NET Web API 2.
TokenEndPointPath : This is a kind of request path client applications which communicate with server directly as part of the OAuth protocol. It must begin with slash “/”
Home=> Index.cshtml
Login Form : In this user request to give their credential, once they submit the form /TOKEN post service is fired, once the service validates the user it will generate a access token and send it is as response to server with username as shown in below figure.
In Login Ajax call success, we are saving the token and user details,
and making another API call /api/values, this function definition is
decorated with [authorize] attribute. we need to pass the access token
as an authorization header whenever this HTTP service request happens
from the client side.
[Authorize] : It is used to authenticate the token send from the client side, once the authentication is successfully the Get() will be fired
Note : we need to send grant_type: 'password' as the data along with user name and password through the body of HTTP request which accessing the URL /TOKEN
From the above figures it is obvious the token is validated, and the service returns a message.
If the credential is wrong the service /TOKEN will return the error message which is shown above
Implementation of Token Based Authentication
Step 1
Open visual studio 2017 => create a new Web API project => Name the project, in my case, I named it as Token_Auth_Web_API, set the Authentication to Individual User Account as shown in below figure.Step 2
Go to Startup.cs file under App_Start folder in the solutionInstall the Owin using the below command in package manager console
- // Configure the application for OAuth based flow
- PublicClientId = "self";
- OAuthOptions = new OAuthAuthorizationServerOptions
- {
- TokenEndpointPath = new PathString("/Token"),
- Provider = new ApplicationOAuthProvider(PublicClientId),
- AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
- AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
- // In production mode set AllowInsecureHttp = false
- AllowInsecureHttp = true
- };
Owin :open web interface for .NET is a middleware which defines the interface between the web server and application.
- Install-Package Owin -Version 1.0.0
TokenEndPointPath : This is a kind of request path client applications which communicate with server directly as part of the OAuth protocol. It must begin with slash “/”
- Provider : The object provided by the application to process the event raised by the authorization server middleware.
- AuthorizeEndpointPath : The request path where the client application will redirect the client/user to obtain user account to issue a token
- AccessTokenExpireTimeSpan : Defines the validity of token
- AllowInsecureHttp : It will allow a normal http request to authorize, if it is set to false, it will process only https request.
Step 3
To register the user, we are going to using api/Account/Register End point from client which is available in AccountController of our WEB API project, as shown below.Go to the Index View of the home controller, as shown in below figure and add the below code
- // POST api/Account/Register
- [AllowAnonymous]
- public async Task<IHttpActionResult> Register(RegisterBindingModel model)
- {
- if (!ModelState.IsValid)
- {
- return BadRequest(ModelState);
- }
- var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
- IdentityResult result = await UserManager.CreateAsync(user, model.Password);
- if (!result.Succeeded)
- {
- return GetErrorResult(result);
- }
- return Ok();
- }
Home=> Index.cshtml
From the above HTML code, it is obvious we have two form
- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
- <h4> Registration Form</h4>
- <div id="loginDiv" style="width:50%">
- <div style="width:50%">
- <div class="form-group">
- <label for="txtEmail">First Name </label>
- <input type='email' name="email" id="txtEmail" class="form-control">
- </div>
- <div class="form-group">
- <label>Password</label>
- <input type="password" id="textPwd" class="form-control">
- </div>
- <div class="form-group">
- <label>Confrim Password</label>
- <input type="password" id="txtConfirmPwd" class="form-control">
- </div>
- </div>
- <button id="register" class="btn btn-default">Submit</button>
- </div>
- <h4>Login </h4>
- <div id="loginDiv" style="width:50%">
- <div class="form-group">
- <label for="txtEmail">First Name </label>
- <input type='email' name="email" id="loginEmail" class="form-control">
- </div>
- <div class="form-group">
- <label>Password</label>
- <input type="password" id="loginPwd" class="form-control">
- </div>
- <button id="btnLogin" class="btn btn-default">Submit</button>
- </div>
- <div>
- <label id="msg"></label>
- </div>
- <script>
- $(document).ready(function () {
- $("#register").on('click', function () {
- var data = { Email: $("#txtEmail").val().trim(), Password: $("#textPwd").val().trim(), ConfirmPassword: $("#txtConfirmPwd").val().trim() };
- $.ajax({
- url: "http://localhost:49501/api/Account/Register",
- type: 'POST',
- data: data,
- success: function (resp) {
- window.location.href = '/Home/Index';
- }
- })
- });
- $("#btnLogin").on('click', function () {
- //var data = { Email: $("#loginEmail").val().trim(), Password: $("#textPwd").val().trim(), ConfirmPassword: $("#loginPwd").val().trim() };
- $.ajax(
- {
- url: "/TOKEN",
- type: "POST",
- data: $.param({ grant_type: 'password', username: $("#loginEmail").val(), password: $("#loginPwd").val() }),
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
- success: function (resp) {
- sessionStorage.setItem('userName', resp.userName);
- sessionStorage.setItem('accessToken', resp.access_token);
- var authHeaders = {};
- authHeaders.Authorization = 'Bearer ' + resp.access_token;
- $.ajax({
- url: "http://localhost:49501/api/values",
- type: "GET",
- headers: authHeaders,
- success: function (response) {
- $("#loginEmail").val("");
- $("#loginPwd").val("");
- $("#msg").text(response);
- }
- });
- },
- error: function () {
- $("#msg").text("Authentication failed");
- }
- })
- });
- })
- </script>
- Registration Form
- Login Form
Login Form : In this user request to give their credential, once they submit the form /TOKEN post service is fired, once the service validates the user it will generate a access token and send it is as response to server with username as shown in below figure.
[EnableCors(origins: "*", headers: "*", methods: "*", exposedHeaders: "X-My-Header")] : Enabled the CROS origin, so that it can be accessed from any domain
- // GET api/values
- [EnableCors(origins: "*", headers: "*", methods: "*", exposedHeaders: "X-My-Header")]
- [Authorize]
- public IEnumerable<string> Get()
- {
- return new string[] {"You are successfully Authenticated to Access the Service"};
- }
[Authorize] : It is used to authenticate the token send from the client side, once the authentication is successfully the Get() will be fired
Client-side HTTP request with Authorization Header
authHeaders.Authorization = 'Bearer ' + resp.access_token : We are defining the authorization header with the access token when the /api/values HTTP call happens. In server side the token is validated, once its success it will return a message “You are successfully Authenticated to Access the Service”
- $("#btnLogin").on('click', function () {
- $.ajax(
- {
- url: "/TOKEN",
- type: "POST",
- data: $.param({ grant_type: 'password', username: $("#loginEmail").val(), password: $("#loginPwd").val() }),
- headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
- success: function (resp) {
- sessionStorage.setItem('userName', resp.userName);
- sessionStorage.setItem('accessToken', resp.access_token);
- var authHeaders = {};
- authHeaders.Authorization = 'Bearer ' + resp.access_token;
- $.ajax({
- url: "http://localhost:49501/api/values",
- type: "GET",
- headers: authHeaders,
- success: function (response) {
- $("#loginEmail").val("");
- $("#loginPwd").val("");
- $("#msg").text(response);
- }
- });
- },
- error: function () {
- $("#msg").text("Authentication failed");
- }
- })
Note : we need to send grant_type: 'password' as the data along with user name and password through the body of HTTP request which accessing the URL /TOKEN