diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 00000000..1ff0c423
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln merge=binary
+#*.csproj merge=binary
+#*.vbproj merge=binary
+#*.vcxproj merge=binary
+#*.vcproj merge=binary
+#*.dbproj merge=binary
+#*.fsproj merge=binary
+#*.lsproj merge=binary
+#*.wixproj merge=binary
+#*.modelproj merge=binary
+#*.sqlproj merge=binary
+#*.wwaproj merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg binary
+#*.png binary
+#*.gif binary
+
+###############################################################################
+# diff behavior for common document formats
+#
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the
+# entries below.
+###############################################################################
+#*.doc diff=astextplain
+#*.DOC diff=astextplain
+#*.docx diff=astextplain
+#*.DOCX diff=astextplain
+#*.dot diff=astextplain
+#*.DOT diff=astextplain
+#*.pdf diff=astextplain
+#*.PDF diff=astextplain
+#*.rtf diff=astextplain
+#*.RTF diff=astextplain
diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml
new file mode 100644
index 00000000..97e538b7
--- /dev/null
+++ b/.github/workflows/ci-cd.yml
@@ -0,0 +1,56 @@
+name: CI/CD with Auto Versioning
+
+on:
+ workflow_dispatch:
+# push:
+# branches: [ master ]
+
+jobs:
+ versioning:
+ runs-on: ubuntu-latest
+ outputs:
+ version: ${{ steps.set_version.outputs.new_version }}
+ steps:
+ - uses: actions/checkout@v4.1.2
+ - name: Bump version and push tag
+ id: set_version
+ uses: mathieudutour/github-tag-action@v6.2
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ default_bump: patch # Automatically bump patch version
+ release_branches: release.*,hotfix.*,master
+ pre_release_branches: feature.*
+
+ build:
+ needs: versioning
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4.1.2
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4.0.0
+ with:
+ dotnet-version: '8.0'
+ - name: Restore dependencies
+ run: dotnet restore
+ - name: Build
+ run: dotnet build --no-restore -c Release
+ - name: Test
+ run: dotnet test --no-build -c Release --verbosity normal
+ - name: Pack
+ run: dotnet pack --no-build -c Release -o nupkg /p:PackageVersion=${{ needs.versioning.outputs.version }}
+ - name: Upload NuGet packages as artifacts
+ uses: actions/upload-artifact@v4.3.1
+ with:
+ name: nuget-packages
+ path: nupkg/*.nupkg
+ publish:
+ needs: build
+ runs-on: ubuntu-latest
+ steps:
+ - name: Download NuGet packages artifacts
+ uses: actions/download-artifact@v4.1.4
+ with:
+ name: nuget-packages
+ path: nupkg
+ - name: Push to NuGet
+ run: dotnet nuget push "**/*.nupkg" -k ${{secrets.NUGET_API_KEY}} -s https://api.nuget.org/v3/index.json --skip-duplicate
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 00000000..37537f2c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,371 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Oo]ut/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+/.idea/.idea.Oidc.Server.dir/.idea
+
+.env
+/.idea/.idea.Abblix.Oidc/Docker/
+/local-npm.cmd
+/local-rebuild.cmd
+/Certificates/myCA/private/Abblix Licensing.pem
+/LicenseGenerator
diff --git a/.idea/.idea.Abblix.Oidc/.idea/.gitignore b/.idea/.idea.Abblix.Oidc/.idea/.gitignore
new file mode 100644
index 00000000..53ed85cd
--- /dev/null
+++ b/.idea/.idea.Abblix.Oidc/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/modules.xml
+/contentModel.xml
+/projectSettingsUpdater.xml
+/.idea.Abblix.Oidc.iml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.Abblix.Oidc/.idea/.name b/.idea/.idea.Abblix.Oidc/.idea/.name
new file mode 100644
index 00000000..32fa4ab0
--- /dev/null
+++ b/.idea/.idea.Abblix.Oidc/.idea/.name
@@ -0,0 +1 @@
+Abblix.Oidc
\ No newline at end of file
diff --git a/.idea/.idea.Abblix.Oidc/.idea/encodings.xml b/.idea/.idea.Abblix.Oidc/.idea/encodings.xml
new file mode 100644
index 00000000..df87cf95
--- /dev/null
+++ b/.idea/.idea.Abblix.Oidc/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Abblix.Oidc/.idea/indexLayout.xml b/.idea/.idea.Abblix.Oidc/.idea/indexLayout.xml
new file mode 100644
index 00000000..7b08163c
--- /dev/null
+++ b/.idea/.idea.Abblix.Oidc/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Abblix.Oidc/.idea/vcs.xml b/.idea/.idea.Abblix.Oidc/.idea/vcs.xml
new file mode 100644
index 00000000..35eb1ddf
--- /dev/null
+++ b/.idea/.idea.Abblix.Oidc/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Abblix.DependencyInjection/Abblix.DependencyInjection.csproj b/Abblix.DependencyInjection/Abblix.DependencyInjection.csproj
new file mode 100644
index 00000000..cd1ba096
--- /dev/null
+++ b/Abblix.DependencyInjection/Abblix.DependencyInjection.csproj
@@ -0,0 +1,35 @@
+
+
+
+ net6.0;net7.0;net8.0
+ enable
+ enable
+ true
+ true
+ Abblix.DependencyInjection
+ Abblix DependencyInjection
+ Enhances .NET applications by extending the standard dependency injection framework. It supports essential patterns such as service aliasing, composite services, and decorators, simplifying and enhancing service registration and resolution processes.
+ Abblix LLP
+ https://www.abblix.com/abblix-oidc-server
+ https://github.com/Abblix/Oidc.Server
+ git
+ Abblix DependencyInjection DI .NET ServiceLifetime Scoped Singleton Transient Composite Decorator AdvancedDI ServiceResolver .NET Core Microsoft.Extensions.DependencyInjection IoC InversionOfControl
+ README.md
+ LICENSE.md
+ Copyright (c) 2024 Abblix LLP. All rights reserved.
+ For detailed release notes, visit: https://github.com/Abblix/Oidc.Server/releases
+ Abblix.png
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Abblix.DependencyInjection/Dependency.cs b/Abblix.DependencyInjection/Dependency.cs
new file mode 100644
index 00000000..125c944d
--- /dev/null
+++ b/Abblix.DependencyInjection/Dependency.cs
@@ -0,0 +1,104 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using Microsoft.Extensions.DependencyInjection;
+
+
+
+namespace Abblix.DependencyInjection;
+
+///
+/// Represents a dependency that can be overridden in a service provider.
+/// This struct provides various static methods to create dependency overrides based on type, instance, or factory functions.
+///
+public readonly struct Dependency
+{
+ ///
+ /// Creates a dependency override where a specified actual type fulfills the contract of a declared type.
+ ///
+ /// The declared type of the dependency.
+ /// The actual type to be used as the implementation.
+ /// A new instance.
+ public static Dependency Override() where TActual : TDeclared
+ => new(typeof(TDeclared), sp => ActivatorUtilities.GetServiceOrCreateInstance(sp)!);
+
+ ///
+ /// Creates a dependency override with a specific instance for the declared type.
+ ///
+ /// The declared type of the dependency.
+ /// The instance to use for the dependency.
+ /// A new instance.
+ public static Dependency Override(TDeclared instance)
+ => new(typeof(TDeclared), _ => instance!);
+
+ ///
+ /// Creates a dependency override using a factory function for the declared type.
+ ///
+ /// The declared type of the dependency.
+ /// The factory function to create the dependency instance.
+ /// A new instance.
+ public static Dependency Override(Func factory)
+ => new(typeof(TDeclared), sp => factory(sp)!);
+
+ ///
+ /// Creates a dependency override where a specified actual type fulfills the contract of a declared type.
+ ///
+ /// The declared type of the dependency.
+ /// The actual type to be used as the implementation.
+ /// A new instance.
+ public static Dependency Override(Type declared, Type actual)
+ => new(declared, sp => ActivatorUtilities.GetServiceOrCreateInstance(sp, actual));
+
+ ///
+ /// Creates a dependency override with a specific instance for the declared type.
+ ///
+ /// The declared type of the dependency.
+ /// The instance to use for the dependency.
+ /// A new instance.
+ public static Dependency Override(Type declared, object instance)
+ => new(declared, _ => instance);
+
+ ///
+ /// Creates a dependency override using a factory function for the declared type.
+ ///
+ /// The declared type of the dependency.
+ /// The factory function to create the dependency instance.
+ /// A new instance.
+ public static Dependency Override(Type declared, Func factory)
+ => new(declared, factory);
+
+ private Dependency(Type type, Func factory)
+ {
+ Type = type;
+ Factory = factory;
+ }
+
+ ///
+ /// The declared type of the dependency.
+ ///
+ internal Type Type { get; }
+
+ ///
+ /// The factory function used to create the dependency instance.
+ ///
+ internal Func Factory { get; }
+}
\ No newline at end of file
diff --git a/Abblix.DependencyInjection/ServiceCollectionExtensions.cs b/Abblix.DependencyInjection/ServiceCollectionExtensions.cs
new file mode 100644
index 00000000..cf0aa195
--- /dev/null
+++ b/Abblix.DependencyInjection/ServiceCollectionExtensions.cs
@@ -0,0 +1,268 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Reflection;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+
+namespace Abblix.DependencyInjection;
+
+///
+/// Provides extension methods for to enhance dependency injection capabilities.
+///
+public static class ServiceCollectionExtensions
+{
+ ///
+ /// Registers an alias for a service type to a specific implementation.
+ ///
+ /// The service type to be aliased.
+ /// The implementation type to use for the alias.
+ /// The to add the service to.
+ /// The updated .
+ public static IServiceCollection AddAlias(this IServiceCollection services)
+ where TImplementation : class, TService
+ where TService : class
+ {
+ var descriptor = new ServiceDescriptor(
+ typeof(TService),
+ sp => sp.GetRequiredService(),
+ services.GetDescriptor().Lifetime);
+
+ services.Add(descriptor);
+ return services;
+ }
+
+ ///
+ /// Composes a service type with multiple implementations into a single composite service.
+ ///
+ /// The interface type to be composed.
+ /// The composite implementation type.
+ /// The to add the service to.
+ /// The dependencies required by the composite service.
+ /// The updated .
+ public static IServiceCollection Compose(
+ this IServiceCollection services,
+ params Dependency[] dependencies)
+ where TInterface : class where TComposite : class, TInterface
+ {
+ var parameterType = typeof(TComposite)
+ .GetConstructors(BindingFlags.Instance | BindingFlags.Public)
+ .SelectMany(constructor => constructor.GetParameters(), (_, parameterInfo) => parameterInfo.ParameterType)
+ .FirstOrDefault(type => type.IsAssignableFrom(typeof(TInterface[])));
+
+ if (parameterType == null)
+ throw new InvalidOperationException(
+ $"The type {typeof(TComposite).FullName} has no public constructor that accepts {typeof(TInterface).FullName}[]");
+
+ var serviceDescriptors = services
+ .Where(descriptor => descriptor.ServiceType == typeof(TInterface))
+ .ToArray();
+
+ if (serviceDescriptors.Length <= 1)
+ return services;
+
+ // choose the shortest lifetime among existing service registrations
+ var lifetime = serviceDescriptors.Max(descriptor => descriptor.Lifetime);
+
+ var compositeDescriptor = ServiceDescriptor.Describe(
+ typeof(TInterface),
+ serviceProvider =>
+ {
+ var serviceInstances = Array.ConvertAll(
+ serviceDescriptors,
+ serviceDescriptor => (TInterface)serviceProvider.CreateService(serviceDescriptor));
+
+ var serviceDependencies = Dependency.Override(parameterType, serviceInstances);
+ return serviceProvider.CreateService(dependencies.Append(serviceDependencies));
+ },
+ lifetime);
+
+ services.RemoveAll();
+ services.Add(compositeDescriptor);
+
+ return services;
+ }
+
+ ///
+ /// Decorates a registered service with a decorator implementation.
+ ///
+ /// The service type to be decorated.
+ /// The decorator implementation type.
+ /// The to add the service to.
+ /// The dependencies required by the decorator.
+ /// The updated .
+ public static IServiceCollection Decorate(
+ this IServiceCollection services,
+ params Dependency[] dependencies)
+ where TInterface : class where TDecorator : class, TInterface
+ {
+ var serviceDescriptor = services.GetDescriptor();
+
+ var decoratorDescriptor = ServiceDescriptor.Describe(
+ typeof(TInterface),
+ serviceProvider =>
+ {
+ var instance = Dependency.Override((TInterface)serviceProvider.CreateService(serviceDescriptor));
+ return serviceProvider.CreateService(dependencies.Append(instance));
+ },
+ serviceDescriptor.Lifetime);
+
+ return services.Replace(decoratorDescriptor);
+ }
+
+ private static T[] Append(this T[] source, T element)
+ {
+ switch (source)
+ {
+ case { Length: > 0 }:
+ Array.Resize(ref source, source.Length + 1);
+ source[^1] = element;
+ return source;
+
+ default:
+ return new[] { element };
+ }
+ }
+
+ private static ServiceDescriptor GetDescriptor(this IServiceCollection services)
+ where TInterface : class
+ {
+ return services.SingleOrDefault(s => s.ServiceType == typeof(TInterface))
+ ?? throw new InvalidOperationException($"{typeof(TInterface).Name} is not registered");
+ }
+
+ private static object CreateService(this IServiceProvider serviceProvider, ServiceDescriptor descriptor)
+ {
+ return descriptor switch
+ {
+ { ImplementationInstance: { } instance } => instance,
+ { ImplementationFactory: { } factory } => factory(serviceProvider),
+ { ImplementationType: { } type } => ActivatorUtilities.GetServiceOrCreateInstance(serviceProvider, type),
+ _ => throw new InvalidOperationException($"Unable to create instance of {descriptor.ServiceType.FullName}")
+ };
+ }
+
+ public static T CreateService(this IServiceProvider serviceProvider, params Dependency[] dependencies)
+ {
+ return (T)serviceProvider.CreateService(typeof(T), dependencies);
+ }
+
+ public static object CreateService(this IServiceProvider serviceProvider,
+ Type type, params Dependency[] dependencies)
+ {
+ var factory = ActivatorUtilities.CreateFactory(type, Array.ConvertAll(dependencies, d => d.Type));
+ return factory(serviceProvider, Array.ConvertAll(dependencies, d => d.Factory(serviceProvider)));
+ }
+
+ ///
+ /// Registers a transient service with custom dependencies.
+ ///
+ /// The service type to register.
+ /// The to add the service to.
+ /// The dependencies required by the service.
+ /// The updated .
+ public static IServiceCollection AddTransient(this IServiceCollection services, params Dependency[] dependencies)
+ where T : class
+ {
+ return services.AddTransient(sp => sp.CreateService(dependencies));
+ }
+
+ ///
+ /// Registers a transient service with custom dependencies.
+ ///
+ /// The type of the service to add.
+ /// The type of the implementation to use.
+ /// The to add the service to.
+ /// The dependencies required by the service.
+ /// The updated .
+ public static IServiceCollection AddTransient(this IServiceCollection services,
+ params Dependency[] dependencies)
+ where TService : class
+ where TImplementation : class, TService
+ {
+ return services.AddTransient(sp => sp.CreateService(dependencies));
+ }
+
+ ///
+ /// Registers a scoped service of the type specified in with custom dependencies.
+ /// A scoped service is created once per request within the scope.
+ ///
+ /// The type of the service to add.
+ /// The to add the service to.
+ /// An array of objects representing additional dependencies required by the service.
+ /// The updated .
+ public static IServiceCollection AddScoped(this IServiceCollection services, params Dependency[] dependencies)
+ where T : class
+ {
+ return services.AddScoped(sp => sp.CreateService(dependencies));
+ }
+
+ ///
+ /// Registers a scoped service with the implementation type specified in
+ /// and the service type specified in with custom dependencies.
+ /// A scoped service is created once per request within the scope.
+ ///
+ /// The type of the service to add.
+ /// The type of the implementation to use.
+ /// The to add the service to.
+ /// An array of objects representing additional dependencies required by the service.
+ /// The updated .
+ public static IServiceCollection AddScoped(this IServiceCollection services,
+ params Dependency[] dependencies)
+ where TService : class
+ where TImplementation : class, TService
+ {
+ return services.AddScoped(sp => sp.CreateService(dependencies));
+ }
+
+ ///
+ /// Registers a singleton service of the type specified in with custom dependencies.
+ /// A singleton service is created the first time it is requested, and subsequent requests use the same instance.
+ ///
+ /// The type of the service to add.
+ /// The to add the service to.
+ /// An array of objects representing additional dependencies required by the service.
+ /// The updated .
+ public static IServiceCollection AddSingleton(this IServiceCollection services, params Dependency[] dependencies)
+ where T : class
+ {
+ return services.AddSingleton(sp => sp.CreateService(dependencies));
+ }
+
+ ///
+ /// Registers a singleton service of the type specified in with custom dependencies.
+ /// A singleton service is created the first time it is requested, and subsequent requests use the same instance.
+ ///
+ /// The type of the service to add.
+ /// The type of the implementation to use.
+ /// The to add the service to.
+ /// An array of objects representing additional dependencies required by the service.
+ /// The updated .
+
+ public static IServiceCollection AddSingleton(this IServiceCollection services,
+ params Dependency[] dependencies)
+ where TService : class
+ where TImplementation : class, TService
+ {
+ return services.AddSingleton(sp => sp.CreateService(dependencies));
+ }
+}
\ No newline at end of file
diff --git a/Abblix.Jwt.UnitTests/Abblix.Jwt.UnitTests.csproj b/Abblix.Jwt.UnitTests/Abblix.Jwt.UnitTests.csproj
new file mode 100644
index 00000000..f7c1ef1a
--- /dev/null
+++ b/Abblix.Jwt.UnitTests/Abblix.Jwt.UnitTests.csproj
@@ -0,0 +1,29 @@
+
+
+
+ net8.0
+ enable
+ enable
+
+ false
+ true
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/Abblix.Jwt.UnitTests/JwtEncryptionTests.cs b/Abblix.Jwt.UnitTests/JwtEncryptionTests.cs
new file mode 100644
index 00000000..9bc4302c
--- /dev/null
+++ b/Abblix.Jwt.UnitTests/JwtEncryptionTests.cs
@@ -0,0 +1,82 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Text.Json.Nodes;
+using Abblix.Utils;
+using Microsoft.IdentityModel.Tokens;
+using Xunit;
+
+namespace Abblix.Jwt.UnitTests;
+
+public class JwtEncryptionTests
+{
+ private static readonly JsonWebKey EncryptingKey = JsonWebKeyFactory.CreateRsa(JsonWebKeyUseNames.Enc);
+ private static readonly JsonWebKey SigningKey = JsonWebKeyFactory.CreateRsa(JsonWebKeyUseNames.Sig);
+
+ [Fact]
+ public async Task JwtFullCycleTest()
+ {
+ var issuedAt = DateTimeOffset.UtcNow;
+
+ var token = new JsonWebToken
+ {
+ Header = { Algorithm = SigningAlgorithms.RS256 },
+ Payload = {
+ JwtId = Guid.NewGuid().ToString("N"),
+ IssuedAt = issuedAt,
+ NotBefore = issuedAt,
+ ExpiresAt = issuedAt + TimeSpan.FromDays(1),
+ Issuer = "abblix.com",
+ Audiences = new []{ nameof(JwtFullCycleTest) },
+ ["test"] = "value",
+ ["address"] = new JsonObject
+ {
+ { "street", "123 Main St" },
+ { "city", "Springfield" },
+ { "state", "IL" },
+ { "zip", "62701" },
+ }
+ },
+ };
+
+ var creator = new JsonWebTokenCreator();
+ var jwt = await creator.IssueAsync(token, SigningKey, EncryptingKey);
+
+ var validator = new JsonWebTokenValidator();
+ var parameters = new ValidationParameters
+ {
+ ValidateAudience = aud => Task.FromResult(token.Payload.Audiences.SequenceEqual(aud)),
+ ValidateIssuer = iss => Task.FromResult(iss == token.Payload.Issuer),
+ ResolveTokenDecryptionKeys = _ => new [] { EncryptingKey }.AsAsync(),
+ ResolveIssuerSigningKeys = _ => new [] { SigningKey }.AsAsync(),
+ };
+
+ var result = Assert.IsType(await validator.ValidateAsync(jwt, parameters));
+ var expectedClaims = ExtractClaims(token);
+ var actualClaims = ExtractClaims(result.Token);
+ Assert.Equal(expectedClaims, actualClaims);
+ }
+
+ private static IEnumerable<(string Key, string?)> ExtractClaims(JsonWebToken token)
+ => from claim in token.Payload.Json
+ select (claim.Key, claim.Value?.ToJsonString());
+}
diff --git a/Abblix.Jwt/Abblix.Jwt.csproj b/Abblix.Jwt/Abblix.Jwt.csproj
new file mode 100644
index 00000000..0357cc7b
--- /dev/null
+++ b/Abblix.Jwt/Abblix.Jwt.csproj
@@ -0,0 +1,40 @@
+
+
+
+ net6.0;net7.0;net8.0
+ enable
+ enable
+ true
+ true
+ Abblix.JWT
+ Abblix JWT
+ A lightweight, easy-to-use library for working with JSON Web Tokens (JWT) in .NET applications. Features include token validation, custom claims, signature verification, and audience validation, making it an ideal choice for developers looking to secure their .NET applications efficiently.
+ Abblix LLP
+ https://www.abblix.com/abblix-oidc-server
+ https://github.com/Abblix/Oidc.Server
+ git
+ Abblix JWT JSON-Web-Token Authentication Security Token API-Security OAuth OAuth2 AccessToken Identity ASP.NET-Security Web-Security
+ README.md
+ LICENSE.md
+ Copyright (c) 2024 Abblix LLP. All rights reserved.
+ For detailed release notes, visit: https://github.com/Abblix/Oidc.Server/releases
+ Abblix.png
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Abblix.Jwt/AlgorithmMapper.cs b/Abblix.Jwt/AlgorithmMapper.cs
new file mode 100644
index 00000000..a127907c
--- /dev/null
+++ b/Abblix.Jwt/AlgorithmMapper.cs
@@ -0,0 +1,64 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using Microsoft.IdentityModel.Tokens;
+
+
+
+namespace Abblix.Jwt;
+
+///
+/// Provides functionality to map signing algorithm names to their corresponding outbound algorithm names.
+///
+public static class AlgorithmMapper
+{
+ ///
+ /// Maps a given signing algorithm name to the corresponding outbound algorithm name.
+ ///
+ /// The signing algorithm name to map.
+ /// The outbound algorithm name corresponding to the given signing algorithm.
+ ///
+ /// This mapping is used to standardize algorithm names across different contexts or specifications,
+ /// ensuring consistency in cryptographic operations.
+ ///
+ public static string MapToOutbound(string signingAlgorithm) => signingAlgorithm switch
+ {
+ SecurityAlgorithms.EcdsaSha256Signature => SecurityAlgorithms.EcdsaSha256,
+ SecurityAlgorithms.EcdsaSha384Signature => SecurityAlgorithms.EcdsaSha384,
+ SecurityAlgorithms.EcdsaSha512Signature => SecurityAlgorithms.EcdsaSha512,
+
+ SecurityAlgorithms.HmacSha256Signature => SecurityAlgorithms.HmacSha256,
+ SecurityAlgorithms.HmacSha384Signature => SecurityAlgorithms.HmacSha384,
+ SecurityAlgorithms.HmacSha512Signature => SecurityAlgorithms.HmacSha512,
+
+ SecurityAlgorithms.RsaSha256Signature => SecurityAlgorithms.RsaSha256,
+ SecurityAlgorithms.RsaSha384Signature => SecurityAlgorithms.RsaSha384,
+ SecurityAlgorithms.RsaSha512Signature => SecurityAlgorithms.RsaSha512,
+
+ SecurityAlgorithms.Aes128KeyWrap => SecurityAlgorithms.Aes128KW,
+ SecurityAlgorithms.Aes192KeyWrap => SecurityAlgorithms.Aes256KW,
+ SecurityAlgorithms.RsaV15KeyWrap => SecurityAlgorithms.RsaPKCS1,
+ SecurityAlgorithms.RsaOaepKeyWrap => SecurityAlgorithms.RsaOAEP,
+
+ _ => signingAlgorithm,
+ };
+}
diff --git a/Abblix.Jwt/ClaimExtensions.cs b/Abblix.Jwt/ClaimExtensions.cs
new file mode 100644
index 00000000..44c8f785
--- /dev/null
+++ b/Abblix.Jwt/ClaimExtensions.cs
@@ -0,0 +1,45 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Text.Json.Nodes;
+
+
+
+namespace Abblix.Jwt;
+
+///
+/// Provides extension methods for handling claims, particularly for converting between JWT claims and security claims.
+///
+public static class ClaimExtensions
+{
+ ///
+ /// Converts a to a string representation. If the node is a ,
+ /// the value is extracted as a string; otherwise, the JSON string representation of the node is returned.
+ ///
+ /// The to convert to a string.
+ /// A string representation of the .
+ public static string AsString(this JsonNode node) => node switch
+ {
+ JsonValue value when value.TryGetValue(out string? s) => s,
+ _ => node.ToJsonString(),
+ };
+}
diff --git a/Abblix.Jwt/IJsonWebTokenCreator.cs b/Abblix.Jwt/IJsonWebTokenCreator.cs
new file mode 100644
index 00000000..92d8bf61
--- /dev/null
+++ b/Abblix.Jwt/IJsonWebTokenCreator.cs
@@ -0,0 +1,43 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Defines the contract for a service that creates JSON Web Tokens (JWTs).
+///
+public interface IJsonWebTokenCreator
+{
+ ///
+ /// Lists the all supported signing algorithms for JWT creation.
+ ///
+ IEnumerable SigningAlgValuesSupported { get; }
+
+ ///
+ /// Issues a new JWT based on the specified JsonWebToken object, signing key, and optional encrypting key.
+ ///
+ /// The JsonWebToken object containing the payload of the JWT.
+ /// The JsonWebKey used to sign the JWT.
+ /// Optional JsonWebKey used to encrypt the JWT. If null, the JWT is not encrypted.
+ /// A Task representing the asynchronous operation, which upon completion yields the JWT as a string.
+ Task IssueAsync(JsonWebToken jwt, JsonWebKey? signingKey, JsonWebKey? encryptingKey = null);
+}
diff --git a/Abblix.Jwt/IJsonWebTokenValidator.cs b/Abblix.Jwt/IJsonWebTokenValidator.cs
new file mode 100644
index 00000000..80430fcc
--- /dev/null
+++ b/Abblix.Jwt/IJsonWebTokenValidator.cs
@@ -0,0 +1,43 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Defines the contract for a service that validates JSON Web Tokens (JWTs).
+///
+public interface IJsonWebTokenValidator
+{
+ ///
+ /// Indicates which algorithms are accepted by the validator for verifying the signatures of incoming JWTs,
+ /// ensuring that only tokens signed with recognized and secure algorithms are considered valid.
+ ///
+ IEnumerable SigningAlgValuesSupported { get; }
+
+ ///
+ /// Asynchronously validates a JWT against a set of specified parameters.
+ ///
+ /// The JWT as a string to be validated.
+ /// The parameters against which the JWT will be validated.
+ /// A Task representing the asynchronous validation operation, which yields a JwtValidationResult indicating the outcome of the validation.
+ Task ValidateAsync(string jwt, ValidationParameters parameters);
+}
diff --git a/Abblix.Jwt/IanaClaimTypes.cs b/Abblix.Jwt/IanaClaimTypes.cs
new file mode 100644
index 00000000..91762bff
--- /dev/null
+++ b/Abblix.Jwt/IanaClaimTypes.cs
@@ -0,0 +1,870 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Provides constants for various JWT and OpenID Connect claim types.
+/// Includes both registered claim types and public claim types as defined in various standards.
+/// This classification helps in ensuring interoperability across different systems and services
+/// by adhering to a common set of identifiers for claims.
+///
+public static class IanaClaimTypes
+{
+ ///
+ /// A set of predefined claims recommended for ensuring interoperability among different systems.
+ /// These claims are widely recognized and provide basic information necessary
+ /// for many authentication and authorization processes.
+ ///
+ public static readonly IReadOnlyCollection Registered = new HashSet(StringComparer.OrdinalIgnoreCase)
+ {
+ Iss, Sub, Aud, Exp, Nbf, Iat, Jti
+ };
+
+ ///
+ /// A set of public claims that can be defined by applications as needed.
+ /// To ensure global uniqueness and avoid collisions, these claims should either be registered
+ /// with the IANA JSON Web Token Registry or be defined within a namespace that is resistant to collisions,
+ /// such as a URI.
+ ///
+ public static readonly IReadOnlyCollection Public = new HashSet(StringComparer.OrdinalIgnoreCase)
+ {
+ Name, GivenName, FamilyName, MiddleName, Nickname, PreferredUsername, Profile, Picture, Website, Email,
+ EmailVerified, Gender, Birthdate, Zoneinfo, Locale, PhoneNumber, PhoneNumberVerified, Address, UpdatedAt, Azp,
+ Nonce, AuthTime, AtHash, CHash, Acr, Amr, SubJwk, Cnf, SipFromTag, SipDate, SipCallid, SipCseqNum, SipViaBranch,
+ Orig, Dest, Mky, Events, Toe, Txn, Rph, Sid, Vot, Vtm, Attest, Origid, Act, Scope, ClientId, MayAct, Jcard,
+ AtUseNbr, Div, Opt, Vc, Vp, Sph, AceProfile, Cnonce, Exi, Roles, Groups, Entitlements, TokenIntrospection,
+ Cdniv, Cdnicrit, Cdniip, Cdniuc, Cdniets, Cdnistt, Cdnistd, SigValClaims, AuthorizationDetails
+ };
+
+ #region RFC7519, Section 4.1.1 - Issuer Claim
+
+ ///
+ /// Represents the principal (e.g., authorization server) that issued the JWT.
+ ///
+ ///
+ /// Defined in RFC 7519, Section 4.1.1. It is a case-sensitive string containing a StringOrURI value.
+ /// Use this claim to identify the issuer of the JWT uniquely.
+ ///
+ public const string Iss = "iss";
+
+ #endregion
+
+ #region RFC7519, Section 4.1.2 - Subject Claim
+
+ ///
+ /// Represents the principal that is the subject of the JWT.
+ ///
+ ///
+ /// Defined in RFC 7519, Section 4.1.2. The "sub" value is a case-sensitive string containing a StringOrURI value.
+ /// This claim is used to identify the subject of the JWT, which could be an end user or a device.
+ ///
+ public const string Sub = "sub";
+
+ #endregion
+
+ #region RFC7519, Section 4.1.3 - Audience Claim
+
+ ///
+ /// Identifies the recipients that the JWT is intended for.
+ ///
+ ///
+ /// Defined in RFC 7519, Section 4.1.3. It is generally a case-sensitive string or an array of strings containing StringOrURI values.
+ /// The audience claim ensures that the JWT is sent to the intended recipients.
+ ///
+ public const string Aud = "aud";
+
+ #endregion
+
+ #region RFC7519, Section 4.1.4 - Expiration Time Claim
+
+ ///
+ /// Specifies the expiration time on or after which the JWT must not be accepted for processing.
+ ///
+ ///
+ /// Defined in RFC 7519, Section 4.1.4. The "exp" claim is a NumericDate value. Use this claim to define the validity period of the JWT.
+ ///
+ public const string Exp = "exp";
+
+ #endregion
+
+ #region RFC7519, Section 4.1.5 - Not Before Claim
+
+ ///
+ /// Defines a time before which the JWT MUST NOT be accepted for processing.
+ ///
+ ///
+ /// Defined in RFC 7519, Section 4.1.5. The "nbf" (Not Before) claim is a NumericDate value.
+ /// This claim helps in ensuring that a JWT is not accepted before a certain time.
+ ///
+ public const string Nbf = "nbf";
+
+ #endregion
+
+ #region RFC7519, Section 4.1.6 - Issued At Claim
+
+ ///
+ /// Indicates the time at which the JWT was issued.
+ ///
+ ///
+ /// Defined in RFC 7519, Section 4.1.6. The "iat" (Issued At) claim is a NumericDate value.
+ /// This claim can be used to determine the age of the JWT.
+ ///
+ public const string Iat = "iat";
+
+ #endregion
+
+ #region RFC7519, Section 4.1.7 - JWT ID Claim
+
+ ///
+ /// Provides a unique identifier for the JWT.
+ ///
+ ///
+ /// Defined in RFC 7519, Section 4.1.7. The "jti" (JWT ID) claim is a case-sensitive string.
+ /// Use this claim to prevent the JWT from being replayed.
+ ///
+ public const string Jti = "jti";
+
+ #endregion
+
+ #region OpenID Connect Core 1.0, Section 5.1 - Personal Identifiable Information Claims
+
+ ///
+ /// Represents the full name of the user.
+ ///
+ ///
+ /// Used in OpenID Connect for representing the user's full name in a single string. It might include the first, middle, last, and other names.
+ ///
+ public const string Name = "name";
+
+ ///
+ /// Represents the first or given name(s) of the user.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim is intended to refer to the user's first name or given name(s). It allows for middle names if applicable.
+ ///
+ public const string GivenName = "given_name";
+
+ ///
+ /// Represents the surname(s) or last name(s) of the user.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim focuses on the user's family name or surname(s), excluding middle names.
+ ///
+ public const string FamilyName = "family_name";
+
+ ///
+ /// Represents the middle name(s) of the user.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim is intended for the user's middle name(s), which might not be present for all users.
+ ///
+ public const string MiddleName = "middle_name";
+
+ ///
+ /// Represents the casual name of the user.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim is for the user's casual or informal name that might differ from their legal name.
+ ///
+ public const string Nickname = "nickname";
+
+ ///
+ /// The username preferred by the user, which may be different from their actual or legal name.
+ ///
+ ///
+ /// This claim is used to convey the user's preferred username within the system. It allows the user
+ /// to specify a nickname or alias that is used within the application for display purposes,
+ /// providing a more personalized user experience.
+ ///
+ public const string PreferredUsername = "preferred_username";
+
+ ///
+ /// Represents the URL of the user's profile page.
+ ///
+ ///
+ /// Used in OpenID Connect. It is the URL of a web page containing information about the user or a social profile page.
+ ///
+ public const string Profile = "profile";
+
+ ///
+ /// Represents the URL of the user's profile picture.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim provides a URL pointing to a profile picture or avatar of the user.
+ ///
+ public const string Picture = "picture";
+
+ ///
+ /// Represents the URL of the user's web page or blog.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim indicates the URL of the user's personal or business website.
+ ///
+ public const string Website = "website";
+
+ ///
+ /// Represents the user's preferred email address.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim is for the user's preferred email. Note that this email address might not be unique.
+ ///
+ public const string Email = "email";
+
+ ///
+ /// Represents whether the user's email address has been verified.
+ ///
+ ///
+ /// Used in OpenID Connect as a boolean. True if the user's email address has been verified; otherwise false.
+ ///
+ public const string EmailVerified = "email_verified";
+
+ ///
+ /// Represents the user's gender.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim can be used to convey the user's gender. The value is not strictly defined and can vary based on the user's preference and the application's requirements.
+ ///
+ public const string Gender = "gender";
+
+ ///
+ /// Represents the user's date of birth.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim is for the user's birthdate, typically represented in the ISO 8601:2004 YYYY-MM-DD format.
+ ///
+ public const string Birthdate = "birthdate";
+
+ ///
+ /// Represents the user's time zone.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim indicates the user's time zone, facilitating localization and personalization.
+ ///
+ public const string Zoneinfo = "zoneinfo";
+
+ ///
+ /// Represents the user's locale.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim specifies the user's preferred language and optionally, region. Typically represented as a language tag, e.g., en-US or fr-CA.
+ ///
+ public const string Locale = "locale";
+
+ ///
+ /// Represents the user's phone number.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim provides the user's preferred phone number. The format of the number can vary and it's not guaranteed to be in a standard format.
+ ///
+ public const string PhoneNumber = "phone_number";
+
+ ///
+ /// Indicates whether the user's phone number has been verified.
+ ///
+ ///
+ /// Used in OpenID Connect as a boolean. True if the user's phone number has been verified; otherwise false.
+ ///
+ public const string PhoneNumberVerified = "phone_number_verified";
+
+ ///
+ /// Represents the user's postal address.
+ ///
+ ///
+ /// Used in OpenID Connect. This JSON structured claim contains components of the user's address such as street address, locality, region, postal code, and country.
+ ///
+ public const string Address = "address";
+
+ ///
+ /// Indicates when the user's information was last updated.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim provides a Unix time stamp indicating when the user's information was last updated.
+ ///
+ public const string UpdatedAt = "updated_at";
+
+ #endregion
+
+ #region OpenID Connect Core 1.0, Section 2 - Other Claims
+
+ ///
+ /// Represents the authorized party - the party to which the ID Token was issued.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim is particularly useful in delegated scenarios to identify the party using the ID Token.
+ ///
+ public const string Azp = "azp";
+
+ ///
+ /// A string value used to associate a client session with an ID Token.
+ ///
+ ///
+ /// Used in OpenID Connect to mitigate replay attacks by binding a session to a token.
+ ///
+ public const string Nonce = "nonce";
+
+ ///
+ /// Indicates the time when the authentication occurred.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim is critical in scenarios where the application requires assurance about
+ /// the moment of authentication, such as re-authentication or step-up authentication.
+ ///
+ public const string AuthTime = "auth_time";
+
+ ///
+ /// Represents the hash of the access token issued.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim is included in the ID Token and is a hash of the access token,
+ /// allowing the recipient to validate the integrity of the access token. It is particularly useful
+ /// in implicit and authorization code flows.
+ ///
+ public const string AtHash = "at_hash";
+
+ ///
+ /// Represents the Authentication Context Class Reference.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim specifies the authentication context class that the authentication
+ /// performed satisfied. It allows clients to request and services to assert the strength of an authentication process.
+ ///
+ public const string Acr = "acr";
+
+ ///
+ /// Represents the Authentication Methods References.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim is used to specify the authentication methods used in the authentication process.
+ /// It provides transparency about how the authentication was performed, such as 'pwd' for password-based
+ /// or 'mfa' for multi-factor authentication.
+ ///
+ public const string Amr = "amr";
+
+ #endregion
+
+ #region OpenID Connect Core 1.0, Section 3.3.2.11
+
+ ///
+ /// Represents the Code Hash Value.
+ ///
+ ///
+ /// Used in OpenID Connect. This claim is used in the ID Token to provide a hash of the authorization code.
+ /// It ensures that the authorization code is bound to the ID Token, enhancing the security of the code exchange process.
+ ///
+ public const string CHash = "c_hash";
+
+ #endregion
+
+ #region OpenID Connect Core 1.0, Section 7.4
+
+ ///
+ /// Represents the subject's public key as a JSON Web Key (JWK).
+ ///
+ ///
+ /// Used in scenarios where public keys are associated with JWT subjects.
+ /// This claim allows embedding a public key directly within a JWT, facilitating key discovery and distribution.
+ ///
+ public const string SubJwk = "sub_jwk";
+
+ #endregion
+
+ #region RFC7800, Section 3.1
+
+ ///
+ /// Represents confirmation methods used by the token.
+ ///
+ ///
+ /// Utilized in scenarios that require additional confirmation of token validity, such as DPoP
+ /// (Demonstrating Proof of Possession). This claim helps in binding tokens to specific cryptographic keys.
+ ///
+ public const string Cnf = "cnf";
+
+ #endregion
+
+ #region RFC8055 - SIP Claims
+
+ ///
+ /// "sip_from_tag" - Value from the SIP 'From' tag header field, used in SIP-based communications.
+ ///
+ public const string SipFromTag = "sip_from_tag";
+
+ ///
+ /// "sip_date" - Value from the SIP 'Date' header field, indicating the time of the SIP message.
+ ///
+ public const string SipDate = "sip_date";
+
+ ///
+ /// "sip_callid" - Value from the SIP 'Call-Id' header field, uniquely identifying the SIP call.
+ ///
+ public const string SipCallid = "sip_callid";
+
+ ///
+ /// "sip_cseq_num" - Numeric value from the SIP 'CSeq' header field, indicating the command sequence number in SIP protocol.
+ ///
+ public const string SipCseqNum = "sip_cseq_num";
+
+ ///
+ /// "sip_via_branch" - Value from the SIP 'Via' branch parameter, used in routing SIP messages.
+ ///
+ public const string SipViaBranch = "sip_via_branch";
+
+ #endregion
+
+ #region RFC8225, Section 5.2.1 - 5.2.2
+
+ ///
+ /// Represents the originating identity in telecommunication protocols.
+ ///
+ ///
+ /// It's used to convey the identity of the originator in communication protocols, aiding in the identification
+ /// and verification of the call origin for security and billing purposes.
+ ///
+ public const string Orig = "orig";
+
+ ///
+ /// Represents the destination identity in telecommunication protocols.
+ ///
+ ///
+ /// Useful in communication protocols to convey the intended recipient or destination of the communication,
+ /// supporting routing, billing, and security measures.
+ ///
+ public const string Dest = "dest";
+
+ ///
+ /// Represents a media key fingerprint.
+ ///
+ ///
+ /// Used in secure communication protocols to provide a fingerprint of the cryptographic key used for
+ /// encrypting media, enhancing the security of media exchanges by facilitating key verification.
+ ///
+ public const string Mky = "mky";
+
+ #endregion
+
+ #region RFC8417, Section 2.2 - Security Event Tokens
+
+ ///
+ /// Represents specific security events or state changes.
+ ///
+ ///
+ /// Used in Security Event Tokens (SETs) to convey information about security-related events or changes,
+ /// such as authentication events or configuration changes, aiding in security monitoring and response.
+ ///
+ public const string Events = "events";
+
+ ///
+ /// Represents the time of the security event.
+ ///
+ ///
+ /// This claim is used in Security Event Tokens (SETs) to indicate the precise time at which the described
+ /// security event occurred, facilitating accurate incident tracking and response.
+ ///
+ public const string Toe = "toe";
+
+ ///
+ /// Represents a transaction identifier.
+ ///
+ ///
+ /// Often utilized in financial transactions and other scenarios where tracking the identity and state
+ /// of individual transactions is critical for security, auditing, and reconciliation processes.
+ ///
+ public const string Txn = "txn";
+
+ #endregion
+
+ #region RFC8443, Section 3 - Resource Priority
+
+ ///
+ /// Represents a resource priority header.
+ ///
+ ///
+ /// This claim is used to indicate the priority of a resource or process in network communications,
+ /// ensuring that critical resources receive appropriate handling and prioritization in congested or
+ /// limited-capacity environments.
+ ///
+ public const string Rph = "rph";
+
+ #endregion
+
+ #region OpenID Connect Front-Channel Logout 1.0, Section 3
+
+ ///
+ /// Represents the session ID for front-channel logout in OpenID Connect sessions.
+ ///
+ ///
+ /// This claim is critical for implementing front-channel logout mechanisms, allowing clients and servers
+ /// to coordinate user sessions and logout processes across multiple applications and services.
+ ///
+ public const string Sid = "sid";
+
+ #endregion
+
+ #region rfc8485 - Vector of Trust
+
+ ///
+ /// Represents the vector of trust for authentication processes.
+ ///
+ ///
+ /// Used to convey the level of confidence in the authentication process, detailing the methods used and
+ /// their security properties. This claim is particularly useful in contexts requiring a nuanced understanding
+ /// of authentication assurance.
+ ///
+ public const string Vot = "vot";
+
+ ///
+ /// Represents the vector of trust trustmark.
+ ///
+ ///
+ /// Provides a URL to a trustmark that further describes the trust vector associated with the authentication process,
+ /// offering a means to verify the authentication methods and their adherence to certain standards or practices.
+ ///
+ public const string Vtm = "vtm";
+
+ #endregion
+
+ #region rfc8588 - SHAKEN Framework
+
+ ///
+ /// Represents the attestation level in SHAKEN/STIR frameworks.
+ ///
+ ///
+ /// This claim is used within the SHAKEN/STIR framework for telecommunication services, indicating the level
+ /// of attestation for the origin of a call, which aids in combating caller ID spoofing and fraud.
+ ///
+ public const string Attest = "attest";
+
+ ///
+ /// Represents the originating identifier in the SHAKEN framework.
+ ///
+ ///
+ /// Used to uniquely identify the originator of a call within the SHAKEN framework, facilitating traceability
+ /// and verification of the call's origin, and enhancing trust in telecommunication ecosystems.
+ ///
+ public const string Origid = "origid";
+
+ #endregion
+
+ #region RFC8693 - OAuth 2.0 Token Exchange
+
+ ///
+ /// Represents the actor in OAuth 2.0 token exchange.
+ ///
+ ///
+ /// This claim is used to indicate the party that the token represents, especially in delegation and
+ /// impersonation scenarios, allowing APIs and services to verify the actual party making a request.
+ ///
+ public const string Act = "act";
+
+ ///
+ /// Represents the scope associated with an access token.
+ ///
+ ///
+ /// Specifies the permissions or access rights granted to an access token, defining what actions
+ /// the token bearer is authorized to perform. This claim is fundamental in controlling access to resources.
+ ///
+ public const string Scope = "scope";
+
+ ///
+ /// Represents the client identifier in OAuth 2.0 contexts.
+ ///
+ ///
+ /// Identifies the OAuth 2.0 client that requested the token, providing a mechanism for associating a token
+ /// with a specific registered client application, critical for enforcing client-specific access policies.
+ ///
+ public const string ClientId = "client_id";
+
+ ///
+ /// Indicates the parties that the token bearer is authorized to act on behalf of.
+ ///
+ ///
+ /// This claim is used in scenarios where a token bearer is permitted to act on behalf of other parties,
+ /// enabling delegation of rights and facilitating advanced authorization scenarios.
+ ///
+ public const string MayAct = "may_act";
+
+ #endregion
+
+ #region rfc8688 - jCard Data
+
+ ///
+ /// Contains jCard data, representing contact information in a JSON format.
+ ///
+ ///
+ /// This claim is used to convey contact information in a structured format that mirrors the vCard specification,
+ /// facilitating interoperable exchange of personal or organizational contact details.
+ ///
+ public const string Jcard = "jcard";
+
+ #endregion
+
+ #region ETSI GS NFV-SEC 022 - API Request Number
+
+ ///
+ /// Indicates the number of API requests for which the access token can be used.
+ ///
+ ///
+ /// This claim is used primarily in environments where token usage is tightly controlled and monitored,
+ /// providing a mechanism for limiting the number of requests a token can authorize to enhance security and
+ /// manage resource utilization.
+ ///
+ public const string AtUseNbr = "at_use_nbr";
+
+ #endregion
+
+ #region rfc8946 - Diverted Call Information
+
+
+ ///
+ /// Contains information about a call that was diverted from its original destination.
+ ///
+ ///
+ /// This claim is used in telecommunications contexts to provide details about call diversions,
+ /// aiding in the management and tracing of call flows and in the implementation of services that
+ /// react to call redirection.
+ ///
+ public const string Div = "div";
+
+ ///
+ /// Contains the original PASSporT in full form, often used in call diversion scenarios.
+ ///
+ ///
+ /// This claim is utilized in telecommunications to verify the authenticity of redirected calls by providing
+ /// a cryptographic assertion of the call's origin, enhancing trust and security in voice communications.
+ ///
+ public const string Opt = "opt";
+
+ #endregion
+
+ #region W3C Verifiable Credentials
+
+ ///
+ /// Represents a verifiable credential as specified in the W3C Recommendation.
+ ///
+ ///
+ /// This claim is used to convey credentials that can be cryptographically verified, supporting a wide range
+ /// of applications from identity verification to qualification attestation in a secure and interoperable manner.
+ ///
+ public const string Vc = "vc";
+
+ ///
+ /// Represents a verifiable presentation as specified in the W3C Recommendation.
+ ///
+ ///
+ /// This claim is used when a subject presents one or more verifiable credentials, allowing the verifier
+ /// to check the authenticity and integrity of the credentials presented, facilitating trusted digital interactions.
+ ///
+ public const string Vp = "vp";
+
+ #endregion
+
+ #region rfc9027 - SIP Priority Header
+
+ ///
+ /// Used to indicate the priority of a SIP message.
+ ///
+ ///
+ /// This claim is relevant in Session Initiation Protocol (SIP)-based communications, where it may influence routing,
+ /// handling, and processing priorities of SIP messages, ensuring that critical communications are appropriately
+ /// prioritized.
+ ///
+ public const string Sph = "sph";
+
+ #endregion
+
+ #region RFC9200 - ACE Framework
+
+ ///
+ /// Specifies the ACE profile a token is used with, indicating its application in constrained environments.
+ ///
+ ///
+ /// This claim is significant in scenarios utilizing the Authentication and Authorization for Constrained
+ /// Environments (ACE) framework, ensuring that tokens are applied in accordance with the specific requirements
+ /// and constraints of the ACE profile in use.
+ ///
+ public const string AceProfile = "ace_profile";
+
+ ///
+ /// Nonce provided by the Resource Server to the Authorization Server via the client, verifying token freshness.
+ ///
+ ///
+ /// This claim is used to ensure the freshness of a token in interactions between the Resource Server, the client,
+ /// and the Authorization Server, mitigating against replay attacks by validating the uniqueness and timeliness
+ /// of each token request.
+ ///
+ public const string Cnonce = "cnonce";
+
+ ///
+ /// Lifetime of the token in seconds from the time the Resource Server first sees it, for devices with
+ /// unsynchronized clocks.
+ ///
+ ///
+ /// This claim addresses challenges posed by devices with unsynchronized clocks by providing a relative measure
+ /// of the token's validity, enhancing interoperability and security in distributed systems.
+ ///
+ public const string Exi = "exi";
+
+ #endregion
+
+ #region RFC7643 - SCIM Roles and Groups
+
+ ///
+ /// Represents the roles associated with the subject, often used in System for Cross-domain Identity Management (SCIM).
+ ///
+ ///
+ /// This claim is used to convey the roles attributed to a subject, facilitating role-based access control (RBAC)
+ /// and other authorization decisions in systems implementing SCIM or similar identity management protocols.
+ ///
+ public const string Roles = "roles";
+
+ ///
+ /// Represents the groups that the subject belongs to, typically used in identity and access management.
+ ///
+ ///
+ /// This claim is used to convey group membership information, supporting group-based access control and
+ /// enabling systems to make authorization decisions based on the groups a subject is associated with.
+ ///
+ public const string Groups = "groups";
+
+ ///
+ /// Represents specific entitlements or permissions granted to the subject.
+ ///
+ ///
+ /// This claim is used to specify granular permissions or entitlements granted to a subject,
+ /// allowing for precise control over access rights and enabling fine-grained authorization policies.
+ ///
+ public const string Entitlements = "entitlements";
+
+ #endregion
+
+ #region OAuth JWT Introspection
+
+ ///
+ /// Contains the response from an OAuth 2.0 token introspection request.
+ ///
+ ///
+ /// This claim is typically used in scenarios where detailed token information is necessary for validating
+ /// token status, scopes, and other attributes as part of OAuth 2.0 introspection processes.
+ ///
+ public const string TokenIntrospection = "token_introspection";
+
+ #endregion
+
+ #region CDNI Claims - RFC9246
+
+ ///
+ /// Version of the claim set used in Content Delivery Network Interconnection (CDNI).
+ ///
+ ///
+ /// This claim facilitates interoperability in CDNI contexts by specifying the version of the claim set,
+ /// ensuring that both the issuer and recipient of a JWT understand the structure and semantics of
+ /// the claims contained within.
+ ///
+ public const string Cdniv = "cdniv";
+
+ ///
+ /// Identifies critical claims within the CDNI claim set.
+ ///
+ ///
+ /// This claim is used to mark certain claims as critical within the context of CDNI,
+ /// indicating that the JWT should be processed differently or not at all if these claims are not understood
+ /// or cannot be fulfilled.
+ ///
+ public const string Cdnicrit = "cdnicrit";
+
+ ///
+ /// Represents an IP address in CDNI scenarios.
+ ///
+ ///
+ /// This claim is used to convey IP address information within CDNI,
+ /// supporting operations such as tokenized redirection or content delivery optimizations based
+ /// on geographical or network-based criteria.
+ ///
+ public const string Cdniip = "cdniip";
+
+ ///
+ /// Contains a URI in CDNI contexts.
+ ///
+ ///
+ /// This claim is utilized to reference specific resources or content within CDNI, allowing for dynamic
+ /// content delivery configurations and optimizations based on the content identified by the URI.
+ ///
+ public const string Cdniuc = "cdniuc";
+
+ ///
+ /// Expiration time setting for token renewal in CDNI.
+ ///
+ ///
+ /// This claim specifies the expiration time for a CDNI token, guiding the renewal process by indicating
+ /// when a new token must be obtained to continue accessing CDNI content or services.
+ ///
+ public const string Cdniets = "cdniets";
+
+ ///
+ /// Transport method for signed token renewal in CDNI.
+ ///
+ ///
+ /// This claim indicates the transport method to be used for renewing signed tokens in CDNI,
+ /// ensuring secure and efficient token exchange mechanisms are employed for content delivery
+ /// and interconnection services.
+ ///
+ public const string Cdnistt = "cdnistt";
+
+ ///
+ /// Depth of the signed token in CDNI.
+ ///
+ ///
+ /// This claim provides information on the depth or hierarchy level of a signed token within CDNI,
+ /// potentially influencing content delivery paths or access control decisions based on the token's
+ /// scope and applicability.
+ ///
+ public const string Cdnistd = "cdnistd";
+
+ #endregion
+
+ #region RFC9321 - Signature Validation
+
+ ///
+ /// Contains claims used for validating signatures, often in security contexts.
+ ///
+ ///
+ /// This claim set is essential for scenarios where signature validation is critical, providing necessary
+ /// information to verify the authenticity and integrity of signed data or tokens in secure communications
+ /// and transactions.
+ ///
+ public const string SigValClaims = "sig_val_claims";
+
+ #endregion
+
+ #region OAuth Rich Authorization Requests (RAR)
+
+ ///
+ /// JSON array representing the authorization requirements for a specific resource or set of resources.
+ ///
+ ///
+ /// This claim is used in OAuth Rich Authorization Requests (RAR) to specify detailed authorization data
+ /// for a transaction, enabling fine-grained access control and tailored authorization experiences.
+ ///
+ public const string AuthorizationDetails = "authorization_details";
+
+ #endregion
+}
diff --git a/Abblix.Jwt/JsonObjectExtensions.cs b/Abblix.Jwt/JsonObjectExtensions.cs
new file mode 100644
index 00000000..5a33fa62
--- /dev/null
+++ b/Abblix.Jwt/JsonObjectExtensions.cs
@@ -0,0 +1,85 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Text.Json.Nodes;
+
+namespace Abblix.Jwt;
+
+///
+/// Provides extension methods for the class, enhancing its usability
+/// by simplifying the process of accessing and manipulating JSON properties.
+///
+///
+/// The extension methods in this class aim to streamline common tasks associated with JSON objects,
+/// such as retrieving and setting properties with type safety and minimal boilerplate code. These methods
+/// abstract away some of the complexities of working directly with and ,
+/// offering a more fluent and intuitive interface for developers.
+///
+public static class JsonObjectExtensions
+{
+ ///
+ /// Retrieves the value of the specified property from a .
+ ///
+ /// The instance to extract the property value from.
+ /// The name of the property whose value is to be retrieved.
+ /// The expected type of the property value.
+ ///
+ /// The value of the specified property if it exists and can be successfully converted to the specified type;
+ /// otherwise, the default value for the type .
+ ///
+ ///
+ /// This method facilitates the retrieval of typed values from a JSON object, abstracting away the need
+ /// for manual type checking and conversion.
+ ///
+ public static T? GetProperty(this JsonObject json, string name)
+ {
+ return json.TryGetPropertyValue(name, out var value) && value != null
+ ? value.GetValue()
+ : default;
+ }
+
+ ///
+ /// Sets or updates the value of a specified property in a .
+ ///
+ /// The instance to modify.
+ /// The name of the property to set or update.
+ /// The new value for the property. If null, the property is removed from the .
+ ///
+ /// This method provides a convenient way to update the properties of a JSON object, allowing for
+ /// the addition of new properties or the removal of existing ones by providing a null value.
+ /// It ensures that the JSON object remains in a consistent state by avoiding the presence of null property values.
+ ///
+ public static JsonObject SetProperty(this JsonObject json, string name, JsonNode? value)
+ {
+ if (json.TryGetPropertyValue(name, out _))
+ {
+ if (value == null)
+ json.Remove(name);
+ }
+ else if (value != null)
+ {
+ json.Add(name, value);
+ }
+
+ return json;
+ }
+}
diff --git a/Abblix.Jwt/JsonWebKey.cs b/Abblix.Jwt/JsonWebKey.cs
new file mode 100644
index 00000000..5dccfa5d
--- /dev/null
+++ b/Abblix.Jwt/JsonWebKey.cs
@@ -0,0 +1,199 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Text.Json.Serialization;
+using Abblix.Utils.Json;
+
+namespace Abblix.Jwt;
+
+//TODO consider to split this class into specialized subclasses (RSA/EllipticCurve)
+///
+/// Represents a JSON Web Key (JWK), a versatile structure for representing cryptographic keys using JSON.
+/// It supports various cryptographic algorithms, including RSA and Elliptic Curve, and can represent both
+/// public and private keys. JWKs are crucial for digital signatures, encryption, and ensuring secure
+/// communication in web-based protocols.
+///
+public record JsonWebKey
+{
+ ///
+ /// Identifies the cryptographic algorithm family used with the key, such as RSA or EC (Elliptic Curve),
+ /// specifying the key's type and its intended cryptographic use.
+ ///
+ [JsonPropertyName("kty")]
+ [JsonPropertyOrder(1)]
+ public string? KeyType { get; set; }
+
+ ///
+ /// Indicates the intended use of the key, for example, "sig" (signature) for signing operations or
+ /// "enc" (encryption) for encryption operations, guiding clients on how to use the key appropriately.
+ ///
+ [JsonPropertyName("use")]
+ [JsonPropertyOrder(2)]
+ public string? Usage { get; set; }
+
+ ///
+ /// Specifies the algorithm intended for use with the key, aligning with JWT and JWA specifications
+ /// to ensure interoperability and secure key management.
+ ///
+ [JsonPropertyName("alg")]
+ [JsonPropertyOrder(3)]
+ public string? Algorithm { get; set; }
+
+ ///
+ /// A unique identifier for the key, facilitating key selection and management in multi-key environments,
+ /// enabling clients and servers to reference and utilize the correct key for cryptographic operations.
+ ///
+ [JsonPropertyName("kid")]
+ [JsonPropertyOrder(4)]
+ public string? KeyId { get; set; }
+
+ ///
+ /// Contains a chain of one or more PKIX certificates (RFC 5280), offering a method to associate X.509
+ /// certificates with the key for validation and trust chain establishment in secure communications.
+ ///
+ [JsonPropertyName("x5c")]
+ [JsonPropertyOrder(5)]
+ [JsonConverter(typeof(ArrayConverter))]
+ public byte[][]? Certificates { get; set; }
+
+ ///
+ /// A base64url-encoded SHA-1 thumbprint of the DER encoding of an X.509 certificate, providing a compact
+ /// means to associate a certificate with the JWK for verification purposes without transmitting the full certificate.
+ ///
+ [JsonPropertyName("x5t")]
+ [JsonPropertyOrder(5)]
+ [JsonConverter(typeof(Base64UrlTextEncoderConverter))]
+ public byte[]? Thumbprint { get; set; }
+
+ ///
+ /// RSA Public Key Exponent (e). Part of the RSA public key.
+ ///
+ [JsonPropertyName("e")]
+ [JsonPropertyOrder(6)]
+ [JsonConverter(typeof(Base64UrlTextEncoderConverter))]
+ public byte[]? RsaExponent { get; set; }
+
+ ///
+ /// RSA Public Key Modulus (n). Part of the RSA public key.
+ ///
+ [JsonPropertyName("n")]
+ [JsonPropertyOrder(7)]
+ [JsonConverter(typeof(Base64UrlTextEncoderConverter))]
+ public byte[]? RsaModulus { get; set; }
+
+ ///
+ /// X-coordinate for Elliptic Curve (x). Part of the Elliptic Curve public key.
+ ///
+ [JsonPropertyName("x")]
+ [JsonPropertyOrder(8)]
+ [JsonConverter(typeof(Base64UrlTextEncoderConverter))]
+ public byte[]? EllipticalCurvePointX { get; set; }
+
+ ///
+ /// Y-coordinate for Elliptic Curve (y). Part of the Elliptic Curve public key.
+ ///
+ [JsonPropertyName("y")]
+ [JsonPropertyOrder(9)]
+ [JsonConverter(typeof(Base64UrlTextEncoderConverter))]
+ public byte[]? EllipticalCurvePointY { get; set; }
+
+ ///
+ /// Elliptic Curve Type (crv). Identifies the curve type for an Elliptic Curve key.
+ ///
+ [JsonPropertyName("crv")]
+ [JsonPropertyOrder(10)]
+ public string? EllipticalCurveType { get; set; }
+
+ ///
+ /// ECC Private Key or RSA Private Exponent (d). Represents the private part of an RSA or Elliptic Curve key.
+ ///
+ [JsonPropertyName("d")]
+ [JsonPropertyOrder(11)]
+ [JsonConverter(typeof(Base64UrlTextEncoderConverter))]
+ public byte[]? PrivateKey { get; set; }
+
+ ///
+ /// RSA First Prime Factor (p). Part of the RSA private key.
+ ///
+ [JsonPropertyName("p")]
+ [JsonPropertyOrder(12)]
+ [JsonConverter(typeof(Base64UrlTextEncoderConverter))]
+ public byte[]? FirstPrimeFactor { get; set; }
+
+ ///
+ /// RSA Second Prime Factor (q). Part of the RSA private key.
+ ///
+ [JsonPropertyName("q")]
+ [JsonPropertyOrder(13)]
+ [JsonConverter(typeof(Base64UrlTextEncoderConverter))]
+ public byte[]? SecondPrimeFactor { get; set; }
+
+ ///
+ /// RSA First Factor CRT Exponent (dp). Part of the RSA private key in Chinese Remainder Theorem (CRT) format.
+ ///
+ [JsonPropertyName("dp")]
+ [JsonPropertyOrder(14)]
+ [JsonConverter(typeof(Base64UrlTextEncoderConverter))]
+ public byte[]? FirstFactorCrtExponent { get; set; }
+
+ ///
+ /// RSA Second Factor CRT Exponent (dq). Part of the RSA private key in CRT format.
+ ///
+ [JsonPropertyName("dq")]
+ [JsonPropertyOrder(15)]
+ [JsonConverter(typeof(Base64UrlTextEncoderConverter))]
+ public byte[]? SecondFactorCrtExponent { get; set; }
+
+ ///
+ /// RSA First CRT Coefficient (qi). Part of the RSA private key in CRT format.
+ ///
+ [JsonPropertyName("qi")]
+ [JsonPropertyOrder(16)]
+ [JsonConverter(typeof(Base64UrlTextEncoderConverter))]
+ public byte[]? FirstCrtCoefficient { get; set; }
+
+ ///
+ /// Prepares a sanitized version of the JWK that excludes private key information unless explicitly included,
+ /// suitable for public sharing while preserving the integrity of sensitive data.
+ ///
+ /// Whether to include private key data in the sanitized output.
+ ///
+ /// A new instance of with or without private key data based on the input parameter.
+ ///
+ public JsonWebKey Sanitize(bool includePrivateKeys)
+ {
+ return includePrivateKeys switch
+ {
+ true when PrivateKey is { Length: > 0} => this,
+ true => throw new InvalidOperationException($"There is no private key for kid={KeyId}"),
+ false => this with
+ {
+ PrivateKey = null,
+ FirstCrtCoefficient = null,
+ FirstPrimeFactor = null,
+ FirstFactorCrtExponent = null,
+ SecondPrimeFactor = null,
+ SecondFactorCrtExponent = null,
+ }
+ };
+ }
+}
diff --git a/Abblix.Jwt/JsonWebKeyExtensions.cs b/Abblix.Jwt/JsonWebKeyExtensions.cs
new file mode 100644
index 00000000..c9602195
--- /dev/null
+++ b/Abblix.Jwt/JsonWebKeyExtensions.cs
@@ -0,0 +1,304 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Security.Cryptography;
+using System.Security.Cryptography.X509Certificates;
+using Abblix.Utils;
+using Microsoft.IdentityModel.Tokens;
+
+namespace Abblix.Jwt;
+
+///
+/// Provides extension methods for the JsonWebKey model to simplify the process of populating its properties from different sources.
+/// These methods enable easy conversion between JsonWebKey and various cryptographic representations.
+///
+public static class JsonWebKeyExtensions
+{
+ ///
+ /// Converts a JsonWebKey to SigningCredentials used in cryptographic operations, specifically for signing tokens.
+ ///
+ /// The JsonWebKey to convert.
+ /// SigningCredentials based on the provided JsonWebKey.
+ /// Thrown when the algorithm is not supported.
+ public static SigningCredentials ToSigningCredentials(this JsonWebKey jsonWebKey)
+ {
+ return jsonWebKey.Algorithm switch
+ {
+ SigningAlgorithms.RS256 => new SigningCredentials(jsonWebKey.ToSecurityKey(), SigningAlgorithms.RS256),
+ _ => throw new InvalidOperationException($"Not supported algorithm: {jsonWebKey.Algorithm}"),
+ };
+ }
+
+ ///
+ /// Converts a JsonWebKey to an RsaSecurityKey used in RSA cryptographic operations.
+ ///
+ /// The JsonWebKey to convert.
+ /// RsaSecurityKey based on the provided JsonWebKey.
+ public static RsaSecurityKey ToSecurityKey(this JsonWebKey jsonWebKey)
+ {
+ return new RsaSecurityKey(jsonWebKey.ToRsa()) { KeyId = jsonWebKey.KeyId };
+ }
+
+ ///
+ /// Converts a JsonWebKey to EncryptingCredentials used in cryptographic operations, specifically for encrypting tokens.
+ ///
+ /// The JsonWebKey to convert.
+ /// EncryptingCredentials based on the provided JsonWebKey.
+ /// Thrown when the algorithm is not supported.
+ public static EncryptingCredentials ToEncryptingCredentials(this JsonWebKey jsonWebKey)
+ {
+ return jsonWebKey.Algorithm switch
+ {
+ SigningAlgorithms.RS256 => new EncryptingCredentials(
+ jsonWebKey.ToSecurityKey(),
+ SecurityAlgorithms.RsaOAEP,
+ SecurityAlgorithms.Aes128CbcHmacSha256),
+
+ _ => throw new InvalidOperationException($"Not supported algorithm: {jsonWebKey.Algorithm}"),
+ };
+ }
+
+ ///
+ /// Converts an X509Certificate2 to a JsonWebKey. The private keys can be optionally included in the conversion.
+ ///
+ /// The X509Certificate2 to convert.
+ /// Indicates whether to include private keys in the conversion.
+ /// A JsonWebKey representing the certificate.
+ public static JsonWebKey ToJsonWebKey(this X509Certificate2 certificate, bool includePrivateKeys = false)
+ => new X509SecurityKey(certificate).ToJsonWebKey(SecurityAlgorithms.RsaSha256, includePrivateKeys);
+
+ ///
+ /// Converts a SecurityKey to a JsonWebKey with a specified algorithm. The private keys can be optionally included.
+ ///
+ /// The SecurityKey to convert.
+ /// The algorithm to be used with the key.
+ /// Indicates whether to include private keys in the conversion.
+ /// A JsonWebKey representing the SecurityKey.
+ public static JsonWebKey ToJsonWebKey(this SecurityKey key, string algorithm, bool includePrivateKeys = false)
+ {
+ // TODO Move it to a virtual method of generic Credentials class with specific implementations in derived classes
+ var jwk = new JsonWebKey
+ {
+ Usage = key.MapKeyUsage(),
+ Algorithm = AlgorithmMapper.MapToOutbound(algorithm),
+ KeyId = key.KeyId,
+ };
+
+ return key switch
+ {
+ X509SecurityKey { PublicKey: RSA publicKey, PrivateKey: RSA privateKey, Certificate: { } cert }
+ => jwk
+ .Apply(publicKey.ExportParameters(false))
+ .Apply(privateKey.ExportParameters(includePrivateKeys))
+ .Apply(cert),
+
+ X509SecurityKey { PublicKey: RSA publicKey, Certificate: { } cert } when !includePrivateKeys
+ => jwk
+ .Apply(publicKey.ExportParameters(false))
+ .Apply(cert),
+
+ X509SecurityKey { PublicKey: ECDsa publicKey, PrivateKey: ECDsa privateKey, Certificate: { } cert }
+ => jwk
+ .Apply(publicKey.ExportParameters(false))
+ .Apply(privateKey.ExportParameters(includePrivateKeys))
+ .Apply(cert),
+
+ X509SecurityKey { PublicKey: ECDsa publicKey, Certificate: { } cert } when !includePrivateKeys
+ => jwk
+ .Apply(publicKey.ExportParameters(false))
+ .Apply(cert),
+
+ RsaSecurityKey { Rsa: { } rsa } => jwk.Apply(rsa.ExportParameters(includePrivateKeys)),
+ RsaSecurityKey { Parameters: var parameters } => jwk.Apply(parameters),
+
+ ECDsaSecurityKey { ECDsa: { } ecDsa } => jwk.Apply(ecDsa.ExportParameters(includePrivateKeys)),
+
+ Microsoft.IdentityModel.Tokens.JsonWebKey jsonWebKey => jwk.Apply(jsonWebKey, includePrivateKeys),
+
+ _ => throw new InvalidOperationException($"The key type {key.GetType().FullName} is not supported"),
+ };
+ }
+
+ ///
+ /// Maps the key usage of a SecurityKey to a string representation.
+ /// Determines whether the key is used for signing, encryption, or both.
+ ///
+ /// The SecurityKey whose usage is to be determined.
+ /// A string representing the usage of the key.
+ private static string MapKeyUsage(this SecurityKey key)
+ {
+ const string defaultUsage = PublicKeyUsages.Signature;
+
+ if (key is not X509SecurityKey x509Key)
+ return defaultUsage;
+
+ var keyUsage = x509Key.Certificate.Extensions.OfType().FirstOrDefault();
+ if (keyUsage == null)
+ return defaultUsage;
+
+ var sig = keyUsage.KeyUsages.HasFlag(X509KeyUsageFlags.DigitalSignature);
+ var enc = keyUsage.KeyUsages.HasFlag(X509KeyUsageFlags.KeyEncipherment |
+ X509KeyUsageFlags.DataEncipherment);
+ return (sig, enc) switch
+ {
+ (true, true) => PublicKeyUsages.Signature + " " + PublicKeyUsages.Encryption,
+ (true, false) => PublicKeyUsages.Signature,
+ (false, true) => PublicKeyUsages.Encryption,
+ _ => defaultUsage,
+ };
+ }
+
+ ///
+ /// Applies X509Certificate2 properties to a JsonWebKey.
+ ///
+ /// The JsonWebKey to which the certificate properties are to be applied.
+ /// The X509Certificate2 providing the properties.
+ /// The updated JsonWebKey with applied certificate properties.
+ public static JsonWebKey Apply(this JsonWebKey jwk, X509Certificate2 certificate)
+ {
+ jwk.Certificates = new[] { certificate.RawData };
+ jwk.Thumbprint = certificate.GetCertHash();
+ return jwk;
+ }
+
+ ///
+ /// Applies RSA parameters to a JsonWebKey.
+ ///
+ /// The JsonWebKey to which the RSA parameters are to be applied.
+ /// The RSAParameters providing the RSA key information.
+ /// The updated JsonWebKey with applied RSA parameters.
+ public static JsonWebKey Apply(this JsonWebKey jwk, RSAParameters parameters)
+ {
+ jwk.KeyType = JsonWebKeyTypes.Rsa;
+ jwk.RsaExponent = parameters.Exponent;
+ jwk.RsaModulus = parameters.Modulus;
+
+ jwk.PrivateKey = parameters.D;
+ jwk.FirstPrimeFactor = parameters.P;
+ jwk.SecondPrimeFactor = parameters.Q;
+ jwk.FirstFactorCrtExponent = parameters.DP;
+ jwk.SecondFactorCrtExponent = parameters.DQ;
+ jwk.FirstCrtCoefficient = parameters.InverseQ;
+
+ return jwk;
+ }
+
+ private static class EllipticalCurveOids
+ {
+ public const string P256 = "1.2.840.10045.3.1.7";
+ public const string P384 = "1.3.132.0.34";
+ public const string P521 = "1.3.132.0.35";
+ }
+
+ ///
+ /// Applies Elliptic Curve parameters to a JsonWebKey.
+ ///
+ /// The JsonWebKey to which the EC parameters are to be applied.
+ /// The ECParameters providing the Elliptic Curve key information.
+ /// The updated JsonWebKey with applied Elliptic Curve parameters.
+ private static JsonWebKey Apply(this JsonWebKey jwk, ECParameters parameters)
+ {
+ jwk.KeyType = JsonWebKeyTypes.EllipticalCurve;
+
+ var curveOid = parameters.Curve.Oid;
+ jwk.EllipticalCurveType = curveOid.Value switch
+ {
+ EllipticalCurveOids.P256 => JsonWebKeyECTypes.P256,
+ EllipticalCurveOids.P384 => JsonWebKeyECTypes.P384,
+ EllipticalCurveOids.P521 => JsonWebKeyECTypes.P521,
+ _ => throw new InvalidOperationException($"The OID [{curveOid.Value}] {curveOid.FriendlyName} is not supported"),
+ };
+
+ jwk.EllipticalCurvePointX = parameters.Q.X;
+ jwk.EllipticalCurvePointY = parameters.Q.Y;
+
+ if (parameters.D != null) jwk.PrivateKey = parameters.D;
+
+ return jwk;
+ }
+
+ ///
+ /// Converts a Microsoft.IdentityModel.Tokens.JsonWebKey to a custom JsonWebKey.
+ /// This method allows the conversion of keys between different JsonWebKey implementations.
+ ///
+ /// The JsonWebKey to be converted.
+ /// The Microsoft.IdentityModel.Tokens.JsonWebKey to convert.
+ /// Indicates whether to include private keys in the conversion.
+ /// A JsonWebKey representing the Microsoft.IdentityModel.Tokens.JsonWebKey.
+ private static JsonWebKey Apply(this JsonWebKey jwk, Microsoft.IdentityModel.Tokens.JsonWebKey key, bool includePrivateKeys = false)
+ {
+ jwk.KeyType = key.Kty;
+ jwk.Usage = key.Use ?? PublicKeyUsages.Signature;
+ jwk.Algorithm = key.Alg;
+ jwk.KeyId = key.Kid;
+
+ jwk.Certificates = key.X5c is { Count: > 0 } certificates ? certificates.Select(HttpServerUtility.UrlTokenDecode).ToArray() : null;
+ jwk.Thumbprint = HttpServerUtility.UrlTokenDecode(key.X5t);
+
+ jwk.RsaExponent = HttpServerUtility.UrlTokenDecode(key.E);
+ jwk.RsaModulus = HttpServerUtility.UrlTokenDecode(key.N);
+
+ jwk.EllipticalCurveType = key.Crv;
+ jwk.EllipticalCurvePointX = HttpServerUtility.UrlTokenDecode(key.X);
+ jwk.EllipticalCurvePointY = HttpServerUtility.UrlTokenDecode(key.Y);
+
+ if (includePrivateKeys)
+ {
+ jwk.PrivateKey = HttpServerUtility.UrlTokenDecode(key.D);
+ jwk.FirstPrimeFactor = HttpServerUtility.UrlTokenDecode(key.P);
+ jwk.SecondPrimeFactor = HttpServerUtility.UrlTokenDecode(key.Q);
+ jwk.FirstFactorCrtExponent = HttpServerUtility.UrlTokenDecode(key.DP);
+ jwk.SecondFactorCrtExponent = HttpServerUtility.UrlTokenDecode(key.DQ);
+ jwk.FirstCrtCoefficient = HttpServerUtility.UrlTokenDecode(key.QI);
+ }
+ return jwk;
+ }
+
+ ///
+ /// Converts a JsonWebKey to an RSA object, which represents an RSA public and private key pair or just a public key.
+ ///
+ /// The JsonWebKey to be converted.
+ /// An RSA object based on the provided JsonWebKey.
+ public static RSA ToRsa(this JsonWebKey key)
+ {
+ var rsa = RSA.Create();
+ rsa.ImportParameters(key.ToRsaParameters());
+ return rsa;
+ }
+
+ ///
+ /// Converts a JsonWebKey to RSAParameters, which represent the key parameters used in RSA cryptographic operations.
+ ///
+ /// The JsonWebKey to be converted.
+ /// An RSAParameters object based on the provided JsonWebKey.
+ public static RSAParameters ToRsaParameters(this JsonWebKey key) => new()
+ {
+ Modulus = key.RsaModulus,
+ Exponent = key.RsaExponent,
+ D = key.PrivateKey,
+ P = key.FirstPrimeFactor,
+ Q = key.SecondPrimeFactor,
+ DP = key.FirstFactorCrtExponent,
+ DQ = key.SecondFactorCrtExponent,
+ InverseQ = key.FirstCrtCoefficient,
+ };
+}
diff --git a/Abblix.Jwt/JsonWebKeyFactory.cs b/Abblix.Jwt/JsonWebKeyFactory.cs
new file mode 100644
index 00000000..1ee7b019
--- /dev/null
+++ b/Abblix.Jwt/JsonWebKeyFactory.cs
@@ -0,0 +1,73 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Security.Cryptography;
+using Microsoft.IdentityModel.Tokens;
+
+namespace Abblix.Jwt;
+
+///
+/// A factory for creating JsonWebKey objects, focusing on RSA keys.
+/// This class provides a method to generate RSA keys with a specified usage and key size,
+/// which can be used for signing or encryption in cryptographic operations.
+///
+public static class JsonWebKeyFactory
+{
+ ///
+ /// Creates an RSA JsonWebKey with a specified usage and key size.
+ ///
+ /// The intended usage of the key, typically 'sig' for signing or 'enc' for encryption.
+ /// The size of the RSA key in bits. The default is 2048 bits, which is commonly used and
+ /// provides a good security level.
+ /// A that contains the RSA key details suitable for JWT operations.
+ public static JsonWebKey CreateRsa(string usage, int keySize = 2048 /* Recommended key size for RSA */)
+ {
+ var algorithm = usage switch
+ {
+ JsonWebKeyUseNames.Sig or JsonWebKeyUseNames.Enc => "RS256",
+ _ => throw new ArgumentException(
+ $"Invalid usage specified. Valid options are '{JsonWebKeyUseNames.Sig}' for signing or '{JsonWebKeyUseNames.Enc}' for encryption.",
+ nameof(usage))
+ };
+
+ using var rsa = RSA.Create();
+ rsa.KeySize = keySize;
+ var parameters = rsa.ExportParameters(true);
+
+ var key = new JsonWebKey
+ {
+ KeyType = "RSA",
+ Algorithm = algorithm,
+ Usage = usage,
+ RsaExponent = parameters.Exponent,
+ RsaModulus = parameters.Modulus,
+ PrivateKey = parameters.D,
+ FirstPrimeFactor = parameters.P,
+ SecondPrimeFactor = parameters.Q,
+ FirstFactorCrtExponent = parameters.DP,
+ SecondFactorCrtExponent = parameters.DQ,
+ FirstCrtCoefficient = parameters.InverseQ,
+ };
+
+ return key;
+ }
+}
diff --git a/Abblix.Jwt/JsonWebKeySet.cs b/Abblix.Jwt/JsonWebKeySet.cs
new file mode 100644
index 00000000..b722ace4
--- /dev/null
+++ b/Abblix.Jwt/JsonWebKeySet.cs
@@ -0,0 +1,40 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Text.Json.Serialization;
+
+namespace Abblix.Jwt;
+
+///
+/// Represents a JSON Web Key Set (JWKS) as defined by the JSON Web Key (JWK) specifications.
+/// A JWKS is a set of keys containing the public keys used to verify any JSON Web Token (JWT) issued by the authorization server.
+///
+public record JsonWebKeySet(JsonWebKey[] Keys)
+{
+ ///
+ /// Gets an array of objects representing the cryptographic keys.
+ ///
+ ///
+ /// The 'keys' property in a JWKS is an array of JWK objects. Each JWK object within the array is a JSON object representing a single public key.
+ ///
+ [JsonPropertyName("keys")] public JsonWebKey[] Keys { get; init; } = Keys;
+}
diff --git a/Abblix.Jwt/JsonWebKeyTypes.cs b/Abblix.Jwt/JsonWebKeyTypes.cs
new file mode 100644
index 00000000..50f8893d
--- /dev/null
+++ b/Abblix.Jwt/JsonWebKeyTypes.cs
@@ -0,0 +1,42 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Provides constants for the types of JSON Web Keys (JWK) as defined in the JWK specifications.
+/// These constants are used to identify the cryptographic algorithm family used by the key.
+///
+public static class JsonWebKeyTypes
+{
+ ///
+ /// Represents an Elliptical Curve cryptographic key.
+ /// This type is used for keys that employ elliptic curve cryptography (ECC) algorithms.
+ ///
+ public const string EllipticalCurve = "EC";
+
+ ///
+ /// Represents a RSA cryptographic key.
+ /// This type is used for keys that employ RSA cryptography algorithms.
+ ///
+ public const string Rsa = "RSA";
+}
diff --git a/Abblix.Jwt/JsonWebToken.cs b/Abblix.Jwt/JsonWebToken.cs
new file mode 100644
index 00000000..2ca56edd
--- /dev/null
+++ b/Abblix.Jwt/JsonWebToken.cs
@@ -0,0 +1,53 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Text.Json.Nodes;
+
+namespace Abblix.Jwt;
+
+///
+/// Represents a JSON Web Token (JWT), a compact, URL-safe means of representing
+/// claims to be transferred between two parties. This record encapsulates the standard
+/// JWT structure, offering properties to access and manipulate the header, payload, and claims.
+///
+public record JsonWebToken
+{
+ ///
+ /// Represents the JWT header, containing metadata about the type of token and the algorithms used to secure it.
+ ///
+ ///
+ /// The header typically includes information such as the type of token (JWT) and
+ /// the signing algorithm (e.g., HS256, RS256). This property allows direct access
+ /// and manipulation of these values.
+ ///
+ public JsonWebTokenHeader Header { get; init; } = new(new JsonObject());
+
+ ///
+ /// Represents the JWT payload, containing the claims about the entity (typically, the user)
+ /// and additional metadata.
+ ///
+ ///
+ /// The payload is where the claims of the JWT are stored. This includes standard claims such as
+ /// issuer, subject, and expiration time, as well as custom claims as required by the application.
+ ///
+ public JsonWebTokenPayload Payload { get; init; } = new(new JsonObject());
+}
diff --git a/Abblix.Jwt/JsonWebTokenAlgorithms.cs b/Abblix.Jwt/JsonWebTokenAlgorithms.cs
new file mode 100644
index 00000000..e863372c
--- /dev/null
+++ b/Abblix.Jwt/JsonWebTokenAlgorithms.cs
@@ -0,0 +1,40 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.IdentityModel.Tokens.Jwt;
+
+namespace Abblix.Jwt;
+
+internal static class JsonWebTokenAlgorithms
+{
+ /// ///
+ /// Defines a static collection of signing algorithm values that are supported for JSON Web Tokens (JWTs).
+ /// This collection is based on the algorithms recognized by the JwtSecurityTokenHandler for outbound tokens,
+ /// including an option for 'none' to allow unsigned tokens. This class serves as a central metadata repository
+ /// for supported algorithms used by both JsonWebTokenCreator and JsonWebTokenValidator classes,
+ /// leveraging JwtSecurityTokenHandler under the hood.
+ ///
+ public static readonly IEnumerable SigningAlgValuesSupported =
+ JwtSecurityTokenHandler.DefaultOutboundAlgorithmMap.Values
+ .Append(SigningAlgorithms.None)
+ .ToArray();
+}
diff --git a/Abblix.Jwt/JsonWebTokenCreator.cs b/Abblix.Jwt/JsonWebTokenCreator.cs
new file mode 100644
index 00000000..ab173ab6
--- /dev/null
+++ b/Abblix.Jwt/JsonWebTokenCreator.cs
@@ -0,0 +1,136 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.IdentityModel.Tokens.Jwt;
+using Microsoft.IdentityModel.Tokens;
+
+namespace Abblix.Jwt;
+
+///
+/// Responsible for creating JSON Web Tokens (JWTs). This class provides functionality to issue JWTs based on given claims and keys.
+///
+///
+/// The class uses to define the token's properties and leverages
+/// for token creation. It supports setting standard claims such as issuer, audience, and times, as well as custom claims
+/// contained within the provided instance.
+///
+public sealed class JsonWebTokenCreator : IJsonWebTokenCreator
+{
+ ///
+ /// Gets the collection of signing algorithms supported for JWT creation.
+ /// This property reflects the JWT security token handler's default outbound algorithm mapping,
+ /// indicating the algorithms available for signing the tokens.
+ ///
+ public IEnumerable SigningAlgValuesSupported => JsonWebTokenAlgorithms.SigningAlgValuesSupported;
+
+ ///
+ /// Asynchronously issues a JWT based on the specified JsonWebToken, signing key, and optional encrypting key.
+ ///
+ /// The JsonWebToken object containing the payload of the JWT.
+ /// The signing key as a JsonWebKey to sign the JWT.
+ /// Optional encrypting key as a JsonWebKey to encrypt the JWT.
+ /// A Task that represents the asynchronous operation and yields the JWT as a string.
+ /// Thrown if the specified date time values cause an overflow.
+ ///
+ /// The method configures a based on the provided JWT, signing key, and encrypting key.
+ /// It then creates the JWT using and returns the serialized token string.
+ /// Note: The audience is set to the first value if multiple audiences are provided, due to limitations of
+ /// .
+ ///
+ public Task IssueAsync(
+ JsonWebToken jwt,
+ JsonWebKey? signingKey,
+ JsonWebKey? encryptingKey = null)
+ {
+ var descriptor = new SecurityTokenDescriptor
+ {
+ TokenType = jwt.Header.Type,
+ Issuer = jwt.Payload.Issuer,
+ Audience = jwt.Payload.Audiences?.SingleOrDefault(), //TODO replace JwtSecurityTokenHandler with own code to overcome this limitation
+
+ IssuedAt = CheckDateOverflow(jwt.Payload.IssuedAt, nameof(jwt.Payload.IssuedAt)),
+ NotBefore = CheckDateOverflow(jwt.Payload.NotBefore, nameof(jwt.Payload.NotBefore)),
+ Expires = CheckDateOverflow(jwt.Payload.ExpiresAt, nameof(jwt.Payload.ExpiresAt)),
+
+ Claims = Convert(jwt.Payload),
+ };
+
+ if (signingKey != null)
+ descriptor.SigningCredentials = signingKey.ToSigningCredentials();
+
+ if (encryptingKey != null)
+ descriptor.EncryptingCredentials = encryptingKey.ToEncryptingCredentials();
+
+ var token = new JwtSecurityTokenHandler().CreateJwtSecurityToken(descriptor);
+
+ return Task.FromResult(token.RawData);
+ }
+
+ ///
+ /// Checks if the specified DateTimeOffset is within the allowable range for JWT date/time claims.
+ ///
+ /// The DateTimeOffset to check.
+ /// The name of the date/time claim for error reporting purposes.
+ /// A DateTime representation of the DateTimeOffset if it is within the allowable range.
+ /// Thrown if the specified DateTimeOffset causes an overflow.
+ ///
+ /// This method ensures that date/time claims do not exceed the maximum possible value that can be encoded in a JWT,
+ /// preventing potential issues with token processing and validation.
+ ///
+ private static DateTime? CheckDateOverflow(DateTimeOffset? dateTime, string name)
+ {
+ if (!dateTime.HasValue)
+ return null;
+
+ var maxPossibleDateTime = DateTimeOffset.UnixEpoch.AddSeconds(int.MaxValue);
+ if (maxPossibleDateTime < dateTime)
+ throw new ArgumentOutOfRangeException(name, dateTime, $"{name} value causes overflow: {dateTime}");
+
+ return dateTime.Value.UtcDateTime;
+ }
+
+ ///
+ /// Converts a collection of JwtClaims into a dictionary suitable for a JWT payload.
+ ///
+ /// The JsonWebTokenPayload containing the claims to be converted.
+ /// A dictionary of claims where the key is the claim type and the value is the claim value.
+ ///
+ /// This method facilitates the conversion of the JWT payload into a format compatible with .
+ /// It ensures that each claim is correctly represented, handling cases where claims have single or multiple values.
+ ///
+ private static IDictionary Convert(JsonWebTokenPayload payload)
+ {
+ var uniqueClaims = payload.Json
+ .ExceptBy(
+ JwtSecurityTokenHandlerConstants.ClaimTypesToExclude,
+ claim => claim.Key)
+ .GroupBy(
+ claim => claim.Key,
+ claim => claim.Value.ToJsonElement());
+
+ var result = uniqueClaims.ToDictionary(
+ claim => claim.Key,
+ claim => claim.Count() == 1 ? (object)claim.Single() : claim.ToArray());
+
+ return result;
+ }
+}
diff --git a/Abblix.Jwt/JsonWebTokenExtensions.cs b/Abblix.Jwt/JsonWebTokenExtensions.cs
new file mode 100644
index 00000000..037e36ed
--- /dev/null
+++ b/Abblix.Jwt/JsonWebTokenExtensions.cs
@@ -0,0 +1,225 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Text.Json;
+using System.Text.Json.Nodes;
+using Abblix.Utils;
+
+namespace Abblix.Jwt;
+
+///
+/// Provides extension methods for handling JSON data within JWTs.
+///
+public static class JsonWebTokenExtensions
+{
+ ///
+ /// Retrieves a value from a based on
+ /// a property stored as Unix time seconds.
+ ///
+ /// The from which to retrieve the date/time value.
+ /// The property name containing the Unix time seconds.
+ ///
+ /// A nullable representing the date and time of the specified property,
+ /// or null if the property is not present or cannot be converted.
+ ///
+ ///
+ /// Unix time seconds are widely used for representing date and time in JSON objects, especially in JWTs.
+ /// This method simplifies retrieving such values by converting them directly to .
+ ///
+ public static DateTimeOffset? GetUnixTimeSeconds(this JsonObject json, string name)
+ {
+ var node = json[name];
+ if (node == null)
+ return null;
+
+ var value = node.AsValue();
+ var seconds = value.TryGetValue(out var intValue) ? intValue : value.GetValue();
+ return DateTimeOffset.FromUnixTimeSeconds(seconds);
+ }
+
+ ///
+ /// Sets a value in a , stored as Unix time seconds.
+ ///
+ /// The to modify.
+ /// The property name under which to store the Unix time seconds.
+ /// The value to set. If null,
+ /// the property will be removed from the JSON object.
+ /// The modified .
+ ///
+ /// Storing dates as Unix time seconds is a common practice in JWTs and other JSON structures.
+ /// This method facilitates setting such values by converting to Unix time seconds.
+ ///
+ public static void SetUnixTimeSeconds(this JsonObject json, string name, DateTimeOffset? value)
+ {
+ var jsonValue = value.HasValue ? JsonValue.Create(value.Value.ToUnixTimeSeconds()) : null;
+ json.SetProperty(name, jsonValue);
+ }
+
+ ///
+ /// Retrieves an array of strings from a based on a specified property name.
+ /// This method supports both single string values and arrays of strings.
+ ///
+ /// The from which to retrieve the array of strings.
+ /// The property name to retrieve the values from.
+ /// An enumerable of strings if the property exists; otherwise, an empty enumerable.
+ ///
+ /// This method is useful for JWT claims or other JSON structures where a property may contain either
+ /// a single string value or an array of strings.
+ ///
+ public static IEnumerable GetArrayOfStrings(this JsonObject json, string name)
+ {
+ if (!json.TryGetPropertyValue(name, out var jsonNode))
+ yield break;
+
+ switch (jsonNode)
+ {
+ case null:
+ break;
+
+ case JsonValue value:
+ yield return value.GetValue();
+ break;
+
+ case JsonArray array:
+ foreach (var element in array)
+ if (element != null)
+ yield return element.GetValue();
+ break;
+ }
+ }
+
+ ///
+ /// Sets a property in a with a value that can be either a single string or an array of strings,
+ /// depending on the number of items in the provided enumerable.
+ ///
+ /// The to modify.
+ /// The name of the property to set.
+ /// The enumerable of string values to set as the property's value.
+ ///
+ /// This method is versatile for JWT or JSON handling where a property may accept both single and multiple values.
+ ///
+ public static void SetArrayOrString(this JsonObject json, string name, IEnumerable values)
+ {
+ json.SetProperty(name, values.ToJsonNode());
+ }
+
+ ///
+ /// Converts a collection of strings to a JSON node, which will be either a single JSON value if there's only one string,
+ /// or a JSON array if there are multiple strings.
+ ///
+ /// The collection of strings to convert.
+ /// A representing either a single value or an array of strings, or null if the collection is empty.
+ private static JsonNode? ToJsonNode(this IEnumerable values)
+ {
+ using var enumerator = values.GetEnumerator();
+
+ if (!enumerator.MoveNext())
+ return null;
+
+ var firstValue = enumerator.Current;
+
+ if (!enumerator.MoveNext())
+ return JsonValue.Create(firstValue);
+
+ var array = new JsonArray { firstValue };
+
+ do array.Add(enumerator.Current);
+ while (enumerator.MoveNext());
+
+ return array;
+ }
+
+ ///
+ /// Retrieves a collection of strings from a space-separated string stored in a specified property of a .
+ ///
+ /// The from which to retrieve the space-separated strings.
+ /// The name of the property containing the space-separated string.
+ /// An enumerable of strings if the property exists and contains values; otherwise, an empty enumerable.
+ ///
+ /// This method simplifies extracting multiple values from a single string property, common in JWT and OAuth scenarios.
+ ///
+ public static IEnumerable GetSpaceSeparatedStrings(this JsonObject json, string name)
+ {
+ var values = json.GetProperty(name);
+ return values.HasValue()
+ ? values.Split(' ', StringSplitOptions.RemoveEmptyEntries)
+ : Enumerable.Empty();
+ }
+
+ ///
+ /// Sets a property in a with a value represented as a space-separated string from an enumerable of strings.
+ ///
+ /// The to modify.
+ /// The name of the property to set.
+ /// The enumerable of string values to join into a space-separated string.
+ /// The modified .
+ ///
+ /// This method is useful for setting JWT claims or other JSON properties that accept a list of values as a single space-separated string.
+ ///
+ public static void SetSpaceSeparatedStrings(this JsonObject json, string name, IEnumerable value)
+ {
+ json.SetProperty(name, string.Join(' ', value));
+ }
+
+ ///
+ /// A static representing a null value in JSON.
+ /// This is used as a default value when a null JSON node needs to be represented as a .
+ ///
+ private static readonly JsonElement NullJsonElement = "null".ToJsonElement();
+
+ ///
+ /// Converts a JsonNode to a JsonElement.
+ ///
+ /// The JsonNode to convert.
+ /// The converted JsonElement.
+ public static JsonElement ToJsonElement(this JsonNode? jsonNode)
+ {
+ return jsonNode == null ? NullJsonElement : jsonNode.ToJsonString().ToJsonElement();
+ }
+
+ ///
+ /// Converts a JSON string to a .
+ ///
+ /// The JSON string to convert.
+ /// A representing the parsed JSON structure.
+ ///
+ /// Thrown when the JSON string is malformed and cannot be parsed.
+ ///
+ ///
+ /// This method is useful for converting a JSON string into a ,
+ /// allowing for easy manipulation and traversal of the JSON structure.
+ ///
+ private static JsonElement ToJsonElement(this string jsonString)
+ => JsonDocument.Parse(jsonString).RootElement;
+
+ ///
+ /// Converts a JsonElement to a JsonNode, allowing for more dynamic manipulation of the JSON structure.
+ ///
+ /// The JsonElement to convert.
+ /// The converted JsonNode.
+ ///
+ /// This method is useful when you need to convert from a structured JsonElement to a more flexible JsonNode.
+ ///
+ public static JsonNode? ToJsonNode(this JsonElement jsonElement)
+ => JsonNode.Parse(jsonElement.GetRawText());
+
+}
diff --git a/Abblix.Jwt/JsonWebTokenHeader.cs b/Abblix.Jwt/JsonWebTokenHeader.cs
new file mode 100644
index 00000000..4434c1b3
--- /dev/null
+++ b/Abblix.Jwt/JsonWebTokenHeader.cs
@@ -0,0 +1,78 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Text.Json.Nodes;
+
+namespace Abblix.Jwt;
+
+///
+/// Represents the header part of a JSON Web Token (JWT), containing metadata about the token
+/// such as the type and the algorithm used for signing.
+///
+///
+/// The JWT header typically specifies the cryptographic operations applied to the JWT
+/// and can also include additional properties defined or required by the application.
+///
+public class JsonWebTokenHeader
+{
+ ///
+ /// Initializes a new instance of the class with the specified JSON object.
+ ///
+ /// The representing the JWT header.
+ public JsonWebTokenHeader(JsonObject json)
+ {
+ Json = json;
+ }
+
+ ///
+ /// The underlying JSON object representing the JWT header.
+ ///
+ public JsonObject Json { get; }
+
+
+ ///
+ /// Gets or sets the type of the JWT, typically "JWT" or a similar identifier.
+ /// This field is optional and used to declare the media type of the JWT.
+ ///
+ ///
+ /// The 'typ' parameter is recommended when the JWT is embedded in places not inherently
+ /// carrying this information, helping recipients process the JWT type accordingly.
+ ///
+ public string? Type
+ {
+ get => Json.GetProperty(JwtClaimTypes.Type);
+ set => Json.SetProperty(JwtClaimTypes.Type, value);
+ }
+
+ ///
+ /// Gets or sets the algorithm used to sign the JWT, indicating how the token is secured.
+ ///
+ ///
+ /// The 'alg' parameter identifies the cryptographic algorithm used to secure the JWT.
+ /// Common algorithms include HS256, RS256, and ES256. It is crucial for verifying the JWT's integrity.
+ ///
+ public string? Algorithm
+ {
+ get => Json.GetProperty(JwtClaimTypes.Algorithm);
+ set => Json.SetProperty(JwtClaimTypes.Algorithm, value);
+ }
+}
diff --git a/Abblix.Jwt/JsonWebTokenPayload.cs b/Abblix.Jwt/JsonWebTokenPayload.cs
new file mode 100644
index 00000000..c556cfb9
--- /dev/null
+++ b/Abblix.Jwt/JsonWebTokenPayload.cs
@@ -0,0 +1,204 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Text.Json.Nodes;
+
+namespace Abblix.Jwt;
+
+///
+/// Represents the payload part of a JSON Web Token (JWT), containing the claims or statements about the subject.
+///
+///
+/// The JWT payload is a JSON object that contains the claims transmitted by the token. Standard claims
+/// such as issuer, subject, expiration time, and more can be included, as well as additional claims as needed.
+/// This class provides a convenient way to work with the payload, allowing for easy access and modification of claims.
+///
+public class JsonWebTokenPayload
+{
+ ///
+ /// Initializes a new instance of the class with the specified JSON object.
+ ///
+ /// The representing the JWT payload.
+ public JsonWebTokenPayload(JsonObject json)
+ {
+ Json = json;
+ }
+
+ ///
+ /// The underlying JSON object representing the JWT payload.
+ ///
+ public JsonObject Json { get; }
+
+ ///
+ /// Indexer to get or set claim values in the payload using the claim name.
+ ///
+ /// The name of the claim.
+ /// The value of the claim if it exists; otherwise, null.
+ public JsonNode? this[string name] {
+ get => Json[name];
+ set => Json.SetProperty(name, value);
+ }
+
+ ///
+ /// The unique identifier of the JWT.
+ ///
+ public string? JwtId
+ {
+ get => Json.GetProperty(JwtClaimTypes.JwtId);
+ set => Json.SetProperty(JwtClaimTypes.JwtId, value);
+ }
+
+ ///
+ /// The time at which the JWT was issued, represented as a Unix timestamp.
+ ///
+ public DateTimeOffset? IssuedAt
+ {
+ get => Json.GetUnixTimeSeconds(JwtClaimTypes.IssuedAt);
+ set => Json.SetUnixTimeSeconds(JwtClaimTypes.IssuedAt, value);
+ }
+
+ ///
+ /// The time before which the JWT must not be accepted for processing, represented as a Unix timestamp.
+ ///
+ public DateTimeOffset? NotBefore
+ {
+ get => Json.GetUnixTimeSeconds(JwtClaimTypes.NotBefore);
+ set => Json.SetUnixTimeSeconds(JwtClaimTypes.NotBefore, value);
+ }
+
+ ///
+ /// The expiration time on or after which the JWT must not be accepted for processing, represented as a Unix timestamp.
+ ///
+ public DateTimeOffset? ExpiresAt
+ {
+ get => Json.GetUnixTimeSeconds(JwtClaimTypes.ExpiresAt);
+ set => Json.SetUnixTimeSeconds(JwtClaimTypes.ExpiresAt, value);
+ }
+
+ ///
+ /// The issuer of the JWT.
+ ///
+ public string? Issuer
+ {
+ get => Json.GetProperty(JwtClaimTypes.Issuer);
+ set => Json.SetProperty(JwtClaimTypes.Issuer, value);
+ }
+
+ ///
+ /// The intended audiences for the JWT.
+ ///
+ public IEnumerable Audiences
+ {
+ get => Json.GetArrayOfStrings(JwtClaimTypes.Audience);
+ set => Json.SetArrayOrString(JwtClaimTypes.Audience, value);
+ }
+
+ ///
+ /// Gets or sets the subject of the JWT.
+ /// The subject typically represents the principal that is the focus of the JWT, often a user identifier.
+ ///
+ ///
+ /// The 'sub' (subject) claim is a standard claim in JWTs used to uniquely identify the principal,
+ /// usually in the context of authentication or user identity. It is commonly a user ID or username.
+ ///
+ public string? Subject
+ {
+ get => Json.GetProperty(JwtClaimTypes.Subject);
+ set => Json.SetProperty(JwtClaimTypes.Subject, value);
+ }
+
+ ///
+ /// The session ID associated with the JWT, typically used to manage session state across applications.
+ ///
+ ///
+ /// The session ID can link the JWT to a specific session for the user, allowing for effective session management and security controls.
+ ///
+ public string? SessionId
+ {
+ get => Json.GetProperty(JwtClaimTypes.SessionId);
+ set => Json.SetProperty(JwtClaimTypes.SessionId, value);
+ }
+
+ ///
+ /// The client ID for which the JWT was issued, identifying the client application in OAuth 2.0 and OpenID Connect flows.
+ ///
+ ///
+ /// This property is crucial in scenarios where the JWT is used to convey or assert the identity of a client application to the authorization server or resource server.
+ ///
+ public string? ClientId
+ {
+ get => Json.GetProperty(JwtClaimTypes.ClientId);
+ set => Json.SetProperty(JwtClaimTypes.ClientId, value);
+ }
+
+ ///
+ /// The scope of access granted by the JWT.
+ /// Scope is typically a space-separated list of permissions or access levels and is not part of the standard JWT claims.
+ ///
+ ///
+ /// The 'scope' claim is often used in OAuth 2.0 and OpenID Connect contexts to specify the extent of access
+ /// granted by the token. Each value in the list represents a specific permission or access level granted to the token bearer.
+ /// This property ensures that the scope is represented appropriately as either a single value or an array of values.
+ ///
+ public IEnumerable Scope
+ {
+ get => Json.GetSpaceSeparatedStrings(JwtClaimTypes.Scope);
+ set => Json.SetSpaceSeparatedStrings(JwtClaimTypes.Scope, value);
+ }
+
+ ///
+ /// Identifies the identity provider that authenticated the end user, useful in federated identity scenarios.
+ ///
+ ///
+ /// This claim is particularly relevant in systems that support multiple identity providers,
+ /// helping to trace the origin of the authentication and ensuring that the JWT can be validated appropriately.
+ ///
+ public string? IdentityProvider
+ {
+ get => Json.GetProperty(JwtClaimTypes.IdentityProvider);
+ set => Json.SetProperty(JwtClaimTypes.IdentityProvider, value);
+ }
+
+ ///
+ /// Represents the time when the authentication occurred, facilitating checks against token freshness
+ /// and replay attacks.
+ ///
+ ///
+ /// Storing the authentication time is critical for applications requiring a high level of assurance
+ /// regarding the moment a user was authenticated, allowing for precise control over session validity
+ /// and user authentication status.
+ ///
+ public DateTimeOffset? AuthenticationTime
+ {
+ get => Json.GetUnixTimeSeconds(JwtClaimTypes.AuthenticationTime);
+ set => Json.SetUnixTimeSeconds(JwtClaimTypes.AuthenticationTime, value);
+ }
+
+ ///
+ /// A value used to associate a client session with an ID token, mitigating replay attacks.
+ ///
+ public string? Nonce
+ {
+ get => Json.GetProperty(JwtClaimTypes.Nonce);
+ set => Json.SetProperty(JwtClaimTypes.Nonce, value);
+ }
+}
diff --git a/Abblix.Jwt/JsonWebTokenValidator.cs b/Abblix.Jwt/JsonWebTokenValidator.cs
new file mode 100644
index 00000000..712e4763
--- /dev/null
+++ b/Abblix.Jwt/JsonWebTokenValidator.cs
@@ -0,0 +1,175 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using System.Text.Json.Nodes;
+using Abblix.Utils;
+using Microsoft.IdentityModel.Tokens;
+
+namespace Abblix.Jwt;
+
+///
+/// Represents a validator for JSON Web Tokens (JWTs) which validates a JWT against specified validation parameters.
+///
+public class JsonWebTokenValidator : IJsonWebTokenValidator
+{
+ ///
+ /// Provides a collection of signing algorithms supported by the validator. This includes all algorithms recognized
+ /// by the JwtSecurityTokenHandler for inbound tokens, as well as an option to accept tokens without a signature.
+ /// This allows for flexibility in validating JWTs with various security requirements.
+ ///
+ public IEnumerable SigningAlgValuesSupported => JsonWebTokenAlgorithms.SigningAlgValuesSupported;
+
+ ///
+ /// Asynchronously validates a JWT string against specified validation parameters.
+ ///
+ /// The JWT string to validate.
+ /// The parameters defining the validation rules and requirements.
+ /// A task representing the validation operation, with a result of JwtValidationResult indicating the validation outcome.
+ public Task ValidateAsync(string jwt, ValidationParameters parameters)
+ => Task.FromResult(Validate(jwt, parameters));
+
+ ///
+ /// Performs the actual validation of a JWT string based on the specified validation parameters.
+ ///
+ /// The JWT string to validate.
+ /// The validation parameters.
+ /// The result of the JWT validation process, either indicating success or detailing any validation errors.
+ private static JwtValidationResult Validate(string jwt, ValidationParameters parameters)
+ {
+ var tokenValidationParameters = new TokenValidationParameters
+ {
+ NameClaimType = JwtClaimTypes.Subject,
+
+ ValidateIssuer = parameters.Options.HasFlag(ValidationOptions.ValidateIssuer),
+ ValidateAudience = parameters.Options.HasFlag(ValidationOptions.ValidateAudience),
+ RequireSignedTokens = parameters.Options.HasFlag(ValidationOptions.RequireSignedTokens),
+ ValidateIssuerSigningKey = parameters.Options.HasFlag(ValidationOptions.ValidateIssuerSigningKey),
+ ValidateLifetime = parameters.Options.HasFlag(ValidationOptions.ValidateLifetime),
+ };
+
+ if (tokenValidationParameters.ValidateIssuer)
+ {
+ var validateIssuer = parameters.ValidateIssuer
+ .NotNull(nameof(parameters.ValidateIssuer));
+
+ tokenValidationParameters.IssuerValidator = (issuer, _, _) =>
+ validateIssuer(issuer).Result ? issuer : null;
+ }
+
+ if (tokenValidationParameters.ValidateAudience)
+ {
+ var validateAudience = parameters.ValidateAudience
+ .NotNull(nameof(parameters.ValidateAudience));
+
+ tokenValidationParameters.AudienceValidator = (audiences, _, _) =>
+ validateAudience(audiences).Result;
+ }
+
+ if (tokenValidationParameters.ValidateIssuerSigningKey)
+ {
+ var resolveIssuerSigningKeys = parameters.ResolveIssuerSigningKeys
+ .NotNull(nameof(parameters.ResolveIssuerSigningKeys));
+
+ tokenValidationParameters.IssuerSigningKeyResolver = (_, securityToken, keyId, _) =>
+ {
+ var signingKeys = resolveIssuerSigningKeys(securityToken.Issuer);
+
+ if (keyId.HasValue())
+ signingKeys = signingKeys.WhereAsync(key => key.KeyId == keyId);
+
+ return signingKeys.SelectAsync(key => key.ToSecurityKey()).ToListAsync().Result;
+ };
+ }
+
+ var resolveTokenDecryptionKeys = parameters.ResolveTokenDecryptionKeys;
+ if (resolveTokenDecryptionKeys != null)
+ tokenValidationParameters.TokenDecryptionKeyResolver = (_, securityToken, keyId, _) =>
+ {
+ var decryptionKeys = resolveTokenDecryptionKeys(securityToken.Issuer);
+
+ if (keyId.HasValue())
+ decryptionKeys = decryptionKeys.WhereAsync(key => key.KeyId == keyId);
+
+ return decryptionKeys.SelectAsync(key => key.ToSecurityKey()).ToListAsync().Result;
+ };
+
+ var handler = new JwtSecurityTokenHandler();
+ SecurityToken token;
+ try
+ {
+ handler.ValidateToken(jwt, tokenValidationParameters, out token);
+ }
+ catch (Exception ex)
+ {
+ return new JwtValidationError(JwtError.InvalidToken, ex.Message);
+ }
+
+ var jwToken = (JwtSecurityToken)token;
+
+ var result = new JsonWebToken
+ {
+ Header =
+ {
+ Type = jwToken.Header.Typ,
+ Algorithm = jwToken.Header.Alg,
+ },
+ Payload =
+ {
+ JwtId = jwToken.Id,
+ IssuedAt = jwToken.IssuedAt,
+ NotBefore = jwToken.ValidFrom,
+ ExpiresAt = jwToken.ValidTo,
+ Issuer = jwToken.Issuer,
+ Audiences = jwToken.Audiences,
+ }
+ };
+
+ foreach (var claim in jwToken.Claims.ExceptBy(JwtSecurityTokenHandlerConstants.ClaimTypesToExclude, claim => claim.Type))
+ {
+ result.Payload[claim.Type] = ToJsonNode(claim.ValueType, claim.Value);
+ }
+
+ return new ValidJsonWebToken(result);
+ }
+
+
+ ///
+ /// Creates a representation of a claim value based on its type.
+ ///
+ /// The type of the claim value.
+ /// The string representation of the claim value.
+ /// A representing the claim value.
+ private static JsonNode? ToJsonNode(string valueType, string value)
+ => valueType switch
+ {
+ JsonClaimValueTypes.Json => JsonNode.Parse(value).NotNull(nameof(value)),
+
+ ClaimValueTypes.Boolean => JsonValue.Create(bool.Parse(value)),
+ ClaimValueTypes.Integer => JsonValue.Create(long.Parse(value)),
+ ClaimValueTypes.Integer32 => JsonValue.Create(int.Parse(value)),
+ ClaimValueTypes.Integer64 => JsonValue.Create(long.Parse(value)),
+
+ _ => value,
+ };
+}
diff --git a/Abblix.Jwt/JwtClaimTypes.cs b/Abblix.Jwt/JwtClaimTypes.cs
new file mode 100644
index 00000000..39fdeed3
--- /dev/null
+++ b/Abblix.Jwt/JwtClaimTypes.cs
@@ -0,0 +1,163 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Provides constants for JWT claim types.
+///
+public static class JwtClaimTypes
+{
+ ///
+ /// The 'typ' claim represents the type of the JWT.
+ ///
+ public const string Type = "typ";
+
+ ///
+ /// The 'alg' (algorithm) claim identifies the cryptographic algorithm used to secure the JWT.
+ /// It is typically found in the JWT header.
+ ///
+ public const string Algorithm = "alg";
+
+ ///
+ /// The 'idp' claim represents the identity provider that authenticated the end user.
+ ///
+ public const string IdentityProvider = "idp";
+
+ ///
+ /// The 'events' claim represents the events associated with the authentication.
+ ///
+ public const string Events = "events";
+
+ ///
+ /// The 'scope' claim represents the scope of access requested.
+ ///
+ public const string Scope = "scope";
+
+ ///
+ /// The 'requested_claims' claim represents the specific claims requested by the client.
+ ///
+ public const string RequestedClaims = "requested_claims";
+
+ ///
+ /// The 'sub' (subject) claim identifies the principal that is the subject of the JWT.
+ /// Typically used to represent the user or entity the token is about.
+ ///
+ public const string Subject = IanaClaimTypes.Sub;
+
+ ///
+ /// The 'sid' (session ID) claim identifies the session to which the JWT is linked.
+ /// Useful for maintaining state between the client and the issuer.
+ ///
+ public const string SessionId = IanaClaimTypes.Sid;
+
+ ///
+ /// The 'iss' (issuer) claim identifies the principal that issued the JWT.
+ /// It is typically a URI identifying the issuer.
+ ///
+ public const string Issuer = IanaClaimTypes.Iss;
+
+ ///
+ /// The 'nonce' claim provides a string value used to associate a client session with an ID token.
+ ///
+ public const string Nonce = IanaClaimTypes.Nonce;
+
+ ///
+ /// The 'aud' (audience) claim identifies the recipients that the JWT is intended for.
+ ///
+ public const string Audience = IanaClaimTypes.Aud;
+
+ ///
+ /// The 'jti' (JWT ID) claim provides a unique identifier for the JWT.
+ ///
+ public const string JwtId = IanaClaimTypes.Jti;
+
+ ///
+ /// The 'auth_time' claim represents the time when the authentication occurred.
+ /// It is expressed as the number of seconds since Unix epoch.
+ ///
+ public const string AuthenticationTime = IanaClaimTypes.AuthTime;
+
+ ///
+ /// The 'client_id' claim represents the identifier for the client that requested the authentication.
+ /// Often used in OAuth 2.0 and OpenID Connect flows.
+ ///
+ public const string ClientId = IanaClaimTypes.ClientId;
+
+ ///
+ /// The 'acr' (Authentication Context Class Reference) claim provides the reference values for the authentication context class.
+ ///
+ public const string AuthContextClassRef = IanaClaimTypes.Acr;
+
+ ///
+ /// The 'email' claim represents the user's email address.
+ ///
+ public const string Email = IanaClaimTypes.Email;
+
+ ///
+ /// The 'email_verified' claim is a boolean that is true if the user's email address has been verified; otherwise, it is false.
+ ///
+ public const string EmailVerified = IanaClaimTypes.EmailVerified;
+
+ ///
+ /// The 'phone_number' claim represents the user's phone number.
+ ///
+ public const string PhoneNumber = IanaClaimTypes.PhoneNumber;
+
+ ///
+ /// The 'phone_number_verified' claim is a boolean that is true if the user's phone number has been verified; otherwise, it is false.
+ ///
+ public const string PhoneNumberVerified = IanaClaimTypes.PhoneNumberVerified;
+
+ ///
+ /// The 'c_hash' claim is used for the code hash value in OpenID Connect.
+ /// It is a hash of the authorization code issued by the authorization server.
+ ///
+ public const string CodeHash = IanaClaimTypes.CHash;
+
+ ///
+ /// The 'at_hash' claim is used for the access token hash value in OpenID Connect.
+ /// It provides validation that the access token is tied to the identity token.
+ ///
+ public const string AccessTokenHash = IanaClaimTypes.AtHash;
+
+ ///
+ /// The 'iat' (issued at) claim identifies the time at which the JWT was issued.
+ /// It is expressed as the number of seconds since the Unix epoch.
+ /// This claim can be used to determine the age of the JWT.
+ ///
+ public const string IssuedAt = IanaClaimTypes.Iat;
+
+ ///
+ /// The 'nbf' (not before) claim identifies the time before which the JWT must not be accepted for processing.
+ /// It is expressed as the number of seconds since the Unix epoch.
+ /// This claim is used to define the earliest time at which the JWT is considered valid.
+ ///
+ public const string NotBefore = IanaClaimTypes.Nbf;
+
+ ///
+ /// The 'exp' (expiration time) claim identifies the expiration time on or after which the JWT must not be accepted for processing.
+ /// It is expressed as the number of seconds since the Unix epoch.
+ /// This claim is used to define the maximum lifespan of the JWT.
+ ///
+ public const string ExpiresAt = IanaClaimTypes.Exp;
+}
diff --git a/Abblix.Jwt/JwtError.cs b/Abblix.Jwt/JwtError.cs
new file mode 100644
index 00000000..24c15989
--- /dev/null
+++ b/Abblix.Jwt/JwtError.cs
@@ -0,0 +1,47 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Enumerates the different types of JWT-related errors.
+///
+public enum JwtError
+{
+ ///
+ /// Indicates that the token is invalid.
+ /// This can be due to various reasons such as incorrect format, signature issues, or payload inconsistencies.
+ ///
+ InvalidToken,
+
+ ///
+ /// Indicates that the token has already been used.
+ /// This error is typically encountered in scenarios where tokens are meant for single use, such as one-time authorization tokens.
+ ///
+ TokenAlreadyUsed,
+
+ ///
+ /// Indicates that the token has been revoked.
+ /// A revoked token is no longer valid for use, typically due to security reasons or changes in the access rights of the user.
+ ///
+ TokenRevoked,
+}
diff --git a/Abblix.Jwt/JwtSecurityTokenHandlerConstants.cs b/Abblix.Jwt/JwtSecurityTokenHandlerConstants.cs
new file mode 100644
index 00000000..dcc9f79f
--- /dev/null
+++ b/Abblix.Jwt/JwtSecurityTokenHandlerConstants.cs
@@ -0,0 +1,53 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Defines constants used with JwtSecurityTokenHandler, particularly for specifying claim types
+/// that should be excluded during certain operations.
+///
+internal static class JwtSecurityTokenHandlerConstants
+{
+ ///
+ /// An array of claim types that are often excluded from JWT token processing.
+ /// These claims are typically handled specially by JWT security token handlers
+ /// due to their significance in the JWT standard and security implications.
+ ///
+ public static readonly string[] ClaimTypesToExclude = {
+
+ // Issuer claim, identifies the principal that issued the JWT.
+ IanaClaimTypes.Iss,
+
+ // Audience claim, identifies the recipients that the JWT is intended for.
+ IanaClaimTypes.Aud,
+
+ // Expiration time claim, specifies the expiration time on or after which the JWT must not be accepted.
+ IanaClaimTypes.Exp,
+
+ // Not before claim, specifies the time before which the JWT must not be accepted.
+ IanaClaimTypes.Nbf,
+
+ // Issued at claim, indicates the time at which the JWT was issued.
+ IanaClaimTypes.Iat,
+ };
+}
diff --git a/Abblix.Jwt/JwtValidationError.cs b/Abblix.Jwt/JwtValidationError.cs
new file mode 100644
index 00000000..36effd85
--- /dev/null
+++ b/Abblix.Jwt/JwtValidationError.cs
@@ -0,0 +1,32 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Represents an error encountered during the validation of a JSON Web Token (JWT).
+/// This record extends the indicating a validation failure.
+///
+/// The specific type of JWT error encountered.
+/// A description of the error providing details about the validation failure.
+public record JwtValidationError(JwtError Error, string ErrorDescription)
+ : JwtValidationResult;
diff --git a/Abblix.Jwt/JwtValidationResult.cs b/Abblix.Jwt/JwtValidationResult.cs
new file mode 100644
index 00000000..7aa09e03
--- /dev/null
+++ b/Abblix.Jwt/JwtValidationResult.cs
@@ -0,0 +1,30 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Serves as the base record for representing the outcome of a JSON Web Token (JWT) validation process.
+/// This abstract record is intended to be inherited by more specific result types that indicate either
+/// successful validation or various types of validation errors.
+///
+public abstract record JwtValidationResult;
diff --git a/Abblix.Jwt/PublicKeyUsages.cs b/Abblix.Jwt/PublicKeyUsages.cs
new file mode 100644
index 00000000..87a2025a
--- /dev/null
+++ b/Abblix.Jwt/PublicKeyUsages.cs
@@ -0,0 +1,41 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Provides constants for specifying the intended usage of a public key.
+/// This class defines different types of public key usages for cryptographic operations,
+/// typically used in JSON Web Key (JWK) specifications and related contexts.
+///
+public static class PublicKeyUsages
+{
+ ///
+ /// Indicates that the public key is intended for use in digital signature operations.
+ ///
+ public const string Signature = "sig";
+
+ ///
+ /// Indicates that the public key is intended for use in encryption operations.
+ ///
+ public const string Encryption = "enc";
+}
diff --git a/Abblix.Jwt/ServiceCollectionExtensions.cs b/Abblix.Jwt/ServiceCollectionExtensions.cs
new file mode 100644
index 00000000..5c9798f3
--- /dev/null
+++ b/Abblix.Jwt/ServiceCollectionExtensions.cs
@@ -0,0 +1,57 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Abblix.Jwt;
+
+///
+/// Provides extension methods for to register JwT-related services within the application.
+///
+public static class ServiceCollectionExtensions
+{
+ ///
+ /// Registers services for creating and validating JSON Web Tokens (JWTs) within the application.
+ ///
+ ///
+ /// This method adds services for JWT handling, enabling the application to generate and validate JWTs efficiently.
+ /// JWTs are an essential part of modern web application security, used for representing claims securely between
+ /// two parties.
+ ///
+ /// By registering these services, the application can:
+ /// - Create JWTs with , allowing for the generation of tokens that can securely
+ /// transmit information between parties.
+ /// - Validate JWTs with , ensuring that incoming tokens are valid and
+ /// have not been tampered with.
+ ///
+ /// This setup is crucial for implementing authentication and authorization mechanisms that rely on JWTs,
+ /// such as OAuth 2.0 and OpenID Connect.
+ ///
+ /// The to configure with JWT services.
+ /// The configured , enabling further chaining of service registrations.
+ public static IServiceCollection AddJsonWebTokens(this IServiceCollection services)
+ {
+ return services
+ .AddSingleton()
+ .AddSingleton();
+ }
+}
diff --git a/Abblix.Jwt/SigningAlgorithms.cs b/Abblix.Jwt/SigningAlgorithms.cs
new file mode 100644
index 00000000..04326e6f
--- /dev/null
+++ b/Abblix.Jwt/SigningAlgorithms.cs
@@ -0,0 +1,42 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Provides constants for various signing algorithms used in JWT and cryptographic operations.
+///
+public static class SigningAlgorithms
+{
+ ///
+ /// Represents the RS256 (RSA Signature with SHA-256) signing algorithm.
+ /// This algorithm is commonly used for creating JWT signatures using RSA keys with SHA-256 hashing.
+ ///
+ public const string RS256 = "RS256";
+
+ ///
+ /// Represents the "none" signing algorithm.
+ /// This value is used when no digital signature or MAC operation is performed on the JWT.
+ /// It is important to use this algorithm with caution as it implies that the JWT is unprotected.
+ ///
+ public const string None = "none";
+}
diff --git a/Abblix.Jwt/ValidJsonWebToken.cs b/Abblix.Jwt/ValidJsonWebToken.cs
new file mode 100644
index 00000000..3aa8660f
--- /dev/null
+++ b/Abblix.Jwt/ValidJsonWebToken.cs
@@ -0,0 +1,35 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Represents a successful JWT validation result, encapsulating a validated JsonWebToken.
+///
+/// The JsonWebToken instance that has been successfully validated.
+public record ValidJsonWebToken(JsonWebToken Token) : JwtValidationResult
+{
+ ///
+ /// Gets the successfully validated JsonWebToken.
+ ///
+ public JsonWebToken Token { get; } = Token;
+}
diff --git a/Abblix.Jwt/ValidationOptions.cs b/Abblix.Jwt/ValidationOptions.cs
new file mode 100644
index 00000000..403b9193
--- /dev/null
+++ b/Abblix.Jwt/ValidationOptions.cs
@@ -0,0 +1,68 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Enumeration for specifying various validation options for JWT tokens.
+/// These options can be combined using bitwise operations to create a customized set of validation rules.
+///
+[Flags]
+public enum ValidationOptions
+{
+ ///
+ /// Default validation options that include validating the issuer, audience, presence of a signature,
+ /// validation of the issuer's signing key, and the token's lifetime.
+ /// This is a common set of validations providing a standard level of security.
+ ///
+ Default = ValidateIssuer | ValidateAudience | RequireSignedTokens | ValidateIssuerSigningKey | ValidateLifetime,
+
+ ///
+ /// Validates the issuer of the JWT.
+ /// Ensures that the issuer claim (iss) matches a specified value, typically configured in the token validation parameters.
+ ///
+ ValidateIssuer = 1 << 0,
+
+ ///
+ /// Validates the audience of the JWT.
+ /// Ensures that the audience claim (aud) matches one of the specified values, typically configured in the token validation parameters.
+ ///
+ ValidateAudience = 1 << 1,
+
+ ///
+ /// Requires that the JWT has a valid signature.
+ /// This ensures that the token has not been tampered with and is from a trusted issuer.
+ ///
+ RequireSignedTokens = 1 << 2,
+
+ ///
+ /// Validates the signing key of the issuer.
+ /// Ensures that the key used to sign the JWT is valid and is authorized by the issuer.
+ ///
+ ValidateIssuerSigningKey = 1 << 3,
+
+ ///
+ /// Validates the lifetime of the JWT.
+ /// Ensures that the token is within its valid time frame of use (not expired and not yet valid if the 'nbf' claim is specified).
+ ///
+ ValidateLifetime = 1 << 4,
+}
diff --git a/Abblix.Jwt/ValidationParameters.cs b/Abblix.Jwt/ValidationParameters.cs
new file mode 100644
index 00000000..777c864d
--- /dev/null
+++ b/Abblix.Jwt/ValidationParameters.cs
@@ -0,0 +1,84 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+namespace Abblix.Jwt;
+
+///
+/// Represents the parameters used for validating a JSON Web Token (JWT).
+///
+public record ValidationParameters
+{
+ ///
+ /// Gets or sets the validation options.
+ ///
+ public ValidationOptions Options { get; init; } = ValidationOptions.Default;
+
+ ///
+ /// Gets or sets the delegate for issuer validation.
+ ///
+ public ValidateIssuersDelegate? ValidateIssuer { get; set; }
+
+ ///
+ /// Gets or sets the delegate for audience validation.
+ ///
+ public ValidateAudienceDelegate? ValidateAudience { get; set; }
+
+ ///
+ /// Gets or sets the delegate for resolving issuer signing keys.
+ ///
+ public ResolveIssuerSigningKeysDelegate? ResolveIssuerSigningKeys { get; set; }
+
+ ///
+ /// Gets or sets the delegate for resolving token decryption keys.
+ ///
+ public ResolveTokenDecryptionKeysDelegate? ResolveTokenDecryptionKeys { get; set; }
+
+ ///
+ /// Represents a delegate that asynchronously resolves a collection of JSON Web Keys (JWKs) for a given issuer,
+ /// used for validating the signing of a JWT.
+ ///
+ /// The issuer for which to resolve the signing keys.
+ /// An asynchronous enumerable of JSON Web Keys.
+ public delegate IAsyncEnumerable ResolveIssuerSigningKeysDelegate(string issuer);
+
+ ///
+ /// Represents a delegate that asynchronously resolves a collection of JSON Web Keys (JWKs) for a given issuer,
+ /// used for token decryption.
+ ///
+ /// The issuer for which to resolve the decryption keys.
+ /// An asynchronous enumerable of JSON Web Keys.
+ public delegate IAsyncEnumerable ResolveTokenDecryptionKeysDelegate(string issuer);
+
+ ///
+ /// Represents a delegate that validates a set of audiences against a specific criterion.
+ ///
+ /// The audiences to validate.
+ /// A task that represents the asynchronous validation operation. The task result contains the validation outcome.
+ public delegate Task ValidateAudienceDelegate(IEnumerable audiences);
+
+ ///
+ /// Represents a delegate that validates an issuer against a specific criterion.
+ ///
+ /// The issuer to validate.
+ /// A task that represents the asynchronous validation operation. The task result contains the validation outcome.
+ public delegate Task ValidateIssuersDelegate(string issuer);
+};
diff --git a/Abblix.Oidc.Server.Mvc/Abblix.Oidc.Server.Mvc.csproj b/Abblix.Oidc.Server.Mvc/Abblix.Oidc.Server.Mvc.csproj
new file mode 100644
index 00000000..ba8ae871
--- /dev/null
+++ b/Abblix.Oidc.Server.Mvc/Abblix.Oidc.Server.Mvc.csproj
@@ -0,0 +1,47 @@
+
+
+
+ net6.0;net7.0;net8.0
+ enable
+ enable
+ Linux
+ net6.0;net7.0;net8.0
+ true
+ true
+ Abblix.OIDC.Server.MVC
+ Abblix OIDC Server Model-View-Controller
+ The package integrates Abblix's OIDC Server capabilities with ASP.NET MVC, offering seamless support for OpenID Connect in MVC applications. It enables fast and easy implementation of secure OpenID Connect protocols, ensuring security features are accessible within the MVC framework.
+ Abblix LLP
+ https://www.abblix.com/abblix-oidc-server
+ https://github.com/Abblix/Oidc.Server
+ git
+ Abblix OIDC OpenID OpenID-Connect Authentication Authorization Security Identity OAuth OAuth2 SSO Single-Sign-On ASP.NET IdentityServer Federation Claims WebApi
+ README.md
+ LICENSE.md
+ Copyright (c) 2024 Abblix LLP. All rights reserved.
+ For detailed release notes, visit: https://github.com/Abblix/Oidc.Server/releases
+ Abblix.png
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Abblix.Oidc.Server.Mvc/ActionResults/ActionResultDecorator.cs b/Abblix.Oidc.Server.Mvc/ActionResults/ActionResultDecorator.cs
new file mode 100644
index 00000000..a6be3afa
--- /dev/null
+++ b/Abblix.Oidc.Server.Mvc/ActionResults/ActionResultDecorator.cs
@@ -0,0 +1,73 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Abblix.Oidc.Server.Mvc.ActionResults;
+
+///
+/// Decorates an by applying additional actions to the HTTP response.
+///
+internal class ActionResultDecorator : ActionResult
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The inner to be executed.
+ /// The action to apply to the .
+ public ActionResultDecorator(
+ ActionResult innerResult,
+ Action applyToResponseAction)
+ {
+ _innerResult = innerResult;
+ _applyToResponseAction = applyToResponseAction;
+ }
+
+ private readonly ActionResult _innerResult;
+ private readonly Action _applyToResponseAction;
+
+ ///
+ /// Executes the result operation of the action method asynchronously.
+ /// This method is called by MVC to process the result of an action method.
+ /// The method applies additional actions to the response and then executes the inner result.
+ ///
+ /// The context in which the result is executed.
+ /// A task that represents the asynchronous execute operation.
+ public override Task ExecuteResultAsync(ActionContext context)
+ {
+ _applyToResponseAction(context.HttpContext.Response);
+ return _innerResult.ExecuteResultAsync(context);
+ }
+
+ ///
+ /// Executes the result operation of the action method synchronously.
+ /// This method is called by MVC to process the result of an action method.
+ /// The method applies additional actions to the response and then executes the inner result.
+ ///
+ /// The context in which the result is executed.
+ public override void ExecuteResult(ActionContext context)
+ {
+ _applyToResponseAction(context.HttpContext.Response);
+ _innerResult.ExecuteResult(context);
+ }
+}
diff --git a/Abblix.Oidc.Server.Mvc/ActionResults/ActionResultExtensions.cs b/Abblix.Oidc.Server.Mvc/ActionResults/ActionResultExtensions.cs
new file mode 100644
index 00000000..db2b5422
--- /dev/null
+++ b/Abblix.Oidc.Server.Mvc/ActionResults/ActionResultExtensions.cs
@@ -0,0 +1,50 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using Microsoft.AspNetCore.Mvc;
+using CookieOptions = Microsoft.AspNetCore.Http.CookieOptions;
+
+namespace Abblix.Oidc.Server.Mvc.ActionResults;
+
+public static class ActionResultExtensions
+{
+ ///
+ /// Decorates an to append a cookie to the response.
+ ///
+ /// The to decorate.
+ /// The name of the cookie to append.
+ /// The value of the cookie.
+ /// The to configure the cookie.
+ /// A decorated that appends the specified cookie.
+ public static ActionResult WithAppendCookie(this ActionResult innerResult, string name, string value, CookieOptions options)
+ => new ActionResultDecorator(innerResult, response => response.Cookies.Append(name, value, options));
+
+ ///
+ /// Decorates an to delete a cookie from the response.
+ ///
+ /// The to decorate.
+ /// The name of the cookie to delete.
+ /// The to configure the deletion of the cookie.
+ /// A decorated that deletes the specified cookie.
+ public static ActionResult WithDeleteCookie(this ActionResult innerResult, string name, CookieOptions options)
+ => new ActionResultDecorator(innerResult, response => response.Cookies.Delete(name, options));
+}
diff --git a/Abblix.Oidc.Server.Mvc/ActionResults/CookieOptionsExtensions.cs b/Abblix.Oidc.Server.Mvc/ActionResults/CookieOptionsExtensions.cs
new file mode 100644
index 00000000..6e07b6f4
--- /dev/null
+++ b/Abblix.Oidc.Server.Mvc/ActionResults/CookieOptionsExtensions.cs
@@ -0,0 +1,57 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using Abblix.Utils;
+using Microsoft.AspNetCore.Http;
+
+namespace Abblix.Oidc.Server.Mvc.ActionResults;
+public static class CookieOptionsExtensions
+{
+ ///
+ /// Converts custom to ASP.NET Core's .
+ ///
+ /// The custom cookie options to convert.
+ /// The converted suitable for ASP.NET Core.
+ public static CookieOptions ConvertOptions(this Common.CookieOptions options) => new()
+ {
+ Domain = options.Domain,
+ Path = options.Path,
+ Secure = options.Secure,
+ IsEssential = options.IsEssential,
+ HttpOnly = options.HttpOnly,
+ SameSite = options.SameSite.ConvertSameSite(),
+ Expires = options.Expires,
+ MaxAge = options.MaxAge,
+ };
+
+ ///
+ /// Converts a string representation of the SameSite attribute to its equivalent.
+ ///
+ /// The string representation of the SameSite attribute.
+ /// The value corresponding to the input string.
+ private static SameSiteMode ConvertSameSite(this string? sameSite)
+ {
+ return sameSite.HasValue()
+ ? Enum.Parse(sameSite, true)
+ : SameSiteMode.Unspecified;
+ }
+}
diff --git a/Abblix.Oidc.Server.Mvc/ActionResults/FrontChannelLogoutResult.cs b/Abblix.Oidc.Server.Mvc/ActionResults/FrontChannelLogoutResult.cs
new file mode 100644
index 00000000..21cf06a2
--- /dev/null
+++ b/Abblix.Oidc.Server.Mvc/ActionResults/FrontChannelLogoutResult.cs
@@ -0,0 +1,96 @@
+// Abblix OIDC Server Library
+// Copyright (c) Abblix LLP. All rights reserved.
+//
+// DISCLAIMER: This software is provided 'as-is', without any express or implied
+// warranty. Use at your own risk. Abblix LLP is not liable for any damages
+// arising from the use of this software.
+//
+// LICENSE RESTRICTIONS: This code may not be modified, copied, or redistributed
+// in any form outside of the official GitHub repository at:
+// https://github.com/Abblix/OIDC.Server. All development and modifications
+// must occur within the official repository and are managed solely by Abblix LLP.
+//
+// Unauthorized use, modification, or distribution of this software is strictly
+// prohibited and may be subject to legal action.
+//
+// For full licensing terms, please visit:
+//
+// https://oidc.abblix.com/license
+//
+// CONTACT: For license inquiries or permissions, contact Abblix LLP at
+// info@abblix.com
+
+using System.Web;
+using System.Xml;
+
+namespace Abblix.Oidc.Server.Mvc.ActionResults;
+
+///
+/// Generates an HTML response that handles front-channel logout by embedding iframes for each logout URI.
+///
+///
+/// This class is responsible for creating an HTML page containing iframes for each URI in the front-channel logout process.
+/// The iframes are used to send logout requests to all clients participating in the user's session.
+/// The 'barrierSync' function ensures that the user is redirected to the post-logout URI only after all iframes have loaded,
+/// indicating that logout requests have been sent to all clients.
+///
+public class FrontChannelLogoutResult : GeneratedHtmlResult
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The URI to redirect to after the front-channel logout process is complete.
+ /// A list of URIs for the iframes to be used in the front-channel logout process.
+ public FrontChannelLogoutResult(
+ Uri? postLogOutUri,
+ IList frontChannelLogoutUris)
+ {
+ _postLogOutUri = postLogOutUri;
+ _frontChannelLogoutUris = frontChannelLogoutUris;
+ }
+
+ private readonly IList _frontChannelLogoutUris;
+ private readonly Uri? _postLogOutUri;
+
+ ///
+ /// Asynchronously writes the HTML content that includes iframes for each front-channel logout URI and
+ /// a script to redirect to the post-logout URI.
+ ///
+ /// The XML writer used to write the HTML content.
+ protected override async Task WriteHtmlAsync(XmlWriter writer)
+ {
+ await writer.WriteDocTypeAsync("html", null, null, null);
+
+ writer.WriteStartElement("html");
+ writer.WriteStartElement("head");
+
+ writer.WriteElementString("style", "iframe { display: none; width: 0; height: 0; }");
+ writer.WriteStartElement("script");
+ await writer.WriteStringAsync($"var count = {_frontChannelLogoutUris.Count}; ");
+
+ if (_postLogOutUri != null)
+ {
+ var postLogOutUri = HttpUtility.JavaScriptStringEncode(_postLogOutUri.OriginalString, true);
+
+ await writer.WriteStringAsync("function barrierSync() { ");
+ await writer.WriteStringAsync("if (--count === 0) ");
+ await writer.WriteStringAsync($"window.location.replace({postLogOutUri}); ");
+ await writer.WriteStringAsync("}");
+ }
+
+ await writer.WriteEndElementAsync(); //
+ await writer.WriteEndElementAsync(); //
+
+ writer.WriteStartElement("body");
+ foreach (var uri in _frontChannelLogoutUris)
+ {
+ writer.WriteStartElement("iframe");
+ writer.WriteAttributeString("onload", "barrierSync()");
+ writer.WriteAttributeString("src", uri.OriginalString);
+ await writer.WriteEndElementAsync(); //
+ }
+
+ await writer.WriteEndElementAsync(); //