Claude
Skills
Sign in
Back

identityserver-configuration

Included with Lifetime
$97 forever

Configure Duende IdentityServer including client definitions, API resources, identity resources, scopes, signing credentials, and server-side sessions. Covers client types (M2M, interactive, SPA), grant types, API Scopes vs API Resources vs Identity Resources, secret management, and client authentication methods. Includes both in-memory and database-backed configuration.

Backend & APIs

What this skill does


# Duende IdentityServer Configuration

## When to Use This Skill

Use this skill when:
- Setting up a new Duende IdentityServer host
- Defining or modifying client registrations
- Configuring API resources, API scopes, or identity resources
- Setting up signing key management (automatic or static)
- Enabling server-side sessions
- Tuning `IdentityServerOptions` for production deployments
- Migrating from IdentityServer4 to Duende IdentityServer

## Core Principles

1. **Authorization Code + PKCE by Default** — Use `GrantTypes.Code` for all interactive clients. Never use implicit flow for new applications.
2. **Least Privilege Scopes** — Grant clients only the scopes they need. Avoid wildcard or overly broad scope assignments.
3. **Automatic Key Management** — Prefer the built-in automatic key rotation over static key configuration in production.
4. **API Resources for Audience Isolation** — Use `ApiResource` to control the `aud` claim and isolate API boundaries. Use `ApiScope` for fine-grained permission modeling within those boundaries.
5. **Server-Side Sessions for Enterprise** — Enable server-side sessions when you need centralized session management, back-channel logout, or session queries.

## Related Skills

- `identityserver-stores` — EF Core persistence for configuration and operational data
- `oauth-oidc-protocols` — Protocol fundamentals that underpin these configuration choices
- `identity-security-hardening` — Production hardening of IdentityServer deployments
- `token-management` — Client-side token lifecycle with Duende.AccessTokenManagement
- `aspnetcore-authentication` — Configuring OIDC authentication in client applications

Docs: https://docs.duendesoftware.com/identityserver/configuration

---

## Sub-Documents

Load these sub-documents when the user's question specifically targets one of these areas:

| Document | Description | When to Load |
|----------|-------------|--------------|
| [docs/client-types.md](docs/client-types.md) | Grant type selection matrix, client property reference tables, client authentication methods (shared secret, private_key_jwt, mTLS), secret rollover, and CORS | private_key_jwt, mTLS, secret rotation, refresh token settings, client authentication, CORS origins |
| [docs/resources-scopes.md](docs/resources-scopes.md) | Resource type decision matrix, identity resources, API scopes (including parameterized scopes), and API resources with audience isolation | aud claim, audience isolation, parameterized scopes, EmitStaticAudienceClaim, API Resources, Identity Resources |

---

## Pattern 1: Hosting and Basic Setup

Register Duende IdentityServer in `Program.cs` with `AddIdentityServer`. All configuration flows from the `IdentityServerOptions` lambda and the builder's fluent API.

```csharp
var builder = WebApplication.CreateBuilder(args);

var idsvrBuilder = builder.Services.AddIdentityServer(options =>
{
    // Let the issuer be inferred from the request URL (recommended)
    // options.IssuerUri = "https://identity.example.com"; // Only set when behind a reverse proxy

    // Enable events for diagnostics
    options.Events.RaiseErrorEvents = true;
    options.Events.RaiseInformationEvents = true;
    options.Events.RaiseFailureEvents = true;
    options.Events.RaiseSuccessEvents = true;
})
    .AddInMemoryIdentityResources(Config.IdentityResources)
    .AddInMemoryApiScopes(Config.ApiScopes)
    .AddInMemoryClients(Config.Clients);

var app = builder.Build();
app.UseIdentityServer(); // Includes UseAuthentication()
app.UseAuthorization();
app.Run();
```

> **Important:** Call `UseIdentityServer()` instead of `UseAuthentication()` — it registers both the IdentityServer middleware and the authentication middleware.

---

## Pattern 2: Client Definitions

Clients represent applications that request tokens. The three most common configurations are:

### Machine-to-Machine (Client Credentials)

For service-to-service communication with no interactive user:

```csharp
new Client
{
    ClientId = "service.worker",
    ClientName = "Background Worker Service",

    AllowedGrantTypes = GrantTypes.ClientCredentials,
    ClientSecrets = { new Secret("secret".Sha256()) },

    AllowedScopes = { "api1", "api2.read_only" }
}
```

### Interactive Web Application (Authorization Code + PKCE)

For server-rendered web apps that authenticate users and call APIs:

```csharp
new Client
{
    ClientId = "web.app",
    ClientName = "Web Application",

    AllowedGrantTypes = GrantTypes.Code,
    RequirePkce = true, // Default is true in Duende IS

    ClientSecrets = { new Secret("secret".Sha256()) },

    // Redirect URIs — must exactly match what the client sends
    RedirectUris = { "https://app.example.com/signin-oidc" },
    PostLogoutRedirectUris = { "https://app.example.com/signout-callback-oidc" },
    FrontChannelLogoutUri = "https://app.example.com/signout-oidc",

    // Enable offline access for refresh tokens
    AllowOfflineAccess = true,

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        IdentityServerConstants.StandardScopes.Email,
        "api1"
    }
}
```

### SPA with BFF Pattern

For JavaScript SPAs using the Backend-for-Frontend pattern (see `duende-bff` skill):

```csharp
new Client
{
    ClientId = "spa.bff",
    ClientName = "SPA with BFF",

    AllowedGrantTypes = GrantTypes.Code,
    RequirePkce = true,
    RequireClientSecret = true, // BFF host holds the secret

    ClientSecrets = { new Secret("secret".Sha256()) },

    RedirectUris = { "https://app.example.com/signin-oidc" },
    PostLogoutRedirectUris = { "https://app.example.com/signout-callback-oidc" },
    BackChannelLogoutUri = "https://app.example.com/bff/backchannel",

    AllowOfflineAccess = true,

    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        "api1"
    }
}
```

### Key Client Properties

| Property | Purpose | Default |
|----------|---------|---------|
| `RequirePkce` | Enforce PKCE for authorization code flow | `true` |
| `AllowOfflineAccess` | Enable refresh token issuance | `false` |
| `AccessTokenLifetime` | Access token duration in seconds | `3600` (1 hour) |
| `IdentityTokenLifetime` | Identity token duration in seconds | `300` (5 min) |
| `RefreshTokenUsage` | `ReUse` or `OneTimeOnly` | `ReUse` (recommend `OneTimeOnly` for security) |
| `RefreshTokenExpiration` | `Absolute` or `Sliding` | `Absolute` |
| `AbsoluteRefreshTokenLifetime` | Max refresh token lifetime in seconds | `2592000` (30 days) |
| `AllowedCorsOrigins` | CORS origins for token endpoint calls | empty |
| `RequireConsent` | Show consent screen | `false` |
| `CoordinateLifetimeWithUserSession` | Tie token lifetimes to user session | `false` |

### Defining Clients in appsettings.json

For scenarios where client configuration should be externalized:

```json
{
  "IdentityServer": {
    "Clients": [
      {
        "Enabled": true,
        "ClientId": "local-dev",
        "ClientName": "Local Development",
        "ClientSecrets": [
          {
            "Value": "<Insert Sha256 hash of the secret encoded as Base64 string>"
          }
        ],
        "AllowedGrantTypes": ["client_credentials"],
        "AllowedScopes": ["api1"]
      }
    ]
  }
}
```

```csharp
// Load clients from configuration
idsvrBuilder.AddInMemoryClients(
    configuration.GetSection("IdentityServer:Clients"));
```

---

## Pattern 3: Identity Resources

Identity resources define groups of claims about users, requested via the `scope` parameter. They map to claims in the **identity token** and the **userinfo endpoint**.

### Standard Identity Resources

```csharp
public static IEnumerable<IdentityResource> IdentityResources =>
    new IdentityResource[]
    {
        new IdentityResources.OpenId(),   // Required — maps to "sub" claim
        new IdentityResources.Profile(),  // name, family_name,

Related in Backend & APIs