Substantive.AspNetCore.Authentication.OpenIdConnect 9.17.29-build20260511r1

Substantive.AspNetCore.Authentication.OpenIdConnect is a reusable .NET library that provides secure-by-default authentication building blocks for Razor Pages applications and API application.

It simplifies configuring:

  • External OAuth / OpenID Connect identity providers (Google, GitHub, GitLab, LINE, Auth0, Okta, Keycloak, Azure AD, Azure AD B2C)
  • Secure defaults (Authorization Code flow, PKCE, no token persistence)
  • Strongly-typed options with validation and source-generated option validators
  • API token validation using OpenIddict (OAuth 2.0 introspection)

Installation

1. Add configuration to the appsettings.json

Add the required authentication configuration to appsettings.json.

  • AuthenticationOpenIdConnect is used for interactive sign-in (Razor Pages / web apps)
  • OpenIddictValidation is used for API token validation (recommended default for APIs)
{
  // API applications typically DO NOT need interactive sign-in
  // AuthenticationOpenIdConnect can be omitted unless the API also hosts UI endpoints
  "OpenIddictValidation": {
    "IssuerBaseAddress": "https://auth.example.com/",
    "Audiences": "api",
    "ClientId": "api-client",
    "ClientSecret": "api-client-secret"
  }
}

2. Load configuration and add dependencies to the program.cs

var builder = WebApplication.CreateBuilder(args);

// API-focused authentication using token validation
builder.Services
       .AddApiAudienceAuthentication(options =>
          builder.Configuration
                 .GetSection("OpenIddictValidation")
                 .Bind(options));

builder.Services.AddAuthorization();

builder.Services.AddControllers();

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

Usage

Sample 1: API Application (Token-based authentication)

This is the recommended setup for API-only applications. The API validates access tokens issued by an external authorization server using OpenIddict.

Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddApiAudienceAuthentication(options =>
        builder.Configuration
            .GetSection("OpenIddictValidation")
            .Bind(options));

builder.Services.AddAuthorization();
builder.Services.AddControllers();

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllers();

app.Run();

Controller example

[ApiController]
[Route("api/[controller]")]
public sealed class ValuesController : ControllerBase
{
    [HttpGet]
    [Authorize]
    public IActionResult Get()
        => Ok(new[] { "value1", "value2" });
}

Sample 2: Blazor Application (Interactive sign-in)

This setup is suitable for Blazor Server applications (or hybrid apps) that require interactive user sign-in using external identity providers.

Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddAuthenticationOpenIdConnect(options =>
        builder.Configuration
            .GetSection("AuthenticationOpenIdConnect")
            .Bind(options));

builder.Services.AddAuthorization();

builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();

var app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

app.Run();

Example configuration using presets

builder.Services.AddAuthenticationOpenIdConnect(options =>
{
    options.AuthenticationOptions.DefaultScheme = "Cookies";
    options.AuthenticationOptions.DefaultChallengeScheme = "Google";

    // Interactive sign-in using Google
    options.Google = OAuthOptionsPresets.Google();

    // Optional: additional external providers
    options.Providers =
    [
        OAuthOptionsPresets.GitHub(),
        OAuthOptionsPresets.Okta("dev-123456.okta.com")
    ];
});

Advanced Sample: Combine OAuth presets with loaded configuration

In real-world applications, it is common to combine secure OAuth presets with configuration-bound secrets and environment-specific values. This approach provides:

  • Secure, opinionated defaults from OAuthOptionsPresets
  • Environment-specific values (ClientId, ClientSecret, scopes) from configuration
  • Clean separation between what the provider is and how it is configured per environment

appsettings.json

{
  "AuthenticationOpenIdConnect": {
    "AuthenticationOptions": {
      "DefaultScheme": "Cookies",
      "DefaultChallengeScheme": "Google"
    },
    "Providers": {
      "Google": {
        "ClientId": "<google-client-id>",
        "ClientSecret": "<google-client-secret>",
        "Scope": [ "openid", "profile", "email" ]
      },
      "GitHub": {
        "ClientId": "<github-client-id>",
        "ClientSecret": "<github-client-secret>",
        "Scope": [ "read:user", "user:email" ]
      }
    }
  }
}

Program.cs

builder.Services.AddAuthenticationOpenIdConnect(options =>
{
    // Bind shared authentication options
    builder.Configuration
        .GetSection("AuthenticationOpenIdConnect")
        .Bind(options);

    // Start from secure presets
    var google = OAuthOptionsPresets.GoogleOAuth();
    var gitHub = OAuthOptionsPresets.GitHub();

    // Overlay environment-specific configuration
    builder.Configuration
        .GetSection("AuthenticationOpenIdConnect:Providers:Google")
        .Bind(google.OAuthOptions);

    builder.Configuration
        .GetSection("AuthenticationOpenIdConnect:Providers:GitHub")
        .Bind(gitHub.OAuthOptions);

    options.Providers =
    [
        google,
        gitHub
    ];
});

Why this pattern works well

  • ✅ Presets define secure defaults (PKCE, callbacks, endpoints)
  • ✅ Configuration controls secrets and scopes per environment
  • ✅ No secrets are embedded in source code
  • ✅ Easy to add/remove providers without rewriting logic
  • ✅ Works cleanly with ValidateOnStart

FAQs and Troubleshoots

Q: Why does the application fail on startup if a provider is misconfigured?

A: This library uses ValidateOnStart and explicit validation to ensure authentication is correctly configured. Failing fast prevents insecure or partially configured authentication from reaching production.

Q: Should I use AuthenticationOpenIdConnect in an API-only application?

A: No. API-only applications should use AddApiAudienceAuthentication with OpenIddict token validation. AuthenticationOpenIdConnect is intended for interactive sign-in scenarios such as Razor Pages or hybrid API + UI applications.

Q: Where should ClientId and ClientSecret values be stored?

A: Always store secrets in configuration sources such as environment variables, secret managers, or user-secrets. They are intentionally never included in presets or source code.

Showing the top 20 packages that depend on Substantive.AspNetCore.Authentication.OpenIdConnect.

Packages Downloads
Substantive.Foundation.Backends
A metapackage contains all Substantive backend building blocks.
9
Substantive.Foundation.Backends
A metapackage contains all Substantive backend building blocks.
10
Substantive.Foundation.Backends
A metapackage contains all Substantive backend building blocks.
11
Substantive.Foundation.Backends
A metapackage contains all Substantive backend building blocks.
14
Substantive.Foundation.Backends
A metapackage contains all Substantive backend building blocks.
15
Substantive.Foundation.Backends
A metapackage contains all Substantive backend building blocks.
16
Substantive.Foundation.Backends
A metapackage contains all Substantive backend building blocks.
21
Substantive.Foundation.Backends
A metapackage contains all Substantive backend building blocks.
24
Substantive.Metapackage.Backends
A metapackage contains all Substantive backend building blocks.
9

Version Downloads Last updated
9.17.34-build20260919R3 1 09/19/2026
9.17.34-build20260919R2 1 09/19/2026
9.17.34-build20260914R1 3 09/14/2026
9.17.33-build20260715R1 7 07/15/2026
9.17.32-build20260701R1 5 07/01/2026
9.17.31-build20260624R1 5 06/24/2026
9.17.30-build20260624R1 5 06/24/2026
9.17.30-build20260616R1 6 06/16/2026
9.17.29-build20260512R1 6 05/12/2026
9.17.29-build20260511R1 6 05/11/2026
9.17.28-build20260331R1 10 03/31/2026
9.17.27-build20260306R1 12 03/06/2026
9.17.26-build20260211R1 11 02/11/2026
9.17.25-build20260210R1 7 02/10/2026
9.17.24-build20260209R1 8 02/09/2026
9.17.24-build20260204R1 9 02/04/2026
9.17.23-build20260204R1 6 02/04/2026
9.17.22-build20260204R1 6 02/04/2026
9.17.21-build20260204R2 6 02/04/2026
9.17.21-build20260204R1 6 02/04/2026
9.17.20-build20260203R1 9 02/03/2026
9.17.19-build20260130R1 13 01/30/2026
9.17.18-build20260129R1 24 01/29/2026
9.17.17-build20260129R1 28 01/29/2026
9.17.17-build20260128R1 26 01/28/2026
9.17.16-build20260127R2 28 01/27/2026
9.17.16-build20260123R1 10 01/23/2026
9.17.15-build20260122R1 12 01/22/2026
9.17.14-build20260122R2 12 01/22/2026
9.17.14-build20260122R1 9 01/22/2026
9.17.14-build20260121R1 8 01/21/2026
9.17.13-build20260121R1 8 01/21/2026
9.17.12-build20260120R1 12 01/20/2026
9.17.11-build20260120R1 9 01/20/2026
9.17.10-build20260120R1 10 01/20/2026
9.17.9-build20260119R1 9 01/19/2026
9.17.8-build20260119R1 8 01/19/2026
9.17.7-build20260115R1 7 01/15/2026
9.17.6-build20260115R1 7 01/15/2026
9.17.5-build20260119R1 8 01/19/2026
9.17.5-build20260115R1 7 01/15/2026
9.17.4-build20260115R1 10 01/15/2026
9.17.3-build20260115R1 7 01/15/2026
9.17.2-build20260115R1 7 01/15/2026
9.17.2-build20260113R1 11 01/13/2026
9.17.1-build20260113R2 7 01/13/2026
9.17.1-build20251231R2 7 12/31/2025
9.17.1-build20251230R2 9 12/30/2025
9.17.1-build20251230R1 7 12/30/2025
9.17.0-build20251229R2 7 12/29/2025
9.17.0-build20251229R1 7 12/29/2025
9.17.0-build20251226R1 7 12/26/2025
9.17.0-build20251225R1 7 12/25/2025
9.16.0-build20251224R1 8 12/24/2025
9.15.3-build20251224R1 7 12/24/2025
9.15.2-build20251224R1 7 12/24/2025
9.15.1-build20251224R1 6 12/24/2025
9.15.0-build20251224R1 7 12/24/2025
9.14.4-build20251224R1 7 12/24/2025
9.14.3-build20251224R4 7 12/24/2025
9.14.2-build20251224R1 4 12/24/2025
9.14.1-build20251224R1 6 12/24/2025
9.14.0-build20251223R1 7 12/23/2025
9.3.0-build20251223R4 6 12/23/2025
9.3.0-build20251223R3 7 12/23/2025
9.3.0-build20251223R2 7 12/23/2025
9.3.0-build20251223R1 6 12/23/2025
9.3.0-build20251222R2 7 12/22/2025
9.3.0-build20251222R1 8 12/22/2025
9.2.0-build20251222R2 6 12/22/2025
9.2.0-build20251222R1 7 12/22/2025
9.1.0-build20251218R1 6 12/18/2025
9.1.0-build20251217R2 6 12/17/2025
9.1.0-build20251217R1 8 12/17/2025
9.1.0-build20251216R2 8 12/16/2025
9.1.0-build20251216R1 7 12/16/2025
9.1.0-build20251215R1 7 12/15/2025
9.1.0-build20251212R1 7 12/12/2025
9.1.0-build20251211R1 7 12/11/2025
9.1.0-build20251210R1 6 12/10/2025
9.1.0-build20251202R2 8 12/02/2025
9.1.0-build20251202R1 7 12/02/2025
9.0.5-build20251117R1 8 11/17/2025
9.0.5-build20251110R1 13 11/10/2025
9.0.5-build20251103R1 10 11/03/2025
9.0.5-build20251030R1 11 10/30/2025
9.0.5-build20251028R1 9 10/28/2025
9.0.5-build20251016R1 8 10/16/2025
9.0.5-build20250925R2 11 09/25/2025
9.0.5-build20250925R1 10 09/25/2025
9.0.5-build20250924R1 10 09/24/2025
9.0.5-build20250910R1 7 09/10/2025
9.0.5-build20250908R1 14 09/08/2025
9.0.5-build20250905R2 9 09/05/2025
9.0.5-build20250905R1 8 09/05/2025
9.0.5-build20250827R1 9 08/27/2025
9.0.5-build20250825R1 8 08/25/2025
9.0.5-build20250822R1 8 08/22/2025
9.0.5-build20250821R1 14 08/21/2025
9.0.4-build20250821R1 12 08/21/2025
9.0.3-build20250821R1 12 08/21/2025
9.0.2-build20250821R1 12 08/21/2025
9.0.1-build20250821R1 12 08/21/2025
9.0.0 10 08/16/2025
9.0.0-build20250821R3 12 08/21/2025
9.0.0-build20250821R2 12 08/21/2025
9.0.0-build20250821R1 11 08/21/2025
9.0.0-build20250818R2 9 08/18/2025
9.0.0-build20250818R1 10 08/18/2025
9.0.0-build20250815R1 10 08/15/2025
9.0.0-build20250814R1 9 08/14/2025
9.0.0-build20250722R3 12 07/22/2025
9.0.0-build20250714R3 15 07/14/2025
9.0.0-build20250714R2 12 07/14/2025
9.0.0-build20250714R1 9 07/14/2025
9.0.0-build20250710R1 12 07/10/2025
9.0.0-build20250707R2 18 07/07/2025
9.0.0-build20250707R1 11 07/07/2025
9.0.0-build20250629R1 15 06/29/2025
9.0.0-build20250626R2 16 06/26/2025
9.0.0-build20250626R1 10 06/26/2025
9.0.0-build20250623R1 17 06/23/2025
9.0.0-build20250621R1 21 06/21/2025
1.1.0-build20251224R1 7 12/24/2025