In last article, we have seen how to add ASP .NET Core identity to your web API project.
In this blog post, let’s see how to setup your web API project for cookie authentication. We will authenticate the users using the data in ASP .NET Core identity tables for the demo.
Cookie Auth with Web APIs ?
Cookie authentication is recommended for interactive web applications, while JWT (aka bearer token) authentication is recommended for web APIs.
So then why are we trying to apply cookie authentication on Web APIs ? Well, in my opinion, we can understand the concept on how cookie authentication can be configured on web project. Once we know the concept, the same concept can be applied to interactive web applications as well.
Source Code To Begin
If you have followed my previous blog, you will have a Web API project with .NET Core identity already configured.
If not, you can get the base solution from my GitHub repository. We will further extend this to enable Cookie authentication.
The solution has only one project. The project already has all the configurations to setup ASP .NET Core identity.
If you run the EF migrations, it will create the database for you. Again, refer my previous blog article for step by step guide. You should be able to run the solution now.
NuGet package references
As we are using .NET Core API project, the Microsoft.AspNetCore.App metapackage is already referenced in the project.
If you are using any project which is not referencing this NuGet package, then you will be required to add the package reference to Microsoft.AspNetCore.Authentication.Cookies package.
Startup.ConfigureServices method
In Startup.ConfigureServices
, you should to create authentication middleware services using AddAuthentication and AddCookie methods as shown below.
The authentication scheme specified in the AddAuthentication
is just a string (in this case it resolves to “Cookie”). You can specify any string value as Authentication Scheme to distinguish it from other schemes in case there are more than one schemes.
AuthenticationScheme
is useful when there are multiple instances of cookie authentication and you want to authorize with a specific scheme.
You can see that we have specified the cookie expiration time to be 1 minute and we also have enabled sliding expiration for the cookie.
Startup.Configure method
In Startup.Configure
method, call UseAuthentication
and UseAuthorization
methods before calling Use Endpoints
. These methods set HttpContext.User
property and run the authentication middleware for requests.
AuthController Code
Let’s add a new controller with name AuthController
to the project inside the Controllers directory. We will add three methods to this controller – Register, Login and Logout.
The Register
method will add a user to the Identity tables. I created this method because it will be handy to test the login / logout functionality. The Login
method will validate the credentials and Logout
methods will sign out the user.
The CreateAsync
method creates the Identity User in the database. It accepts a clear text password which is hashed and then stored in the AspNetUsers table.
The FindByNameAsync
method finds out the identity by username. So it can be used in Login
method to check if user with provided credentials exists.
Below is the complete code of the AuthController.cs file.
Authorize
Even if login and logout is working properly from your AuthController
, it is not helpful yet. This is because the WeatherForecastController
is actually allowing anonymous calls.
So, for completing the demo, let’s apply the [Authorize]
attribute on the WeatherForecastController
as shown below. You can specify the name of Authentication Scheme which will allow Authorize
attribute to use appropriate scheme for verifying authorization.
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
Now if you try to call the GET action on WeatherForecastController
, it would return 404.
Wait…. what ?
Why 404 instead of 401 ?
Well, actually, I was expecting it to return 401 unauthorized
. But there seems to be an issue in the .NET Core 3 cookie authentication middleware, it tries to redirect the GET call to Account/Login action, which does not exist in our solution. This is the reason why we get 404 Not Found
.
I also tried to change the LoginPath
on cookie policy, to /Auth/Login
which exist in our solution. But it was still trying to redirect the user to Account controller which looks odd.
If you are more curios, refer this issue and this issue on GitHub.
Test in Postman
If your solution is ready, you can test the APIs using Postman. Create the User Registration, Login, Get weather forecast and Logout requests and execute them in the same order for testing the positive flow.
If you are too lazy (like me) to create the Postman requests, you can also use the JSON file from the GitHub solution and import it in the Postman. It will have sample inputs for these for requests..
When you perform login, you do not need to add any additional inputs to Weather Forecast GET request, that is because, Postman automatically uses the cookie which was issued after successful login.
You can download the complete source code of cookie authentication sample from my GitHub repository.
I hope you enjoyed this article. Let me know your thoughts.
Thank you for the amazing post.
404 issue got resolved by adding below Key Value pair.
X-Requested-With : XMLHttpRequest
Glad to know the article was helpful. All the best !
Hi,
Thank you for your amazing post, I got fix the issue 404 code, adding CookieAuthenticationDefaults.AuthenticationScheme as I copied below. I hope help to others.
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
{
options.Events.OnRedirectToLogin = context =>
{
context.Response.Headers[“Location”] = context.RedirectUri;
context.Response.StatusCode = 401;
return Task.CompletedTask;
};
options.SlidingExpiration = true;
options.ExpireTimeSpan = new TimeSpan(0, 1, 0);
});
That is also nice approach. As an alternative and if it is possible for you to change API client, you can also try sending this header ‘X-Requested-With : XMLHttpRequest’ with request as mentioned on the GitHub links. If this header approach works for you, then you do not need the code to override OnRedirectToLogin.
It was a pleasure to read it! Can the user forge these cookies?