From 99dd6fb7e3ecf0c14074c700095769080c4171d7 Mon Sep 17 00:00:00 2001 From: AL Rodriguez Date: Thu, 26 Mar 2026 14:03:05 -0400 Subject: [PATCH 01/13] Moved data protection info to a new page in the General Information section. Added callouts for BFF. Updated the Data Protection info for IdentityServer to link to the general topic. --- .../content/docs/general/data-protection.md | 132 ++++++++++++++++++ .../docs/identityserver/deployment/index.md | 104 +------------- 2 files changed, 135 insertions(+), 101 deletions(-) create mode 100644 astro/src/content/docs/general/data-protection.md diff --git a/astro/src/content/docs/general/data-protection.md b/astro/src/content/docs/general/data-protection.md new file mode 100644 index 00000000..3ccbcd42 --- /dev/null +++ b/astro/src/content/docs/general/data-protection.md @@ -0,0 +1,132 @@ +--- +title: Data Protection +description: Comprehensive guide covering key aspects of add data protection. +date: 2026-03-26T08:20:20+02:00 +sidebar: + order: 20 +redirect_from: + - /dataprotection/ +--- + +Any Duende server-side application like IdentityServer of BFF is developed and deployed as an ASP.NET Core application. While there are a lot of decisions to make, this also means that your implementation can be built, deployed, hosted, and managed with the same technology you're using for any other ASP.NET applications you have. + +One important aspect to include in your application is around Data Protection. + +:::note +Some of our most common support requests are related to [Data Protection Keys](#data-protection-keys), so we strongly encourage you to review the rest of this page before deploying to production. +::: + +## ASP.NET Core Data Protection + +Data Protection in any Duende server-side application makes extensive use of ASP.NET's [data protection](https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/) feature. It is crucial that you configure data protection correctly before you start using your application in production. + +In local development, ASP.NET automatically creates data protection keys, but in a deployed environment, you will need +to ensure that your data protection keys are stored in a persistent way and shared across all load balanced instances of +your implementation. This means you'll need to choose where to store and how to protect the data +protection keys, as appropriate for your environment. Microsoft has extensive +documentation [here](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview) +describing how to configure storage and protection of data protection keys. + +A typical implementation should include data protection configuration code, like this: + +```csharp +// Program.cs +builder.Services.AddDataProtection() + // Choose an extension method for key persistence, such as + // PersistKeysToFileSystem, PersistKeysToDbContext, + // PersistKeysToAzureBlobStorage, PersistKeysToAWSSystemsManager, or + // PersistKeysToStackExchangeRedis + .PersistKeysToFoo() + // Choose an extension method for key protection, such as + // ProtectKeysWithCertificate, ProtectKeysWithAzureKeyVault + .ProtectKeysWithBar() + // Explicitly set an application name to prevent issues with + // key isolation. + .SetApplicationName("My.Duende.IdentityServer"); +``` + +:::danger[Ensure data protection keys are persisted] +Always make sure data protection is configured to persist data protection keys to storage, using `.PersistKeys...()` +for your storage mechanism. + +In addition, make sure the storage mechanism itself is durable. For example, if you are using the default file system +based key store, make sure that the configured path is not stored on ephemeral storage. If you are using Redis to store +data protection keys using `PersistKeysToStackExchangeRedis`, ensure that your Redis service is configured to persist +data to a database backup or append-only file. Otherwise, when your Redis instance reboots, you will lose all data +protection keys. + +If you lose your data protection keys, all data protected with those keys is no longer be readable. +::: + +## ASP.NET Data Protection Keys and IdentityServer Signing Keys + +ASP.NET's data protection keys are sometimes confused with IdentityServer's signing keys, but the two are completely +separate keys with different purposes. IdentityServer implementations need both to function correctly. + +### ASP.NET Data Protection Keys + +Data protection is a cryptographic library that is part of ASP.NET Core. Data protection uses private key +cryptography to encrypt and sign sensitive data to ensure that it is only written and read by the application. The +framework uses data protection to secure data that is commonly used by IdentityServer implementations, such as +authentication cookies and anti-forgery tokens. In addition, IdentityServer itself uses data protection to protect +sensitive data at rest, such as persisted grants, and sensitive data passed through the browser, such as the +context objects passed to pages in the UI. The data protection keys are critical secrets for an IdentityServer +implementation because they encrypt a great deal of sensitive data at rest and prevent sensitive data that is +round-tripped through the browser from being tampered with. + +### The IdentityServer Signing Key + +Separately, IdentityServer needs cryptographic keys, called [signing keys](/identityserver/fundamentals/key-management.md), to +sign tokens such as JWT access tokens and id tokens. The signing keys use public key cryptography to allow client +applications and APIs to validate token signatures using the public keys, which are published by IdentityServer +through [discovery](/identityserver/reference/endpoints/discovery.md). The private key component of the signing keys are +also critical secrets for IdentityServer because a valid signature provides integrity and non-repudiation guarantees +that allow client applications and APIs to trust those tokens. + +## Common Problems + +Common data protection problems occur when data is protected with a key that is not available when the data is later +read. A common symptom is `CryptographicException`s in the application logs. For example, when automatic key +management fails to read its signing keys due to a data protection failure, IdentityServer will log an error message +such as "Error unprotecting key with kid {Signing Key ID}.", and log the underlying +`System.Security.Cryptography.CryptographicException`, with a message like "The key {Data Protection Key ID} was not +found in the key ring." + +Failures to read automatic signing keys are often the first place where a data protection problem manifests, but any of +many places where ASP.NET uses data protection might also throw `CryptographicException`s. + +There are several ways that data protection problems can occur: + +1. In load balanced environments, every instance of a Duende server-side app needs to be configured to share data protection keys. + Without shared data protection keys, each load balanced instance will only be able to read the data that it writes. +2. Data protected data could be generated in a development environment and then accidentally included into the build + output. This is most commonly the case for automatically managed signing keys that are stored on disk. If you are + using automatic signing key management with the default file system based key store, you should exclude the `~/keys` + directory from source control and make sure keys are not included in your builds. Note that if you are using our + Entity Framework based implementation of the operational data stores, then the keys will instead be stored in the + database. +3. Data protection creates keys isolated by application name. If you don't specify a name, the content root path of the + application will be used. But, beginning in .NET 6.0 Microsoft changed how they handle the path, which can cause data + protection keys to break. Their docs on the problem + are [here](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview#setapplicationname), + including a work-around where you de-normalize the path. Then, in .NET 7.0, this change was reverted. The solution is + always to specify an explicit application name, and if you have old keys that were generated without an explicit + application name, you need to set your application name to match the default behavior that produced the keys you want + to be able to read. +4. If your IdentityServer is hosted by IIS, special configuration is needed for data protection. In most default + deployments, IIS lacks the permissions required to persist data protection keys, and falls back to using an ephemeral + key generated every time the site starts up. Microsoft's docs on this issue + are [here](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/advanced?view=aspnetcore-7.0#data-protection). + +### Identity Server's Usage of Data Protection + +Duende IdentityServer's features that rely on data protection include + +* protecting signing keys at rest (if [automatic key management](/identityserver/fundamentals/key-management.md#automatic-key-management) is used and enabled) +* protecting [persisted grants](/identityserver/data/operational.md#persisted-grant-service) at rest (if enabled) +* protecting [server-side session](/identityserver/ui/server-side-sessions/index.md) data at rest (if enabled) +* protecting [the state parameter](/identityserver/ui/login/external.md#state-url-length-and-isecuredataformat) for + external OIDC providers (if enabled) +* protecting message payloads sent between pages in the UI ( + e.g. [logout context](/identityserver/ui/logout/logout-context.md) and [error context](/identityserver/ui/error.md)). +* session management (because the ASP.NET Core cookie authentication handler requires it) diff --git a/astro/src/content/docs/identityserver/deployment/index.md b/astro/src/content/docs/identityserver/deployment/index.md index 476a005a..54f25bca 100644 --- a/astro/src/content/docs/identityserver/deployment/index.md +++ b/astro/src/content/docs/identityserver/deployment/index.md @@ -6,7 +6,6 @@ sidebar: label: Overview order: 10 redirect_from: - - /dataprotection/ - /identityserver/v5/deployment/ - /identityserver/v6/deployment/ - /identityserver/v7/deployment/ @@ -96,116 +95,19 @@ Duende IdentityServer makes extensive use of ASP.NET's [data protection](https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/) feature. It is crucial that you configure data protection correctly before you start using your IdentityServer in production. -In local development, ASP.NET automatically creates data protection keys, but in a deployed environment, you will need -to ensure that your data protection keys are stored in a persistent way and shared across all load balanced instances of -your IdentityServer implementation. This means you'll need to choose where to store and how to protect the data -protection keys, as appropriate for your environment. Microsoft has extensive -documentation [here](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview) -describing how to configure storage and protection of data protection keys. +The recommended practices for setting up and using Data Protection in Duende IdentityServer are the same as other server-side products, like BFF, and are enumerated in the [general Data Protection page](/general/data-protection). -A typical IdentityServer implementation should include data protection configuration code, like this: - -```csharp -// Program.cs -builder.Services.AddDataProtection() - // Choose an extension method for key persistence, such as - // PersistKeysToFileSystem, PersistKeysToDbContext, - // PersistKeysToAzureBlobStorage, PersistKeysToAWSSystemsManager, or - // PersistKeysToStackExchangeRedis - .PersistKeysToFoo() - // Choose an extension method for key protection, such as - // ProtectKeysWithCertificate, ProtectKeysWithAzureKeyVault - .ProtectKeysWithBar() - // Explicitly set an application name to prevent issues with - // key isolation. - .SetApplicationName("IdentityServer"); -``` - -:::danger[Ensure data protection keys are persisted] -Always make sure data protection is configured to persist data protection keys to storage, using `.PersistKeys...()` -for your storage mechanism. - -In addition, make sure the storage mechanism itself is durable. For example, if you are using the default file system -based key store, make sure that the configured path is not stored on ephemeral storage. If you are using Redis to store -data protection keys using `PersistKeysToStackExchangeRedis`, ensure that your Redis service is configured to persist -data to a database backup or append-only file. Otherwise, when your Redis instance reboots, you will lose all data -protection keys. - -If you lose your data protection keys, all data protected with those keys to no longer be readable. -::: - -### Data Protection Keys and IdentityServer's Signing Keys - -ASP.NET's data protection keys are sometimes confused with IdentityServer's signing keys, but the two are completely -separate keys with different purposes. IdentityServer implementations need both to function correctly. - -#### Data Protection Keys - -Data protection is a cryptographic library that is part of the ASP.NET framework. Data protection uses private key -cryptography to encrypt and sign sensitive data to ensure that it is only written and read by the application. The -framework uses data protection to secure data that is commonly used by IdentityServer implementations, such as -authentication cookies and anti-forgery tokens. In addition, IdentityServer itself uses data protection to protect -sensitive data at rest, such as persisted grants, and sensitive data passed through the browser, such as the -context objects passed to pages in the UI. The data protection keys are critical secrets for an IdentityServer -implementation because they encrypt a great deal of sensitive data at rest and prevent sensitive data that is -round-tripped through the browser from being tampered with. - -#### IdentityServer Signing Key - -Separately, IdentityServer needs cryptographic keys, called [signing keys](/identityserver/fundamentals/key-management.md), to -sign tokens such as JWT access tokens and id tokens. The signing keys use public key cryptography to allow client -applications and APIs to validate token signatures using the public keys, which are published by IdentityServer -through [discovery](/identityserver/reference/endpoints/discovery.md). The private key component of the signing keys are -also critical secrets for IdentityServer because a valid signature provides integrity and non-repudiation guarantees -that allow client applications and APIs to trust those tokens. - -### Common Problems - -Common data protection problems occur when data is protected with a key that is not available when the data is later -read. A common symptom is `CryptographicException`s in the IdentityServer logs. For example, when automatic key -management fails to read its signing keys due to a data protection failure, IdentityServer will log an error message -such as "Error unprotecting key with kid {Signing Key ID}.", and log the underlying -`System.Security.Cryptography.CryptographicException`, with a message like "The key {Data Protection Key ID} was not -found in the key ring." - -Failures to read automatic signing keys are often the first place where a data protection problem manifests, but any of -many places where IdentityServer and ASP.NET use data protection might also throw `CryptographicException`s. - -There are several ways that data protection problems can occur: - -1. In load balanced environments, every instance of IdentityServer needs to be configured to share data protection keys. - Without shared data protection keys, each load balanced instance will only be able to read the data that it writes. -2. Data protected data could be generated in a development environment and then accidentally included into the build - output. This is most commonly the case for automatically managed signing keys that are stored on disk. If you are - using automatic signing key management with the default file system based key store, you should exclude the `~/keys` - directory from source control and make sure keys are not included in your builds. Note that if you are using our - Entity Framework based implementation of the operational data stores, then the keys will instead be stored in the - database. -3. Data protection creates keys isolated by application name. If you don't specify a name, the content root path of the - application will be used. But, beginning in .NET 6.0 Microsoft changed how they handle the path, which can cause data - protection keys to break. Their docs on the problem - are [here](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview#setapplicationname), - including a work-around where you de-normalize the path. Then, in .NET 7.0, this change was reverted. The solution is - always to specify an explicit application name, and if you have old keys that were generated without an explicit - application name, you need to set your application name to match the default behavior that produced the keys you want - to be able to read. -4. If your IdentityServer is hosted by IIS, special configuration is needed for data protection. In most default - deployments, IIS lacks the permissions required to persist data protection keys, and falls back to using an ephemeral - key generated every time the site starts up. Microsoft's docs on this issue - are [here](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/advanced?view=aspnetcore-7.0#data-protection). ### Identity Server's Usage of Data Protection Duende IdentityServer's features that rely on data protection include -* protecting signing keys at rest ( - if [automatic key management](/identityserver/fundamentals/key-management.md#automatic-key-management) is used and enabled) +* protecting signing keys at rest (if [automatic key management](/identityserver/fundamentals/key-management.md#automatic-key-management) is used and enabled) * protecting [persisted grants](/identityserver/data/operational.md#persisted-grant-service) at rest (if enabled) * protecting [server-side session](/identityserver/ui/server-side-sessions/index.md) data at rest (if enabled) * protecting [the state parameter](/identityserver/ui/login/external.md#state-url-length-and-isecuredataformat) for external OIDC providers (if enabled) -* protecting message payloads sent between pages in the UI ( - e.g. [logout context](/identityserver/ui/logout/logout-context.md) and [error context](/identityserver/ui/error.md)). +* protecting message payloads sent between pages in the UI (e.g. [logout context](/identityserver/ui/logout/logout-context.md) and [error context](/identityserver/ui/error.md)). * session management (because the ASP.NET Core cookie authentication handler requires it) ## IdentityServer Data Stores From 57b5ccc8af0e7b07ede9a7cb9e28d60f86acc3f2 Mon Sep 17 00:00:00 2001 From: Al Rodriguez Date: Thu, 26 Mar 2026 17:39:16 -0400 Subject: [PATCH 02/13] Update astro/src/content/docs/identityserver/deployment/index.md Co-authored-by: Maarten Balliauw --- astro/src/content/docs/identityserver/deployment/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astro/src/content/docs/identityserver/deployment/index.md b/astro/src/content/docs/identityserver/deployment/index.md index 54f25bca..89ed37ef 100644 --- a/astro/src/content/docs/identityserver/deployment/index.md +++ b/astro/src/content/docs/identityserver/deployment/index.md @@ -95,7 +95,7 @@ Duende IdentityServer makes extensive use of ASP.NET's [data protection](https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/) feature. It is crucial that you configure data protection correctly before you start using your IdentityServer in production. -The recommended practices for setting up and using Data Protection in Duende IdentityServer are the same as other server-side products, like BFF, and are enumerated in the [general Data Protection page](/general/data-protection). +The recommended practices for setting up and using ASP.NET Core Data Protection for Duende IdentityServer are the same as for other server-side products, like BFF. See the [general ASP.NET Core Data Protection page](/general/data-protection). ### Identity Server's Usage of Data Protection From 44126240900d0e728d6b0fd89efcaa08890dd240 Mon Sep 17 00:00:00 2001 From: Al Rodriguez Date: Thu, 26 Mar 2026 17:39:27 -0400 Subject: [PATCH 03/13] Update astro/src/content/docs/identityserver/deployment/index.md Co-authored-by: Maarten Balliauw --- astro/src/content/docs/identityserver/deployment/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astro/src/content/docs/identityserver/deployment/index.md b/astro/src/content/docs/identityserver/deployment/index.md index 89ed37ef..3daf2429 100644 --- a/astro/src/content/docs/identityserver/deployment/index.md +++ b/astro/src/content/docs/identityserver/deployment/index.md @@ -107,7 +107,7 @@ Duende IdentityServer's features that rely on data protection include * protecting [server-side session](/identityserver/ui/server-side-sessions/index.md) data at rest (if enabled) * protecting [the state parameter](/identityserver/ui/login/external.md#state-url-length-and-isecuredataformat) for external OIDC providers (if enabled) -* protecting message payloads sent between pages in the UI (e.g. [logout context](/identityserver/ui/logout/logout-context.md) and [error context](/identityserver/ui/error.md)). +* protecting message payloads sent between pages in the UI (e.g. [logout context](/identityserver/ui/logout/logout-context.md) and [error context](/identityserver/ui/error.md)) * session management (because the ASP.NET Core cookie authentication handler requires it) ## IdentityServer Data Stores From 979f111602811983d1aac702d618402ad97ec7f9 Mon Sep 17 00:00:00 2001 From: Al Rodriguez Date: Thu, 26 Mar 2026 17:39:35 -0400 Subject: [PATCH 04/13] Update astro/src/content/docs/general/data-protection.md Co-authored-by: Maarten Balliauw --- astro/src/content/docs/general/data-protection.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/astro/src/content/docs/general/data-protection.md b/astro/src/content/docs/general/data-protection.md index 3ccbcd42..a0101f6b 100644 --- a/astro/src/content/docs/general/data-protection.md +++ b/astro/src/content/docs/general/data-protection.md @@ -3,7 +3,8 @@ title: Data Protection description: Comprehensive guide covering key aspects of add data protection. date: 2026-03-26T08:20:20+02:00 sidebar: - order: 20 + label: Data Protection + order: 9 redirect_from: - /dataprotection/ --- From 7783faddbe7338075bfaea0c6b644cac28c57673 Mon Sep 17 00:00:00 2001 From: Al Rodriguez Date: Thu, 26 Mar 2026 17:39:44 -0400 Subject: [PATCH 05/13] Update astro/src/content/docs/general/data-protection.md Co-authored-by: Maarten Balliauw --- astro/src/content/docs/general/data-protection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/astro/src/content/docs/general/data-protection.md b/astro/src/content/docs/general/data-protection.md index a0101f6b..afa7c83e 100644 --- a/astro/src/content/docs/general/data-protection.md +++ b/astro/src/content/docs/general/data-protection.md @@ -9,9 +9,9 @@ redirect_from: - /dataprotection/ --- -Any Duende server-side application like IdentityServer of BFF is developed and deployed as an ASP.NET Core application. While there are a lot of decisions to make, this also means that your implementation can be built, deployed, hosted, and managed with the same technology you're using for any other ASP.NET applications you have. +Any Duende server-side application, like IdentityServer or BFF, is developed and deployed as an ASP.NET Core application. While there are a lot of decisions to make, this also means that your implementation can be built, deployed, hosted, and managed with the same technology you're using for any other ASP.NET applications you have. -One important aspect to include in your application is around Data Protection. +It is important to correctly configure ASP.NET Core Data Protection i your application. :::note Some of our most common support requests are related to [Data Protection Keys](#data-protection-keys), so we strongly encourage you to review the rest of this page before deploying to production. From fadf91759ee325b2c182a7d02098295eb9d53fde Mon Sep 17 00:00:00 2001 From: Al Rodriguez Date: Thu, 26 Mar 2026 17:39:51 -0400 Subject: [PATCH 06/13] Update astro/src/content/docs/general/data-protection.md Co-authored-by: Maarten Balliauw --- astro/src/content/docs/general/data-protection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/astro/src/content/docs/general/data-protection.md b/astro/src/content/docs/general/data-protection.md index afa7c83e..3f3fc686 100644 --- a/astro/src/content/docs/general/data-protection.md +++ b/astro/src/content/docs/general/data-protection.md @@ -1,6 +1,6 @@ --- -title: Data Protection -description: Comprehensive guide covering key aspects of add data protection. +title: ASP.NET Core Data Protection +description: Comprehensive guide covering key aspects of ASP.NET Core Data Protection. date: 2026-03-26T08:20:20+02:00 sidebar: label: Data Protection From 1555ed9809633a5abc116d0e689a140194f8baca Mon Sep 17 00:00:00 2001 From: Al Rodriguez Date: Thu, 26 Mar 2026 17:40:03 -0400 Subject: [PATCH 07/13] Update astro/src/content/docs/general/data-protection.md Co-authored-by: Maarten Balliauw --- astro/src/content/docs/general/data-protection.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/astro/src/content/docs/general/data-protection.md b/astro/src/content/docs/general/data-protection.md index 3f3fc686..eda79528 100644 --- a/astro/src/content/docs/general/data-protection.md +++ b/astro/src/content/docs/general/data-protection.md @@ -87,8 +87,8 @@ that allow client applications and APIs to trust those tokens. ## Common Problems Common data protection problems occur when data is protected with a key that is not available when the data is later -read. A common symptom is `CryptographicException`s in the application logs. For example, when automatic key -management fails to read its signing keys due to a data protection failure, IdentityServer will log an error message +read. A common symptom is `CryptographicException`s in the application logs. For example, when IdentityServer's automatic key +management fails to read its signing keys due to a data protection failure, it will log an error message such as "Error unprotecting key with kid {Signing Key ID}.", and log the underlying `System.Security.Cryptography.CryptographicException`, with a message like "The key {Data Protection Key ID} was not found in the key ring." From 352d9ac7b4a7d1bf9af18ff00d4e322ce19886dd Mon Sep 17 00:00:00 2001 From: Al Rodriguez Date: Thu, 26 Mar 2026 17:40:11 -0400 Subject: [PATCH 08/13] Update astro/src/content/docs/general/data-protection.md Co-authored-by: Maarten Balliauw --- astro/src/content/docs/general/data-protection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astro/src/content/docs/general/data-protection.md b/astro/src/content/docs/general/data-protection.md index eda79528..ccfee89b 100644 --- a/astro/src/content/docs/general/data-protection.md +++ b/astro/src/content/docs/general/data-protection.md @@ -114,7 +114,7 @@ There are several ways that data protection problems can occur: always to specify an explicit application name, and if you have old keys that were generated without an explicit application name, you need to set your application name to match the default behavior that produced the keys you want to be able to read. -4. If your IdentityServer is hosted by IIS, special configuration is needed for data protection. In most default +4. If you host on IIS, special configuration is needed for data protection. In most default deployments, IIS lacks the permissions required to persist data protection keys, and falls back to using an ephemeral key generated every time the site starts up. Microsoft's docs on this issue are [here](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/advanced?view=aspnetcore-7.0#data-protection). From 033acdb075cb84bac3d1ae5addbf3be19825d376 Mon Sep 17 00:00:00 2001 From: Al Rodriguez Date: Tue, 31 Mar 2026 11:21:49 -0400 Subject: [PATCH 09/13] Update astro/src/content/docs/general/data-protection.md Co-authored-by: Maarten Balliauw --- astro/src/content/docs/general/data-protection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astro/src/content/docs/general/data-protection.md b/astro/src/content/docs/general/data-protection.md index ccfee89b..2d46f96a 100644 --- a/astro/src/content/docs/general/data-protection.md +++ b/astro/src/content/docs/general/data-protection.md @@ -13,7 +13,7 @@ Any Duende server-side application, like IdentityServer or BFF, is developed and It is important to correctly configure ASP.NET Core Data Protection i your application. -:::note +:::tip Some of our most common support requests are related to [Data Protection Keys](#data-protection-keys), so we strongly encourage you to review the rest of this page before deploying to production. ::: From f14ec709dd715d679ba23ca144a9862139b2debd Mon Sep 17 00:00:00 2001 From: Al Rodriguez Date: Tue, 31 Mar 2026 11:33:55 -0400 Subject: [PATCH 10/13] Update astro/src/content/docs/general/data-protection.md Co-authored-by: Wesley Cabus --- astro/src/content/docs/general/data-protection.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astro/src/content/docs/general/data-protection.md b/astro/src/content/docs/general/data-protection.md index 2d46f96a..d1a783ab 100644 --- a/astro/src/content/docs/general/data-protection.md +++ b/astro/src/content/docs/general/data-protection.md @@ -11,7 +11,7 @@ redirect_from: Any Duende server-side application, like IdentityServer or BFF, is developed and deployed as an ASP.NET Core application. While there are a lot of decisions to make, this also means that your implementation can be built, deployed, hosted, and managed with the same technology you're using for any other ASP.NET applications you have. -It is important to correctly configure ASP.NET Core Data Protection i your application. +It is important to correctly configure ASP.NET Core Data Protection in your application. :::tip Some of our most common support requests are related to [Data Protection Keys](#data-protection-keys), so we strongly encourage you to review the rest of this page before deploying to production. From 6ce179c004c7bd2ff6e9e93e35f19be02222a196 Mon Sep 17 00:00:00 2001 From: AL Rodriguez Date: Tue, 31 Mar 2026 14:26:57 -0400 Subject: [PATCH 11/13] Moved some of the Data Protection content back to the IdentityServer page, specifically the IdentityServer specific content. Also some rewording for simplicity or spelling fixes. --- .../content/docs/general/data-protection.md | 52 +++---------------- .../docs/identityserver/deployment/index.md | 44 ++++++++++++---- 2 files changed, 42 insertions(+), 54 deletions(-) diff --git a/astro/src/content/docs/general/data-protection.md b/astro/src/content/docs/general/data-protection.md index d1a783ab..ad1c19f0 100644 --- a/astro/src/content/docs/general/data-protection.md +++ b/astro/src/content/docs/general/data-protection.md @@ -24,8 +24,8 @@ Data Protection in any Duende server-side application makes extensive use of ASP In local development, ASP.NET automatically creates data protection keys, but in a deployed environment, you will need to ensure that your data protection keys are stored in a persistent way and shared across all load balanced instances of your implementation. This means you'll need to choose where to store and how to protect the data -protection keys, as appropriate for your environment. Microsoft has extensive -documentation [here](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview) +protection keys, as appropriate for your environment. Microsoft has [extensive +documentation](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview) describing how to configure storage and protection of data protection keys. A typical implementation should include data protection configuration code, like this: @@ -48,41 +48,17 @@ builder.Services.AddDataProtection() :::danger[Ensure data protection keys are persisted] Always make sure data protection is configured to persist data protection keys to storage, using `.PersistKeys...()` -for your storage mechanism. +for your storage mechanism. If you lose your data protection keys, all data protected with those keys is no longer be readable. -In addition, make sure the storage mechanism itself is durable. For example, if you are using the default file system +Additionally ensure the storage mechanism itself is durable. For example, if you are using the default file system based key store, make sure that the configured path is not stored on ephemeral storage. If you are using Redis to store -data protection keys using `PersistKeysToStackExchangeRedis`, ensure that your Redis service is configured to persist -data to a database backup or append-only file. Otherwise, when your Redis instance reboots, you will lose all data -protection keys. +data protection keys using `PersistKeysToStackExchangeRedis()`, ensure that your Redis service is configured to persist +data to a database backup or append-only file. Otherwise you will lose all data +protection keys when your Redis instance reboots. -If you lose your data protection keys, all data protected with those keys is no longer be readable. +For a more advanced setup, you can create a [key escrow sink](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/extensibility/key-management?view=aspnetcore-10.0#xmlkeymanager), allowing you to store new data protection keys into a secure storage (e.g., Azure Key Vault) before the new keys are encrypted. This enables you to restore existing data protection keys in case they become corrupted or lost. ::: -## ASP.NET Data Protection Keys and IdentityServer Signing Keys - -ASP.NET's data protection keys are sometimes confused with IdentityServer's signing keys, but the two are completely -separate keys with different purposes. IdentityServer implementations need both to function correctly. - -### ASP.NET Data Protection Keys - -Data protection is a cryptographic library that is part of ASP.NET Core. Data protection uses private key -cryptography to encrypt and sign sensitive data to ensure that it is only written and read by the application. The -framework uses data protection to secure data that is commonly used by IdentityServer implementations, such as -authentication cookies and anti-forgery tokens. In addition, IdentityServer itself uses data protection to protect -sensitive data at rest, such as persisted grants, and sensitive data passed through the browser, such as the -context objects passed to pages in the UI. The data protection keys are critical secrets for an IdentityServer -implementation because they encrypt a great deal of sensitive data at rest and prevent sensitive data that is -round-tripped through the browser from being tampered with. - -### The IdentityServer Signing Key - -Separately, IdentityServer needs cryptographic keys, called [signing keys](/identityserver/fundamentals/key-management.md), to -sign tokens such as JWT access tokens and id tokens. The signing keys use public key cryptography to allow client -applications and APIs to validate token signatures using the public keys, which are published by IdentityServer -through [discovery](/identityserver/reference/endpoints/discovery.md). The private key component of the signing keys are -also critical secrets for IdentityServer because a valid signature provides integrity and non-repudiation guarantees -that allow client applications and APIs to trust those tokens. ## Common Problems @@ -119,15 +95,3 @@ There are several ways that data protection problems can occur: key generated every time the site starts up. Microsoft's docs on this issue are [here](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/advanced?view=aspnetcore-7.0#data-protection). -### Identity Server's Usage of Data Protection - -Duende IdentityServer's features that rely on data protection include - -* protecting signing keys at rest (if [automatic key management](/identityserver/fundamentals/key-management.md#automatic-key-management) is used and enabled) -* protecting [persisted grants](/identityserver/data/operational.md#persisted-grant-service) at rest (if enabled) -* protecting [server-side session](/identityserver/ui/server-side-sessions/index.md) data at rest (if enabled) -* protecting [the state parameter](/identityserver/ui/login/external.md#state-url-length-and-isecuredataformat) for - external OIDC providers (if enabled) -* protecting message payloads sent between pages in the UI ( - e.g. [logout context](/identityserver/ui/logout/logout-context.md) and [error context](/identityserver/ui/error.md)). -* session management (because the ASP.NET Core cookie authentication handler requires it) diff --git a/astro/src/content/docs/identityserver/deployment/index.md b/astro/src/content/docs/identityserver/deployment/index.md index 3daf2429..5659546c 100644 --- a/astro/src/content/docs/identityserver/deployment/index.md +++ b/astro/src/content/docs/identityserver/deployment/index.md @@ -97,20 +97,32 @@ crucial that you configure data protection correctly before you start using your The recommended practices for setting up and using ASP.NET Core Data Protection for Duende IdentityServer are the same as for other server-side products, like BFF. See the [general ASP.NET Core Data Protection page](/general/data-protection). +### ASP.NET Data Protection Keys and IdentityServer Signing Keys -### Identity Server's Usage of Data Protection +ASP.NET's data protection keys are sometimes confused with IdentityServer's signing keys, but the two are completely +separate keys with different purposes. IdentityServer implementations need both to function correctly. -Duende IdentityServer's features that rely on data protection include +#### ASP.NET Data Protection Keys -* protecting signing keys at rest (if [automatic key management](/identityserver/fundamentals/key-management.md#automatic-key-management) is used and enabled) -* protecting [persisted grants](/identityserver/data/operational.md#persisted-grant-service) at rest (if enabled) -* protecting [server-side session](/identityserver/ui/server-side-sessions/index.md) data at rest (if enabled) -* protecting [the state parameter](/identityserver/ui/login/external.md#state-url-length-and-isecuredataformat) for - external OIDC providers (if enabled) -* protecting message payloads sent between pages in the UI (e.g. [logout context](/identityserver/ui/logout/logout-context.md) and [error context](/identityserver/ui/error.md)) -* session management (because the ASP.NET Core cookie authentication handler requires it) +Data protection is a cryptographic library that is part of ASP.NET Core. Data protection uses private key +cryptography to encrypt and sign sensitive data to ensure that it is only written and read by the application. The +framework uses data protection to secure data that is commonly used by IdentityServer implementations, such as +authentication cookies and anti-forgery tokens. In addition, IdentityServer itself uses data protection to protect +sensitive data at rest, such as persisted grants, and sensitive data passed through the browser, such as the +context objects passed to pages in the UI. The data protection keys are critical secrets for an IdentityServer +implementation because they encrypt a great deal of sensitive data at rest and prevent sensitive data that is +round-tripped through the browser from being tampered with. + +#### The IdentityServer Signing Key -## IdentityServer Data Stores +Separately, IdentityServer needs cryptographic keys, called [signing keys](/identityserver/fundamentals/key-management.md), to +sign tokens such as JWT access tokens and id tokens. The signing keys use public key cryptography to allow client +applications and APIs to validate token signatures using the public keys, which are published by IdentityServer +through [discovery](/identityserver/reference/endpoints/discovery.md). The private key component of the signing keys are +also critical secrets for IdentityServer because a valid signature provides integrity and non-repudiation guarantees +that allow client applications and APIs to trust those tokens. + +### IdentityServer Data Stores IdentityServer itself is stateless and does not require server affinity - but there is data that needs to be shared between in multi-instance deployments. @@ -135,6 +147,18 @@ You can either use a traditional database for storing operational data, or use a Duende IdentityServer includes storage implementations for above data using EntityFramework, and you can build your own. See the [data stores](/identityserver/data) section for more information. +### IdentityServer Features Using Data Protection + +Duende IdentityServer's features that rely on data protection include: + +* protecting signing keys at rest (if [automatic key management](/identityserver/fundamentals/key-management.md#automatic-key-management) is used and enabled) +* protecting [persisted grants](/identityserver/data/operational.md#persisted-grant-service) at rest (if enabled) +* protecting [server-side session](/identityserver/ui/server-side-sessions/index.md) data at rest (if enabled) +* protecting [the state parameter](/identityserver/ui/login/external.md#state-url-length-and-isecuredataformat) for + external OIDC providers (if enabled) +* protecting message payloads sent between pages in the UI (e.g. [logout context](/identityserver/ui/logout/logout-context.md) and [error context](/identityserver/ui/error.md)). +* session management (because the ASP.NET Core cookie authentication handler requires it) + ## Distributed Caching Some optional features rely on ASP.NET Core distributed caching: From 22d9998e09c2d0f6216f7dfc4f71c2a41bdb072e Mon Sep 17 00:00:00 2001 From: Wesley Cabus Date: Wed, 1 Apr 2026 14:25:07 +0200 Subject: [PATCH 12/13] Some formatting and rewording --- .../content/docs/general/data-protection.md | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/astro/src/content/docs/general/data-protection.md b/astro/src/content/docs/general/data-protection.md index ad1c19f0..6014bb91 100644 --- a/astro/src/content/docs/general/data-protection.md +++ b/astro/src/content/docs/general/data-protection.md @@ -47,27 +47,27 @@ builder.Services.AddDataProtection() ``` :::danger[Ensure data protection keys are persisted] -Always make sure data protection is configured to persist data protection keys to storage, using `.PersistKeys...()` +Always make sure data protection is configured to persist data protection keys to storage, using `.PersistKeysTo...()` for your storage mechanism. If you lose your data protection keys, all data protected with those keys is no longer be readable. -Additionally ensure the storage mechanism itself is durable. For example, if you are using the default file system +Additionally, ensure the storage mechanism itself is durable. For example, if you are using the default file system based key store, make sure that the configured path is not stored on ephemeral storage. If you are using Redis to store data protection keys using `PersistKeysToStackExchangeRedis()`, ensure that your Redis service is configured to persist -data to a database backup or append-only file. Otherwise you will lose all data -protection keys when your Redis instance reboots. +data to a database backup or append-only file. Otherwise, you will lose all data protection keys when your Redis instance reboots. -For a more advanced setup, you can create a [key escrow sink](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/extensibility/key-management?view=aspnetcore-10.0#xmlkeymanager), allowing you to store new data protection keys into a secure storage (e.g., Azure Key Vault) before the new keys are encrypted. This enables you to restore existing data protection keys in case they become corrupted or lost. +For a more advanced setup, you can create a [key escrow sink](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/extensibility/key-management?view=aspnetcore-10.0#xmlkeymanager), allowing you to store new data protection keys into +a secure storage (e.g., Azure Key Vault) before the new keys are encrypted. +This enables you to restore existing data protection keys in case they become corrupted or lost. ::: - ## Common Problems Common data protection problems occur when data is protected with a key that is not available when the data is later read. A common symptom is `CryptographicException`s in the application logs. For example, when IdentityServer's automatic key management fails to read its signing keys due to a data protection failure, it will log an error message -such as "Error unprotecting key with kid {Signing Key ID}.", and log the underlying -`System.Security.Cryptography.CryptographicException`, with a message like "The key {Data Protection Key ID} was not -found in the key ring." +such as `"Error unprotecting key with kid {Signing Key ID}."`, and log the underlying +`System.Security.Cryptography.CryptographicException`, with a message like `"The key {Data Protection Key ID} was not +found in the key ring."` Failures to read automatic signing keys are often the first place where a data protection problem manifests, but any of many places where ASP.NET uses data protection might also throw `CryptographicException`s. @@ -82,16 +82,14 @@ There are several ways that data protection problems can occur: directory from source control and make sure keys are not included in your builds. Note that if you are using our Entity Framework based implementation of the operational data stores, then the keys will instead be stored in the database. -3. Data protection creates keys isolated by application name. If you don't specify a name, the content root path of the - application will be used. But, beginning in .NET 6.0 Microsoft changed how they handle the path, which can cause data - protection keys to break. Their docs on the problem - are [here](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview#setapplicationname), - including a work-around where you de-normalize the path. Then, in .NET 7.0, this change was reverted. The solution is - always to specify an explicit application name, and if you have old keys that were generated without an explicit - application name, you need to set your application name to match the default behavior that produced the keys you want - to be able to read. -4. If you host on IIS, special configuration is needed for data protection. In most default - deployments, IIS lacks the permissions required to persist data protection keys, and falls back to using an ephemeral - key generated every time the site starts up. Microsoft's docs on this issue - are [here](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/advanced?view=aspnetcore-7.0#data-protection). +3. Data protection derives keys isolated per application name from the generated key material. If you don't specify a name, + the content root path of the application will be used. In .NET 6.0, Microsoft introduced a breaking change: they changed + how ASP.NET Core sets the content root path, which can cause Data Protection issues. This change was reverted in .NET 7.0, + and Microsoft has [documented a workaround in case your application has to restore the correct application name](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview#set-the-application-name-setapplicationname). + A better solution is to always specify an explicit application name, but know that changing the application name will + cause all existing data protected with the previous application name to become unreadable. +4. When hosting your web application on Microsoft IIS, [special configuration may be required for data protection](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/advanced#data-protection). + In most default deployments, IIS falls back to using an ephemeral storage for data protection keys, which means that + new keys are generated every time the application pool restarts. We recommend storing data protection keys in a shared location, + such as a protected file share or database, and configuring IIS to use that location for data protection. From 69a512438e502cae0eb3d87d763db9c140807664 Mon Sep 17 00:00:00 2001 From: AL Rodriguez Date: Wed, 1 Apr 2026 09:13:10 -0400 Subject: [PATCH 13/13] Added changes from PR suggestions --- astro/src/content/docs/general/data-protection.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/astro/src/content/docs/general/data-protection.md b/astro/src/content/docs/general/data-protection.md index 6014bb91..befb8803 100644 --- a/astro/src/content/docs/general/data-protection.md +++ b/astro/src/content/docs/general/data-protection.md @@ -14,18 +14,18 @@ Any Duende server-side application, like IdentityServer or BFF, is developed and It is important to correctly configure ASP.NET Core Data Protection in your application. :::tip -Some of our most common support requests are related to [Data Protection Keys](#data-protection-keys), so we strongly encourage you to review the rest of this page before deploying to production. +Some of our most common support requests are related to [Data Protection Keys](#data-protection-keys). We strongly encourage you to review the rest of this page before deploying to production. ::: -## ASP.NET Core Data Protection +## About ASP.NET Core Data Protection -Data Protection in any Duende server-side application makes extensive use of ASP.NET's [data protection](https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/) feature. It is crucial that you configure data protection correctly before you start using your application in production. +Duende's SDKs, like IdentityServer and BFF, make extensive use of ASP.NET's [data protection](https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/) feature. It is crucial that you configure data protection correctly when deploying your application in production. In local development, ASP.NET automatically creates data protection keys, but in a deployed environment, you will need to ensure that your data protection keys are stored in a persistent way and shared across all load balanced instances of your implementation. This means you'll need to choose where to store and how to protect the data protection keys, as appropriate for your environment. Microsoft has [extensive -documentation](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview) +documentation on data protection](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview) describing how to configure storage and protection of data protection keys. A typical implementation should include data protection configuration code, like this: