Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion astro/src/content/docs/identityserver/spaces/index.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "IdentityServer Spaces"
description: "Run multiple isolated IdentityServer security domains in a single deployment using Spaces with per-tenant configuration and operational data"
date: 2026-10-23
date: 2026-11-02
sidebar:
label: "Overview"
order: 1
Expand Down Expand Up @@ -98,6 +98,62 @@ If users must be shared across spaces, use a deliberately separate user director
[space-aware User Management storage](/identityserver/data/providers/duende-storage/getting-started.md#use-duende-user-management).
:::

## Cookies and Space Paths

When a path pattern matches a space, IdentityServer scopes its cookies to that space's path. This keeps sessions in
different spaces on the same origin apart. IdentityServer derives the cookie `Path` on every request from the resolved
base path, which is the hosting `PathBase` plus the matched space path (for example, `/host/space-a`). Spaces matched
by origin only add no space path, so their cookies use the hosting `PathBase`, or `/` when it is empty.
There is nothing to configure. All other cookie attributes (name, `Domain`, `Secure`, `SameSite`, and `HttpOnly`) come
from your configuration unchanged.

IdentityServer scopes these cookies to the space path:

* The session cookie, which uses the `idsrv` scheme by default. If you set
`IdentityServerOptions.Authentication.CookieAuthenticationScheme`, or rely on the default authenticate or default
scheme, that scheme's cookie is scoped instead (for example, ASP.NET Core Identity's `Identity.Application`).
* The `idsrv.external` cookie used for external authentication.
* The temporary message cookies that carry state between pages, such as consent.
* The check-session cookie, `idsrv.session` by default. It takes the same path as the cookies above, so it is scoped to
the space path and your hosting `PathBase`. The name comes from `Authentication.CheckSessionCookieName`. IdentityServer
issues it only when `Endpoints.EnableCheckSessionEndpoint` is enabled. It still uses `Domain` and `SameSite` from
`Authentication.CheckSessionCookieDomain` and `Authentication.CheckSessionCookieSameSiteMode`.

Other application cookies, and the correlation and nonce cookies of external authentication handlers such as OpenID
Connect, are not changed.

:::caution[Don't use the __Host- cookie name prefix with a non-root cookie path]
The `__Host-` prefix requires `Path=/`. If IdentityServer builds a `__Host-` prefixed cookie for a request whose
resolved cookie path isn't `/`, it throws an `InvalidOperationException` before issuing the cookie. This happens with
path-based spaces, and also with origin-only spaces or apps without Spaces when the hosting `PathBase` isn't empty.
The message starts with: `Cookie '<name>' uses the '__Host-' prefix, which requires the cookie path to be '/', but the
resolved IdentityServer cookie path is '<path>'.` Use the `__Secure-` prefix instead. It still requires the `Secure`
attribute but permits non-root paths.
:::

### Rollout Impact

IdentityServer doesn't migrate or remove existing cookies. Cookies issued with `Path=/` before you enabled path-based
spaces stay in the browser until they expire or the user clears them. Browsers send `Path=/` cookies to every path,
so these older cookies are still sent to requests under each space path. A new space-scoped cookie with the same name
can exist next to them.

Changing the cookie path alone doesn't end existing sessions. Whether IdentityServer accepts an older cookie depends on
[data protection partitioning](/identityserver/spaces/getting-started.md#before-deployment):

* In a named space, the partitioned data protector can't read a cookie that was protected before partitioning, so the
user has to sign in again.
* In the Default space, a fallback to the unpartitioned purpose chain can still read the
older cookie, so the existing session can stay valid.
* With `SpacesOptions.PartitionDataProtection` set to `false`, an older cookie can be read in any space.

Don't rely on path scoping to sign users out. If existing sessions must end when you enable path-based spaces, end them
explicitly, for example by changing the session cookie name. Hosts without a space path, including origin-only spaces
with an empty `PathBase`, keep `Path=/` and aren't affected.

Call `UseSpaceResolution()` before `UseIdentityServer()`. If space resolution hasn't run yet, cookies fall back to
`Path=/` and aren't isolated between spaces.

## What Spaces Does Not Isolate

:::caution[Spaces Do Not Isolate Every Process-Level Dependency]
Expand Down
Loading