aspnetcore-authentication
ASP.NET Core authentication middleware configuration including OpenID Connect, JWT Bearer, cookie authentication, authentication schemes, challenge/forbid flows, and external identity provider integration.
What this skill does
# ASP.NET Core Authentication
## When to Use This Skill
Use this skill when:
- Configuring OIDC authentication in an ASP.NET Core web application
- Setting up JWT Bearer authentication for an API
- Managing authentication schemes (cookies, OIDC, JWT, external providers)
- Implementing challenge, sign-in, sign-out, and forbid flows
- Debugging authentication failures (401s, redirect loops, claim mapping issues)
- Integrating with Duende IdentityServer as an OpenID Connect provider
- Configuring token validation parameters
## Core Principles
1. **Authentication ≠ Authorization** — Authentication establishes *who* the user is. Authorization (see `aspnetcore-authorization`) determines *what* they can do.
2. **Scheme-Based Architecture** — ASP.NET Core authentication is built around named schemes. Each scheme has a handler that knows how to authenticate, challenge, and sign out.
3. **Cookies for Web Apps, JWT for APIs** — Web applications use cookie authentication (with OIDC for login). APIs use JWT Bearer or introspection.
4. **Never Roll Your Own** — Use the built-in OIDC and JWT Bearer handlers. They handle nonce validation, key rotation, token validation, and dozens of edge cases.
5. **Claim Type Mapping Matters** — The OIDC handler maps JWT claim types to .NET claim types by default. Disable this for predictable claim names.
## Related Skills
- `aspnetcore-authorization` — Policy-based authorization after authentication
- `identityserver-configuration` — Server-side client and resource configuration
- `identityserver-sessions-providers` — Server-side sessions to reduce cookie size and maintain IdP-side data
- `oauth-oidc-protocols` — Protocol fundamentals underlying these handlers
- `token-management` — Automatic token refresh with Duende.AccessTokenManagement
Docs: https://docs.duendesoftware.com/identityserver/tokens/authentication
---
## Pattern 1: OIDC Authentication for Web Applications
The most common pattern — a server-rendered web app authenticating users via Duende IdentityServer:
```csharp
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
})
.AddCookie("Cookies", options =>
{
options.Cookie.Name = "myapp";
options.Cookie.SameSite = SameSiteMode.Lax;
options.ExpireTimeSpan = TimeSpan.FromHours(8);
options.SlidingExpiration = true;
})
.AddOpenIdConnect("oidc", options =>
{
options.Authority = "https://identity.example.com";
options.ClientId = "web.app";
options.ClientSecret = "secret";
options.ResponseType = "code"; // Authorization code flow
// Map scopes to request
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.Scope.Add("api1");
options.Scope.Add("offline_access"); // For refresh tokens
// Save tokens in the authentication cookie
options.SaveTokens = true;
// Disable Microsoft's JWT claim type mapping
options.MapInboundClaims = false;
// Where to get additional user claims
options.GetClaimsFromUserInfoEndpoint = true;
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
RoleClaimType = "role"
};
});
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
```
### Critical Settings Explained
| Setting | Why | Default |
|---------|-----|---------|
| `MapInboundClaims = false` | Prevents renaming `sub` → `http://schemas.xmlsoap.org/.../nameidentifier` | `true` (maps) |
| `SaveTokens = true` | Stores access/refresh tokens in the cookie for later API calls | `false` |
| `GetClaimsFromUserInfoEndpoint = true` | Fetches full profile claims from userinfo | `false` |
| `ResponseType = "code"` | Authorization code flow (PKCE is automatic in .NET 7+) | `"code"` (.NET 7+; was `"code id_token"` in earlier versions) |
---
## Pattern 2: JWT Bearer Authentication for APIs
APIs validate access tokens issued by IdentityServer:
```csharp
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://identity.example.com";
options.Audience = "catalog-api"; // Must match ApiResource name
options.MapInboundClaims = false; // Must be included
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudience = "catalog-api",
NameClaimType = "name",
RoleClaimType = "role"
};
});
builder.Services.AddAuthorization();
var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();
// Protect endpoints
app.MapGet("/products", () => Results.Ok())
.RequireAuthorization();
```
### Multiple Audiences
When an API accepts tokens from multiple resources:
```csharp
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = true,
ValidAudiences = new[] { "catalog-api", "shared-api" }
};
```
---
## Pattern 3: Reference Token Introspection
For APIs that validate reference tokens (opaque tokens) instead of JWTs:
```csharp
builder.Services.AddAuthentication("Bearer")
.AddOAuth2Introspection("Bearer", options =>
{
options.Authority = "https://identity.example.com";
options.ClientId = "catalog-api";
options.ClientSecret = "api-secret";
});
```
> Install the `Duende.AspNetCore.Authentication.JwtBearer` package which supports both JWT and reference token validation, switching automatically based on the token format.
### Combined JWT + Reference Token Support
```csharp
builder.Services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "https://identity.example.com";
options.MapInboundClaims = false;
// The Duende JWT handler can forward to introspection for reference tokens
options.ForwardDefaultSelector = Selector.ForwardReferenceToken("introspection");
})
.AddOAuth2Introspection("introspection", options =>
{
options.Authority = "https://identity.example.com";
options.ClientId = "catalog-api";
options.ClientSecret = "api-secret";
});
```
---
## Pattern 4: Understanding Authentication Schemes
ASP.NET Core uses named authentication schemes. Each scheme is handled by a specific handler.
### Default Schemes
```csharp
builder.Services.AddAuthentication(options =>
{
// Used for [Authorize] attribute and User.Identity
options.DefaultScheme = "Cookies";
// Used when authentication is required (401 → redirect to login)
options.DefaultChallengeScheme = "oidc";
// Used when access is denied (403)
options.DefaultForbidScheme = "oidc";
// Used when signing in (setting the cookie after OIDC callback)
options.DefaultSignInScheme = "Cookies";
// Used when signing out
options.DefaultSignOutScheme = "oidc";
});
```
### The Authentication Flow
```
Request → [UseAuthentication] → Cookie handler reads cookie
├─ Valid cookie → User is authenticated
└─ No cookie → User is anonymous
[UseAuthorization] → [Authorize] attribute checks
├─ Authenticated → proceed
└─ Not authenticated → Challenge
└─ OIDC handler redirects to IdentityServer
└─ User logs in → callback → cookie created
```
---
## Pattern 5: Claim Type Mapping
By default, the Microsoft OIDC handler remaps JWT claims to XML-based .NET claim types. This causes confusion:
### The Mapping Problem
| JWT Claim | .NET Default Mapping | After `MapInboundClaims = false` |
|-----------|---------------------|------------------------Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.