ANAuthenticationBasic 1.0.0

dotnet add package ANAuthenticationBasic --version 1.0.0                
NuGet\Install-Package ANAuthenticationBasic -Version 1.0.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ANAuthenticationBasic" Version="1.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add ANAuthenticationBasic --version 1.0.0                
#r "nuget: ANAuthenticationBasic, 1.0.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install ANAuthenticationBasic as a Cake Addin
#addin nuget:?package=ANAuthenticationBasic&version=1.0.0

// Install ANAuthenticationBasic as a Cake Tool
#tool nuget:?package=ANAuthenticationBasic&version=1.0.0                

AN.Authentication.Basic

This project contains an implementation of Basic Authentication Scheme for ASP.NET Core. See the RFC-7617.

Add Basic Authentication

To add Basic authentication in .NET Core, we need to modify Program.cs file. If you are using .NET Core version 5 or less, you have to add the modifications in the Startup.cs file inside the ConfigureServices method.

Add the code to configure Basic authentication right above the builder.Services.AddAuthentication() line:

builder.Services.AddAuthentication()
                .AddBasic(BasicDefaults.AuthenticationScheme);

Basic Authentication Configuration

To configure Basic authentication, we need use delegate from overloaded method AddBasic(string authenticationScheme, Action<BasicOptions> configure):

builder.Services.AddAuthentication()
                .AddBasic(BasicDefaults.AuthenticationScheme, configure => {
                    //some options will be here
                });

User credentials separator

User credentials (user-id and password) constructs by concatenating the user-id, a single colon (':') character, and the password. If your credentials is separated by another symbol, then it can be configured with the option CredentialsSeparator:

builder.Services.AddAuthentication()
                .AddBasic(BasicDefaults.AuthenticationScheme, configure => {
                    //Default option value is single colon (':')
                    configure.CredentialsSeparator = '~'
                });

Credentials encoding scheme

By default user credentials encoded by Base64 into a sequence of US-ASCII characters. If your credentials is by another algorithm or scheme, then it can be configured with the option EncodedHeaderDecoder:

builder.Services.AddAuthentication()
                .AddBasic(BasicDefaults.AuthenticationScheme, configure => {
                    configure.EncodedHeaderDecoder = credentials => DecodeCretentialsToString(credentials);
                });

Or you can use EncodedHeaderAsyncDecoder for asynchronous decode:

builder.Services.AddAuthentication()
                .AddBasic(BasicDefaults.AuthenticationScheme, configure => {
                    configure.EncodedHeaderAsyncDecoder = async (credentials, cancellationToken) => await DecodeCretentialsToStringAsync(credentials, cancellationToken);
                });

If both the EncodedHeaderAsyncDecoder and EncodedHeaderDecoder options are implemented, BasicHandler will use only EncodedHeaderAsyncDecoder to work:

builder.Services.AddAuthentication()
                .AddBasic(BasicDefaults.AuthenticationScheme, configure => {
                    //This one will be used
                    configure.EncodedHeaderAsyncDecoder = async (credentials, cancellationToken) => await DecodeCretentialsToStringAsync(credentials, cancellationToken);

                    //This one will be ignored
                    configure.EncodedHeaderDecoder = credentials => DecodeCretentialsToString(credentials);
                });

ClaimsPrincipal object creation

After decoding user credentials, it will be split into two separed strings (user-id and password). Then user-id and password will be used to create Claim[] by ClaimsFactory option for final ClaimsIdentity. By default this ClaimsFactory creates Claim[] with only one Claim with type NameIdentifier. If you need add another claims or get claims from storage, you can overload ClaimsFactory option:

builder.Services.AddAuthentication()
                .AddBasic(BasicDefaults.AuthenticationScheme, configure => {
                    configure.ClaimsFactory = (userId, password) => GetUserClaimsFromStorage(userId, password);
                });

Or you can use AsyncClaimsFactory for asynchronous Claim[] create:

builder.Services.AddAuthentication()
                .AddBasic(BasicDefaults.AuthenticationScheme, configure => {
                    configure.AsyncClaimsFactory = async (userId, password, cancellationToken) => await GetUserClaimsFromStorageAsync(userId, password, cancellationToken);
                });

Same as when you use header decoding option, if both the AsyncClaimsFactory and ClaimsFactory options are implemented, BasicHandler will use only AsyncClaimsFactory to work:

builder.Services.AddAuthentication()
                .AddBasic(BasicDefaults.AuthenticationScheme, configure => {
                    //This one will be used
                    configure.AsyncClaimsFactory = async (userId, password, cancellationToken) => await GetUserClaimsFromStorageAsync(userId, password, cancellationToken);

                    //This one will be ignored
                    configure.ClaimsFactory = (userId, password) => GetUserClaimsFromAnotherStorage(userId, password);
                });

Dependency Injection for ClaimsPrincipal object creation

If you want to get Claim[] from a service that works with dependency injection, you need to add service that implement IClaimsService or IAsyncClaimsService to the IServiceCollection.

builder.Services.AddTransient<IClaimsService, MyClaimsService>();

Both interfaces implement methods that returns an Claim[].


//sync service
public class ClaimsService : IClaimsService
{
    private readonly UserStorage storage;

    public ClaimsService(UserStorage storage)
    {
        this.storage = storage;
    }

    public Claim[] GetClaims(string userId, string password)
        => storage.GetUserClaimsFromStorage(userId, password);
}

//async service
public class AsyncClaimsService : IAsyncClaimsService
{
    private readonly UserStorage storage;

    public AsyncClaimsService(UserStorage storage)
    {
        this.storage = storage;
    }

    public async Task<Claim[]> GetClaimsAsync(string userId, string password, CancellationToken cancellationToken = default)
        => await storage.GetUserClaimsFromStorageAsync(userId, password, cancellationToken);
}

In case both types of services are added, only IAsyncClaimsService will be used.

If both one of ClaimService and one of options ClaimsFactory are implemented in same time, only the service will be used to create the Claim[].

Basic Authentication Events

The following events may occur during Basic authentication, which we can handle:

  • OnMessageReceived - Invoked when a protocol message is first received.
  • OnFailed - Invoked if authentication fails during request processing. The exceptions will be re-thrown after this event unless suppressed.
  • OnChallenge - Invoked before a challenge is sent back to the caller.
  • OnForbidden - Invoked if authorization fails and results in a Forbidden response.
  • OnPrincipalCreated - Invoked after request principal instance created.

All this events is part of BasicEvents object.

Events handling is the same as in other authentication schemes:

builder.Services.AddAuthentication()
                .AddBasic(BasicDefaults.AuthenticationScheme, configure => {
                    configure.Events = new BasicEvents()
                    {
                        OnMessageReceived = context => {
                            //handle this event
                            return Task.CompletedTask;
                        }
                    }
                });
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.0.0 183 1/14/2024

Please refer to README.md for details.