DNV.OAuth.Web.Extensions 1.17.1

dotnet add package DNV.OAuth.Web.Extensions --version 1.17.1
                    
NuGet\Install-Package DNV.OAuth.Web.Extensions -Version 1.17.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="DNV.OAuth.Web.Extensions" Version="1.17.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="DNV.OAuth.Web.Extensions" Version="1.17.1" />
                    
Directory.Packages.props
<PackageReference Include="DNV.OAuth.Web.Extensions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add DNV.OAuth.Web.Extensions --version 1.17.1
                    
#r "nuget: DNV.OAuth.Web.Extensions, 1.17.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package DNV.OAuth.Web.Extensions@1.17.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=DNV.OAuth.Web.Extensions&version=1.17.1
                    
Install as a Cake Addin
#tool nuget:?package=DNV.OAuth.Web.Extensions&version=1.17.1
                    
Install as a Cake Tool

DNV.OAuth.Web.Extensions

DNV.OAuth.Web.Extensions helps ASP.NET Core applications add optional OAuth web behaviors on top of DNV.OAuth.Web, including API-friendly cookie responses, MFA challenges, path-based multitenancy, and Veracity policy validation.

Overview

This package extends the DNV.OAuth.Web.AddOidc and OidcOptions model. It includes:

  • Cookie redirect suppression for APIs.
  • MFA request helpers that add mfa_required=true to OIDC authorization requests.
  • Path-based tenant resolution and per-tenant cookie isolation.
  • Veracity policy validation during OIDC token validation.
  • Public policy validation interfaces for custom validation or violation handling.

Source repository: https://github.com/dnv-internal/SolutionPackage

Package registry: TODO: Confirm the NuGet feed or registry where this package is published.

When to use this

  • Use this when a DNV.OAuth.Web application needs one of the optional web authentication behaviors provided here.
  • Use this when API endpoints should return 401/403 instead of cookie-auth 302 redirects.
  • Use this when a web app needs path-based tenant cookie isolation or Veracity policy validation.

When not to use this

  • Do not use this without the base DNV.OAuth.Web OIDC setup.
  • Do not use path-based multitenancy as a replacement for authorization or tenant data isolation.
  • Do not use MFA helpers as proof of strong authentication unless the identity provider issues the expected mfaType claim.

Features

  • SuppressOAuthRedirectForApi for 401/403 API responses.
  • AddMfaSupport, ChallengeForMfaAsync, and SignedInWithMfa.
  • UseMultitenancy and AddMultitenantAuthentication.
  • AddPolicyValidation and PolicyValidationOptions.
  • IPolicyValidator and IPolicyViolationHandler extension points.
  • Targets net8.0 and net10.0.

Requirements

Requirement Version / value Notes
Runtime net8.0, net10.0 From DNV.OAuth.Web.Extensions.csproj.
Base package DNV.OAuth.Web This package extends AddOidc and OidcOptions.
Policy dependency DNV.Veracity.Services.Api.My Used by policy validation.
Host framework ASP.NET Core Uses cookie, OIDC, middleware, and authorization APIs.
Platform TODO Confirm supported operating systems.
Stability TODO Confirm package stability and support policy.
License TODO No repository license file was found.

Installation

dotnet add package DNV.OAuth.Web.Extensions

If your environment uses a private NuGet feed, configure that feed before running the command.

Quick start

Configure base OIDC with DNV.OAuth.Web, then add the extensions you need.

using DNV.OAuth.Web;
using DNV.OAuth.Web.Extensions.Cookie;
using DNV.OAuth.Web.Extensions.Mfa;
using DNV.OAuth.Web.Extensions.Policy;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddControllersWithViews();
builder.Services.AddDistributedMemoryCache();

var oidcOptions = new OidcOptions
{
    Authority = "https://login.veracity.com/tfp/<tenant>/b2c_1a_signinwithadfsidp/v2.0",
    ClientId = "<client-id>",
    ClientSecret = Environment.GetEnvironmentVariable("OAUTH_CLIENT_SECRET")!,
    Scopes = new[] { "api://example/user_impersonation", "offline_access" },
    ResponseType = OpenIdConnectResponseType.Code
};

oidcOptions.AddMfaSupport(request => request.Path.StartsWithSegments("/secure"));

builder.Services.AddOidc(oidcOptions)
    .AddPolicyValidation(options =>
    {
        options.VeracityPolicyApiConfigName = "VeracityMyPolicies";
        options.ServiceId = "<service-id>";
        options.PolicyValidationMode = PolicyValidationMode.All;
    });

builder.Services.SuppressOAuthRedirectForApi(request => request.Path.StartsWithSegments("/api"));

var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();

Expected result:

OIDC sign-in is configured, /secure challenges request MFA, policy validation runs after token validation, and /api redirects become 401/403 responses.

Use cases

Goal: Prevent API clients from receiving HTML login redirects.

Scenario: A web app has both MVC pages and /api endpoints protected by cookie authentication.

Prerequisites:

  • Cookie authentication configured through DNV.OAuth.Web.AddOidc or ASP.NET Core cookie authentication.

Code:

using DNV.OAuth.Web.Extensions.Cookie;

var builder = WebApplication.CreateBuilder(args);

builder.Services.SuppressOAuthRedirectForApi(
    request => request.Path.StartsWithSegments("/api"));

Expected result:

Unauthenticated /api requests receive 401. Forbidden /api requests receive 403.

Why this works: The extension wraps OnRedirectToLogin and OnRedirectToAccessDenied on CookieAuthenticationOptions.

Common mistakes:

  • Passing no predicate suppresses redirects for every request.
  • Suppression applies only when the response status is still 200 OK.

Related:

Use case: Request MFA for sensitive routes

Goal: Ask the identity provider for MFA only when the request requires it.

Scenario: A signed-in user accesses /secure and the application wants an MFA challenge when the session does not already show MFA.

Prerequisites:

  • OIDC configured with DNV.OAuth.Web.
  • Identity provider support for the mfa_required parameter and mfaType claim values used by this package.

Code:

using DNV.OAuth.Web;
using DNV.OAuth.Web.Extensions.Mfa;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDistributedMemoryCache();

var oidcOptions = new OidcOptions
{
    Authority = "https://login.veracity.com/tfp/<tenant>/b2c_1a_signinwithadfsidp/v2.0",
    ClientId = "<client-id>",
    ClientSecret = Environment.GetEnvironmentVariable("OAUTH_CLIENT_SECRET")!,
    Scopes = new[] { "api://example/user_impersonation" }
};

oidcOptions.AddMfaSupport(request => request.Path.StartsWithSegments("/secure"));
builder.Services.AddOidc(oidcOptions);

public sealed class SecureController : Controller
{
    public async Task<IActionResult> Index()
    {
        if (!HttpContext.SignedInWithMfa())
        {
            await HttpContext.ChallengeForMfaAsync("/secure");
            return new EmptyResult();
        }

        return Content("MFA session");
    }
}

Expected result:

OIDC redirects for /secure include mfa_required=true until the signed-in principal has an accepted mfaType claim.

Why this works: AddMfaSupport wraps OnRedirectToIdentityProvider; ChallengeForMfaAsync stores the MFA flag in AuthenticationProperties.

Common mistakes:

  • Calling ChallengeForMfaAsync with an empty redirect URL.
  • Assuming SignedInWithMfa is true for all MFA mechanisms; it checks mfaType=phone or mfaType=federatedIdp.

Related:

Use case: Isolate authentication cookies by tenant path

Goal: Use the first URL path segment as a tenant alias and isolate authentication cookies.

Scenario: The same app serves /tenant-a and /tenant-b, but a user session for one tenant should not be reused by the other tenant.

Prerequisites:

  • OIDC configured with DNV.OAuth.Web.
  • UseMultitenancy called before routing and authentication.

Code:

using DNV.OAuth.Web;
using DNV.OAuth.Web.Extensions.Multitenancy;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDistributedMemoryCache();

builder.Services.AddOidc(new OidcOptions
{
    Authority = "https://login.veracity.com/tfp/<tenant>/b2c_1a_signinwithadfsidp/v2.0",
    ClientId = "<client-id>",
    ClientSecret = Environment.GetEnvironmentVariable("OAUTH_CLIENT_SECRET")!,
    Scopes = new[] { "api://example/user_impersonation", "offline_access" }
}).AddMultitenantAuthentication();

var app = builder.Build();

app.UseMultitenancy(path => path.StartsWithSegments("/health"));
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();
app.Run();

Expected result:

Requests such as /tenant-a/orders run with PathBase=/tenant-a, and cookie names receive tenant-aware postfixes.

Why this works: TenantResolutionMiddleware moves the first path segment to PathBase, while multitenant cookie options append .Super or .Sub postfixes.

Common mistakes:

  • Calling UseMultitenancy after UseRouting or UseAuthentication.
  • Treating path tenant resolution as data authorization. Always validate tenant access in application logic.

Related:

Use case: Validate Veracity policies during sign-in

Goal: Require platform, service, or subscription policy validation as part of OIDC sign-in.

Scenario: A web app must ensure Veracity policies are accepted before the user is authorized.

Prerequisites:

  • DNV.Veracity.Services.Api.My configuration for the named policy API config.
  • A policy mode appropriate for the application.

Code:

using DNV.OAuth.Web;
using DNV.OAuth.Web.Extensions.Policy;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDistributedMemoryCache();

builder.Services.AddOidc(new OidcOptions
{
    Authority = "https://login.veracity.com/tfp/<tenant>/b2c_1a_signinwithadfsidp/v2.0",
    ClientId = "<client-id>",
    ClientSecret = Environment.GetEnvironmentVariable("OAUTH_CLIENT_SECRET")!,
    Scopes = new[] { "api://example/user_impersonation", "offline_access" }
}).AddPolicyValidation(options =>
{
    options.VeracityPolicyApiConfigName = "VeracityMyPolicies";
    options.ServiceId = "<service-id>";
    options.PolicyValidationMode = PolicyValidationMode.All;
    options.AuthorizationPolicyName = PolicyValidationOptions.VeracityDefaultPolicy;
    options.AddAsDefaultPolicy = true;
});

Expected result:

Successful validation adds the vplcvdt claim and the configured authorization policy requires that claim.

Why this works: AddPolicyValidation wraps the OIDC OnTokenValidated event and registers an authorization policy requiring vplcvdt.

Common mistakes:

  • Leaving PolicyValidationMode at the default value 0; validation fails because no mode is selected.
  • Omitting VeracityPolicyApiConfigName; AddPolicyValidation throws ArgumentNullException.
  • Omitting ServiceId when using modes that validate service policies.

Related:

Use case: Override policy violation handling

Goal: Customize how policy validation failures are handled.

Scenario: The default handler redirects to the URL returned by the policy API, but an application wants a 403 response.

Prerequisites:

  • A custom IPolicyViolationHandler registered before AddPolicyValidation.

Code:

using DNV.OAuth.Web.Extensions.Policy;
using DNV.Veracity.Services.Api.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IPolicyViolationHandler, ForbiddenPolicyViolationHandler>();

public sealed class ForbiddenPolicyViolationHandler : IPolicyViolationHandler
{
    public Task HandleTermsAndConditionsViolated<TOptions>(
        RemoteAuthenticationContext<TOptions> ctx,
        PolicyValidationResult validationResult)
        where TOptions : AuthenticationSchemeOptions
        => WriteForbidden(ctx);

    public Task HandleServiceSubscriptionViolated<TOptions>(
        RemoteAuthenticationContext<TOptions> ctx,
        PolicyValidationResult validationResult)
        where TOptions : AuthenticationSchemeOptions
        => WriteForbidden(ctx);

    public Task HandleCompanyAffiliationViolated<TOptions>(
        RemoteAuthenticationContext<TOptions> ctx,
        PolicyValidationResult validationResult)
        where TOptions : AuthenticationSchemeOptions
        => WriteForbidden(ctx);

    private static Task WriteForbidden<TOptions>(RemoteAuthenticationContext<TOptions> ctx)
        where TOptions : AuthenticationSchemeOptions
    {
        ctx.HandleResponse();
        ctx.Response.StatusCode = StatusCodes.Status403Forbidden;
        return ctx.Response.WriteAsync("Policy validation failed.");
    }
}

Expected result:

Policy violations return 403 with a custom message instead of using the default redirect behavior.

Why this works: The package registers default policy services with TryAddSingleton, so earlier registrations win.

Common mistakes:

  • Registering the custom handler after AddPolicyValidation.
  • Writing sensitive policy API details into the response.

Related:

Configuration

Option Type Default Required Description
SuppressOAuthRedirectForApi(apiPredicate) Func<HttpRequest,bool>? Suppress all when null No Selects requests that should receive 401/403 instead of redirects.
AddMfaSupport(mfaPredict) Func<HttpRequest,bool>? Uses challenge property when null No Selects requests that should add mfa_required=true.
UseMultitenancy(shouldSkip) Func<PathString,bool>? Do not skip No Skips tenant extraction for selected paths.
AddMultitenantAuthentication(configAction) Action<CookieAuthenticationOptions,HttpContext>? null No Customizes per-request cookie options.
PolicyValidationOptions.PolicyValidationMode PolicyValidationMode 0 Yes Selects platform/service/subscription checks.
PolicyValidationOptions.VeracityPolicyApiConfigName string? null Yes Name passed to AddMyPolicies.
PolicyValidationOptions.ServiceId string? null Some modes Service id for service policy validation.
PolicyValidationOptions.GetReturnUrl Func<HttpContext,string,string>? Builds absolute URL No Custom return URL builder.
PolicyValidationOptions.AuthorizationPolicyName string VeracityDefaultPolicy Yes Authorization policy requiring vplcvdt.
PolicyValidationOptions.AddAsDefaultPolicy bool true No Sets the policy as default.

API overview

API Purpose Typical use
SuppressOAuthRedirectForApi Converts cookie redirects to 401/403. API endpoints in cookie-auth apps.
AddMfaSupport Adds MFA request behavior to OidcOptions. Sensitive routes or explicit MFA challenge.
ChallengeForMfaAsync Starts an MFA challenge. Controller/action requiring MFA.
SignedInWithMfa Checks the mfaType claim. Gate sensitive actions after sign-in.
UseMultitenancy Resolves first path segment as tenant alias. Path-based tenant routing.
AddMultitenantAuthentication Configures tenant-aware cookies and OIDC callback handling. Tenant-isolated authentication sessions.
AddPolicyValidation Adds Veracity policy checks and an authorization policy. Sign-in policy enforcement.
IPolicyValidator Policy validation abstraction. Replace validation behavior.
IPolicyViolationHandler Policy violation abstraction. Replace redirect/error behavior.
PolicyValidationMode Flags for policy validation. Select platform, service, and subscription checks.

Error handling and troubleshooting

Symptom Likely cause Fix
API still receives 302 redirects Predicate did not match the API path. Check the apiPredicate passed to SuppressOAuthRedirectForApi.
MFA parameter is not sent Predicate returned false and no challenge property was set. Use AddMfaSupport with the right predicate or call ChallengeForMfaAsync.
Tenant path is not resolved Middleware order is wrong or shouldSkip matched. Call UseMultitenancy before routing/authentication and review skip rules.
HttpContext is not available. Tenant cookie options were created outside a request. Use multitenant cookie options only in request-aware paths.
Policy validation always fails PolicyValidationMode is 0 or required options are missing. Set a valid mode, API config name, and service id when required.

Observability and diagnostics

PolicyValidator logs Veracity policy API errors with ILogger<PolicyValidator>. Other extensions rely on ASP.NET Core authentication and middleware logging.

Performance considerations

  • Multitenancy creates cookie options per request through a custom IOptionsMonitor<CookieAuthenticationOptions>.
  • Policy validation calls the Veracity policy API during OIDC token validation.
  • Cookie suppression and MFA event wrappers add minimal per-request overhead.
  • TODO: Confirm trimming and native AOT support.

Security notes

  • Keep OIDC client secrets and Veracity API configuration secrets out of source control.
  • MFA helpers request MFA and inspect specific mfaType claim values; they do not replace server-side authorization checks.
  • Path-based tenant resolution isolates authentication cookies but does not enforce tenant data access. Validate tenant authorization in application code.
  • Policy validation may redirect users to URLs returned by the policy API. Validate configuration and avoid exposing sensitive details in custom handlers.
  • Authentication cookies and policy validation responses can reveal user state. Use HTTPS, secure cookies, and appropriate cache controls.
  • Vulnerability reporting: TODO: Confirm the security contact or SECURITY.md process for this repository.

Examples

Versioning and compatibility

The project targets net8.0 and net10.0. Package versioning is controlled by repository MSBuild properties and BUILD_VERSION.

TODO: Confirm semantic versioning policy, supported package versions, and breaking-change process.

Contributing

From the repository root:

dotnet test src/OAuth/OAuth.sln

TODO: Confirm contribution guidelines and code review requirements.

Support

Package metadata lists author Albert Yang <albert.yang@dnv.com>.

TODO: Confirm the owning team, support contact, and issue reporting process.

License

TODO: Confirm the package license and add or link the repository license file.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.17.1 59,563 2/27/2026
1.17.1-preview.1789020820 57 9/10/2026
1.17.1-preview.1785316862 77 7/29/2026
1.17.0 150 2/26/2026
1.16.0 148 2/26/2026
1.15.1 1,771 2/3/2026
1.15.1-preview.1772090606 94 2/26/2026
1.15.1-preview.1771954705 87 2/24/2026
1.15.1-preview.1771953954 85 2/24/2026
1.15.0 342 4/30/2025
1.14.7 5,925 4/16/2025
1.14.5 336 3/12/2025
1.14.4 131,616 11/27/2024
1.14.3 288 11/27/2024
1.14.2 5,056 10/9/2024
1.14.1 278 9/27/2024
1.14.0 265 9/26/2024
1.13.0 24,450 8/9/2024
Loading failed