YG.Authentication
2.2.1
See the version list below for details.
dotnet add package YG.Authentication --version 2.2.1
NuGet\Install-Package YG.Authentication -Version 2.2.1
<PackageReference Include="YG.Authentication" Version="2.2.1" />
<PackageVersion Include="YG.Authentication" Version="2.2.1" />
<PackageReference Include="YG.Authentication" />
paket add YG.Authentication --version 2.2.1
#r "nuget: YG.Authentication, 2.2.1"
#:package YG.Authentication@2.2.1
#addin nuget:?package=YG.Authentication&version=2.2.1
#tool nuget:?package=YG.Authentication&version=2.2.1
YGAuthentication
YGAuthentication provides authentication and authorization for Blazor applications using either a local JWT-based identity system or OpenID Connect (OIDC) Single Sign-On.
Features:
Local JWT Authentication Authentication and authorization for Blazor applications using JWT claims. Works with or without a WebAPI. BCrypt password hashing support. Login through WebAPI: api/loginEncr (BCrypt) api/login (plain text) Direct authentication without a WebAPI: _authEncr.Authenticate(...) _auth.Authenticate(...) Built-in authorization support for protected pages. WebAPI endpoints: api/login api/auth
OpenID Connect (OIDC) Single Sign-On
Starting July 2026, Authentication is renamed to YG.Authentication, and it also supports OpenID Connect providers such as Auth0, Microsoft Entra ID (Azure AD), Okta, Keycloak, and other standards-compliant identity providers.
Simply add your OIDC configuration to appsettings.json and register the services.
YG.Authentication Service Registration:
builder.Services.AddYGOpenIdConnect(config);
builder.Services.AddScoped<IYGOpenIdConnectEventHandler, YourCustomOpenIdConnectUserHandler>();
Middleware:
app.MapYGOpenIdConnectEndpoints(config);
Hosting Your Own Identity Provider
You can use the built-in local JWT identity system or integrate with an external OpenID Connect provider.
If you need help getting started, feel free to reach out:
Email: cs@yogigrantz.com CodeMentor: Yogi Grantz
Installation
Include this package in the project file
!!! Be sure to follow the working POC example [YGEnvAuthenticationTestApp]. The source code includes POC Blazor Web app.
This is an advanced library. It requires special IoC registrations in program.cs, and the login page requires a bunch of usings and injects to include the necessary libraries and retrieve instances of DI objects from IoC Container. The sample project YGEnvAuthenticationTestApp contains 4 sample login pages:
Login 1: Direct authentication without encrypted password Login 2: Direct authentication with encrypted password Login 3: WebAPI authentication without encrypted password Login 4: WebAPI authentication with encrypted password
Usage
.csproj file:
<PropertyGroup> <TargetFramework>net8.0</TargetFramework> <Nullable>enable</Nullable> <ImplicitUsings>disable</ImplicitUsings> </PropertyGroup>
<ItemGroup> <PackageReference Include="Blazored.LocalStorage" Version="4.5.0" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="YG.Authentication" Version="2.2.0" /> </ItemGroup>
AppSettings.json for custom jwt:
{
"AuthName": "AnyNameOfYourChoice",
"LoginPage": "/Login"
}
With OpenIDC, these are required:
"YGAuthentication": {
"OpenIdConnect": {
"Provider": "Auth0",
"Domain": "yourtenant.us.auth0.com",
"ClientId": "xxxxxxxx",
"ClientSecret": "xxxxxxxx",
"LoginPath": "/login?redirectUri=/",
"LogoutPath": "/logout",
"CallbackPath": "/signin-oidc",
"SignedOutCallbackPath": "/signout-callback-oidc",
"SignedOutRedirectUri": "/",
"ClaimsIssuer": "Auth0",
"DefaultRedirectPath": "/",
"CookieExpireDays": 2
}
},
program.cs:
using BlazorApp3.Components;
using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components;
using YGAuthentication.ActionFilters;
using YGAuthentication.Jwt;
using YGAuthentication.States;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents();
IConfiguration config = builder.Configuration;
string authName = config.GetValue<string>("AuthName");
string loginPage = config.GetValue<string>("LoginPage");
builder.Services.AddHttpClient(authName);
builder.Services.AddControllers();
builder.Services.AddBlazoredLocalStorage();
//sample one username and password. In reality you would populate the dictionary with username and pwd from IDS
string username = "yogi";
string pwd = "123";
int jwtExpMinutes = 60;
builder.Services.AddScoped<IAuthorizationJWT, AuthorizationJWT>(_ => {
Dictionary<string, string> userCreds = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
userCreds.Add(username, pwd); // Populate this with username and password from DB. The password is clear text
return new AuthorizationJWT(userCreds, "username", jwtExpMinutes, "YourCompanyName", "General Audience");
});
builder.Services.AddScoped<IAuthorizationJWTEncrypted, AuthorizationJWTEncrypted>(_ => {
Dictionary<string, string> userCredsHashed = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
string pwdEncrypted = BCrypt.Net.BCrypt.HashPassword(pwd);
userCredsHashed.Add(username, pwdEncrypted); // Populate this with username and password from DB. The password is BCrypt-hashed
return new AuthorizationJWTEncrypted(userCredsHashed, "username", jwtExpMinutes, "YourCompanyName", "General Audience");
});
builder.Services.AddScoped<IAppState, AppState>(_ => new AppState());
builder.Services.AddScoped<BasicAuthentication>();
builder.Services.AddScoped<IPageAuthCheck, PageAuthCheck>(ioc => new PageAuthCheck(ioc.GetService<NavigationManager>(), ioc.GetService<IHttpClientFactory>(), ioc.GetService<ILocalStorageService>(), authName, loginPage));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapControllerRoute(
name: "mvc",
pattern: "{controller}/{action}/{id?}");
app.UseAntiforgery();
app.MapControllers();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode();
app.Run();
For OIDC, the middleware should follow this sequence: ---------------------
// OpenIDC - Auth0 ----------------
builder.Services.AddYGOpenIdConnect(builder.Configuration);
// For checking user role against local database, create DI class that inherits from IYGOpenIdConnectEventHandler
// Then Register it in DI, like this:
builder.Services.AddScoped<IYGOpenIdConnectEventHandler, YourCustomHandler>();
// code all the necessary actions upon successful login and logout in this class: YourCustomHandler - name it appropriately to suit your needs
// OpenIDC ---- end
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapControllerRoute(
name: "mvc",
pattern: "{controller}/{action}/{id?}");
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");
app.UseAuthentication();
app.UseAuthorization();
string oidcProvider = builder.Configuration["YGAuthentication:OpenIdConnect:Provider"] ?? "Auth0";
app.MapYGOpenIdConnectEndpoints(oidcProvider);
app.Run();
// if you ever need help setting this up, please connect and message me in LinkedIn: Yogi Grantz
Login Page - UI:
Please see the source code - YGAuthenticationTestApp:
Login1 - straight authentication without password encryption
Login2 - straight authentication with password encryption
Login3 - WebAPI authentication without password encryption
Login4 - WebAPI authentication with password encryption
App.razor:
@using YGAuthentication.Jwt
@inject IPageAuthCheck _pageCheck
@using YGAuthentication.States
@inject IAppState _appstate
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
@code {
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await _pageCheck.AuthCheckAsync();
_appstate.ErrorMessage = _pageCheck.ErrorMessage;
if (_pageCheck.IsAuthorized)
_appstate.LoggedIn = true;
else
_appstate.LoggedIn = false;
}
}
}
NavMenu:
@using YGAuthentication.Jwt
@inject IPageAuthCheck _pageCheck
@using YGAuthentication.States
@inject IAppState _appstate
protected override void OnInitialized()
{
_appState.OnChange += StateHasChanged;
}
public void Dispose()
{
_appState.OnChange -= StateHasChanged;
}
Any Page:
@using YGAuthentication.States
@inject IAppState _appstate
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
if (_appstate.LoggedIn)
{
_message = "Authorized";
_msgClass = "alert-success";
}
else
_message = $"You are NOT Authorized {_appstate.ErrorMessage}";
}
Logout Page:
@page "/Logout"
@using Blazored.LocalStorage
@using YGAuthentication.Jwt
@inject ILocalStorageService _localStorage
@inject IPageAuthCheck _pageAuth
<h3>Logout</h3>
<div>@_errMsg</div>
@code {
private string _errMsg = "";
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
try
{
var result = await _pageAuth.LogoutAsync(_localStorage);
if (!result.Item1)
_errMsg = result.Item2;
else
_errMsg = $"Logged out: {result.Item2}";
}
catch (Exception ex)
{
_errMsg = ex.Message;
}
}
}
Examples
A full working POC SampleAuthTest (MudBlazor) and YGEnvAuthenticationTestApp (Plain Blazor) are provided in the Repo.
Output:
Blazor Web Application that uses log in
Dependencies
<ItemGroup> <PackageReference Include="BCrypt.Net-Next" Version="4.0.3" /> <PackageReference Include="Blazored.LocalStorage" Version="4.5.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.2.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Formatters.Json" Version="2.2.0" /> <PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" /> <PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.0.2" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.2" /> </ItemGroup>
Contributing
Any new ideas on how to enhance this class without adding much complexity, please adhere to SOLID principle
License
This project is licensed under the MIT License(LICENSE).
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. 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. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- BCrypt.Net-Next (>= 4.0.3)
- Blazored.LocalStorage (>= 4.5.0)
- Microsoft.AspNetCore.Authentication.OpenIdConnect (>= 8.0.0)
- Microsoft.AspNetCore.Mvc.Abstractions (>= 2.2.0)
- Microsoft.AspNetCore.Mvc.Formatters.Json (>= 2.2.0)
- Microsoft.Extensions.Http (>= 8.0.0)
- Microsoft.IdentityModel.Tokens (>= 8.0.2)
- System.IdentityModel.Tokens.Jwt (>= 8.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Updated Readme.md