swirl
Home Software Blog Wallpapers Webtools
Custom authentication schemes in ASP.NET Core
Sunday 13, December 2020   |   Post link
Logo

Overview

This blog posts demonstrates how a custom authentication scheme can be used in DotNet Core Web API.

Recap the basics

We all know this but it's always good to remind ourselves of this - authentication is the proces of determing whothe person is or determining if the user is really who he says he is. Authorization is determining if the user is allowed to perform a certain operation.

The six guiding principles of RESTful APIs talk nothing of authentication nor authorization. The example discussed here will break the stateful principle by storing an authentication state of users. That's OK since the main aim is to discuss how a custom authentication scheme can be implemented. The technique discussed here can be used without maintaining state on the server which is how JWTs work.

The authentication machanism

The service has two endpoints:

  • WeatherForecast - requires the caller to be already authenticated. Returns weather forecast data
  • authenticate - used by a caller for authenticating itself with the service

The authentication flows is depicted in the image below.

Authentication flow

Protecting the weather forecast route

The Get() method is protected by adding an Authorize attribute. We also specify the name of the authentication scheme.
[HttpGet]
[Authorize(AuthenticationSchemes = TokenAuthenticationSchemeOptions.Name)]
public IEnumerable Get()
{
	var rng = new Random();
	return Enumerable.Range(1, 5).Select(index => new WeatherForecast
	{
		Date = DateTime.Now.AddDays(index),
		TemperatureC = rng.Next(-20, 55),
		Summary = Summaries[rng.Next(Summaries.Length)]
	})
	.ToArray();
}

The important thing to note is we are specifying the custom authentication scheme name here.

Creating the custom authentication scheme

DotNet Core handles authentication by calling registered authentication handlers. This means we need to create our own authentication handler. Each authentication handler may have its own configuration. Authentication handlers and their configuration options are called authentication schemes.

The scheme options

The first step is to define the options related to our custom authentication scheme. This is done by deriving a class from the AuthenticationSchemeOptions class.

using Microsoft.AspNetCore.Authentication;

namespace AuthenticatedWebApi.Security
{
	public class TokenAuthenticationSchemeOptions : AuthenticationSchemeOptions 
	{
		public const string Name = "TokenAuthenticationScheme";
	}
}

We don't have any custom options as such. The class contains only the name of the scheme. It's not necessary to declare the name here.

The authentication handler

The authentication handler is the main class that gets used at the time of authentication. The HandleAuthenticationAsync method is called every time an endpoint is accessed that is protected using the Authorize attribute. The implementation of HandleAuthenticationAsync looks for a header named 'AuthToken', extracts the value and checks if the value is present in an internal list. If either the header is absent or the value is not present in-memory, it returns 401 i.e. unauthorized status code. Storing & checking the token value is abstracted into the TokenService class.

The authenticaton endpoint

The /Authenticate endpoint is used to authenticate a client. The AuthenticationController class provides a Post method which accepts the username and password, it forwards this information to the TokenService class which checks if the username and password matches. The actual list of username and passwords are stored in the appseeting.json file. Needless to say you can implement any scheme for persisting user information e.g. a database. Note, the passwords are stored as SHA256 hashes. You can use the hash utility to generate SHA256 hashes.

The token service

The TokenService class contains all the logic required for:

  • Reading the users from the application settings file (appsettings.json)
  • Checking if a username, password combination exists

The cool factor

I always find it cool to write UseXYZ() type of methods to add an entire capability to the ASP.NET AspNetCore processing pipeline. We'll use a similar style to register our custom authentication scheme with ASP.NET core. The TokenAuthenticationExtensions class is written just for this reason.

using Microsoft.Extensions.DependencyInjection;

namespace AuthenticatedWebApi.Security
{
	public static class TokenAuthenticationExtensions 
	{
		public static void UseTokenAuthentication(this IServiceCollection services) 
		{
			services.AddAuthentication(options => {
				options.DefaultScheme = TokenAuthenticationSchemeOptions.Name;
			})
			.AddScheme(
				TokenAuthenticationSchemeOptions.Name, option => {}
			);
		}
	} 
}

The most important point to note is that we use the AddScheme method to register our custom authentication handler & options. Note, we've also set our custom authentication scheme as the default one so there is no need to specify our authentication scheme in the Authorize attrbitue.

Using the APIs

Download the code from GitHub. Build and run the service. We'll use the curl program to invoke the APIs, you can use other tools like Postman if you like.

Access the API without authentication.

Let's see what happens if one accesses the API without having an authtoken.

Unauthorized

The output is the 401 (unauthorized) status code.

Authenticate

Let's authenticate using a username and password

Authenticate

The result is 200 (OK) and the response is the token string.

Access the API with the token

Let's authenticate using a username and password

Authenticate

The result is 200 (OK) and the response is the weather forecast.

Conclusion

Though the sample is contrived it demonstrates how a custom authentication scheme is implemented in ASP.NET Core. The AuthenticationHandler, AuthenticationSchemeOptions are core classes which are used to create the custom authentication scheme . Extension method over IServiceCollection interface make the registration of the scheme easy.

References




Comments

Posts By Year

2024 (4)
2023 (5)
2022 (10)
2021 (5)
2020 (12)
2019 (6)
2018 (8)
2017 (11)
2016 (6)
2015 (17)
2014 (2)
2013 (4)
2012 (2)

Posts By Category

.NET (4)
.NET Core (2)
ASP.NET MVC (4)
AWS (5)
AWS API Gateway (1)
Android (1)
Apache Camel (1)
Architecture (1)
Audio (1)
Azure (2)
Book review (3)
Business (1)
C# (3)
C++ (2)
CloudHSM (1)
Containers (4)
Corporate culture (1)
Database (3)
Database migration (1)
Desktop (1)
Docker (1)
DotNet (3)
DotNet Core (2)
ElasticSearch (1)
Entity Framework (3)
Git (3)
IIS (1)
JDBC (1)
Java (10)
Kibana (1)
Kubernetes (1)
Lambda (1)
Learning (1)
Life (7)
Linux (2)
Lucene (1)
Multi-threading (1)
Music (1)
OData (1)
Office (1)
PHP (1)
Photography (1)
PowerShell (2)
Programming (28)
Python (1)
Rants (5)
SQL (2)
SQL Server (1)
Security (3)
Software (1)
Software Engineering (1)
Software development (2)
Solr (1)
Sql Server (2)
Storage (1)
T-SQL (1)
TDD (1)
TSQL (5)
Tablet (1)
Technology (1)
Test Driven (1)
Testing (1)
Tomcat (1)
Unit Testing (1)
Unit Tests (1)
Utilities (3)
VC++ (1)
VMWare (1)
VSCode (1)
Visual Studio (2)
Wallpapers (1)
Web API (2)
Win32 (1)
Windows (9)
XML (2)

Posts By Tags

.NET(6) API Gateway(1) ASP.NET(4) AWS(3) Adults(1) Advertising(1) Android(1) Anti-forgery(1) Asynch(1) Authentication(2) Azure(2) Backup(1) Beliefs(1) BlockingQueue(1) Book review(2) Books(1) Busy(1) C#(4) C++(3) CLR(1) CORS(1) CSRF(1) CTE(1) Callbacks(1) Camel(1) Certificates(1) Checkbox(1) Client authentication(1) CloudHSM(1) Cmdlet(1) Company culture(1) Complexity(1) Consumer(1) Consumerism(1) Containers(3) Core(2) Custom(2) DPI(1) Data-time(1) Database(4) Debugging(1) Delegates(1) Developer(2) Dockers(2) DotNetCore(3) EF 1.0(1) Earphones(1) Elastic Search(2) ElasticSearch(1) Encrypted(1) Entity framework(1) Events(1) File copy(1) File history(1) Font(1) Git(2) HierarchyID(1) Hyper-V(1) IIS(1) Installing(1) Intelli J(1) JDBC(1) JSON(1) JUnit(1) JWT(1) Java(3) JavaScript(1) Kubernetes(1) Life(1) LinkedIn(1) Linux(2) Localization(1) Log4J(1) Log4J2(1) Logging(1) Lucene(1) MVC(4) Management(2) Migration history(1) Mirror(1) Mobile Apps(1) Modern Life(1) Money(1) Music(1) NGINX(1) NTFS(1) NUnit(2) OData(1) OPENXML(1) Objects(1) Office(1) OpenCover(1) Organization(1) PHP(1) Paths(1) PowerShell(2) Processes(1) Producer(1) Programming(2) Python(2) QAAC(1) Quality(1) REDIS(2) REST(1) Runtimes(1) S3-Select(1) SD card(1) SLF4J(1) SQL(2) SQL Code-first Migration(1) SSH(2) SSL(1) Sattelite assemblies(1) School(1) Secrets Manager(1) Self reliance(1) Service(1) Shell(1) Solr(1) Sony VAIO(1) Spirituality(1) Spring(1) Sql Express(1) System Image(1) TDD(1) TSQL(3) Table variables(1) Tables(1) Tablet(1) Ubuntu(1) Url rewrite(1) VMWare(1) VSCode(1) Validation(2) VeraCode(1) Wallpaper(1) Wallpapers(1) Web Development(4) Windows(2) Windows 10(2) Windows 2016(2) Windows 8.1(1) Work culture(1) XML(1) Yii(1) iTunes(1) open file handles(1) renew(1) security(1) static ip address(1) ulimit(1)