Skip to content

Keys rotation

The IdentityServer:Key section configure the signing key using Aguacongas.IdentityServer.KeysRotation.
To use the keys rotation mechanism, the Type must be KeysRotation.

minimum configuration sample

"IdentityServer": {
  "Key": {
    "Type": "KeysRotation",
    "StorageKind": "EntityFramework"
  }
}

full configuration sample

"IdentityServer": {
  "Key": {
    "Type": "KeysRotation",
    "StorageKind": "Redis",
    "StorageConnectionString": "localhost:6379",
    "KeyProtectionOptions": {
      "KeyProtectionKind": "X509",
      "X509CertificatePath": "C:\\certificates\\theidserver.pfx",
      "X509CertificatePassword": "P@ssw0rd"
    },
    "KeyRotationOptions": {
      "AutoGenerateKeys": true,
      "NewKeyLifetime": "90.00:00:00",
      "KeyPropagationWindow": "14.00:00:00",
      "MaxServerClockSkew": "00:05:00",
      "KeyRingRefreshPeriod": "24:00:00"
    },
    "RsaEncryptorConfiguration": {
      "EncryptionAlgorithmKeySize": 2048,
      "SigningAlgorithm": "RS256",
      "KeyIdSize": 128,
      "KeyRetirement": "180.00:00:00"
    },
    "AdditionalSigningKeyType": {
      "RS384": {
        "EncryptionAlgorithmKeySize": 2048,
        "SigningAlgorithm": "RS384",
        "KeyIdSize": 128,
        "KeyRetirement": "180.00:00:00"
      },
      "RS512": {
        "EncryptionAlgorithmKeySize": 2048,
        "SigningAlgorithm": "RS512",
        "KeyIdSize": 128,
        "KeyRetirement": "180.00:00:00"
      },
      "PS256": {
        "EncryptionAlgorithmKeySize": 2048,
        "SigningAlgorithm": "PS256",
        "KeyIdSize": 128,
        "KeyRetirement": "180.00:00:00"
      },
      "PS384": {
        "EncryptionAlgorithmKeySize": 2048,
        "SigningAlgorithm": "PS384",
        "KeyIdSize": 128,
        "KeyRetirement": "180.00:00:00"
      },
      "PS512": {
        "EncryptionAlgorithmKeySize": 2048,
        "SigningAlgorithm": "PS512",
        "KeyIdSize": 128,
        "KeyRetirement": "180.00:00:00"
      },
      "ES256": {
        "EncryptionAlgorithmKeySize": 521,
        "SigningAlgorithm": "ES256",
        "KeyIdSize": 128,
        "KeyRetirement": "180.00:00:00"
      },
      "ES384": {
        "EncryptionAlgorithmKeySize": 521,
        "SigningAlgorithm": "ES384",
        "KeyIdSize": 128,
        "KeyRetirement": "180.00:00:00"
      },
      "ES512": {
        "EncryptionAlgorithmKeySize": 521,
        "SigningAlgorithm": "ES512",
        "KeyIdSize": 128,
        "KeyRetirement": "180.00:00:00"
      }
    }
  }
}

Storages

  • StorageKind defines the storage kind to use.
  • StorageConnectionString defines how to access the storage.

The configuration support all Key storage providers except Registry because it's a Windows only store.

File system

  "StorageKind": "FileSytem",
  "StorageConnectionString": "C:\\data-protection-keys",

For FileSytem storage kind, the StorageConnectionString defines the path where to store keys.

Azure Storage

  "StorageKind": "AzureStorage",
  "StorageConnectionString": "<blob URI including SAS token>",

For AzureStorage storage kind, the StorageConnectionString defines the blog URI including SAS token where to store keys.

Redis

  "StorageKind": "Redis",
  "StorageConnectionString": "localhost:6379",
  "RedisKey": "KeysRotation-Keys"

For Redis storage kind, the StorageConnectionString defines the redis connection string.
(optional) RedisKey defines the redis list key where to store generated keys.

Entity Framework Core

  "StorageKind": "EntityFramework"

For EntityFramework storage king, keys are store in the KeyRotationKeys table of TheIdServer database

RavenDb

  "StorageKind": "RavenDb"

For RavenDb storage king, keys are store in the KeyRotationKeys documents of RavenDb database

MongoDb

  "StorageKind": "MongoDb"

For MongoDb storage king, keys are store in the KeyRotationKeys collection of MongoDb database

Key protection

KeyProtectionOptions controls Key encryption at rest configuration.

  • KeyProtectionKind defines the kind of key protection to use.

Azure Key Vault

⚠️ Important Update: TheIdServer now uses the modern Azure.Security.KeyVault.Keys SDK. The old Microsoft.Azure.KeyVault SDK is obsolete.

The simplest configuration. Works with Managed Identity in production and Azure CLI in development:

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://your-vault.vault.azure.net/keys/key-name"
  }

This automatically uses:
- Managed Identity when running on Azure
- Azure CLI credentials when developing locally (after az login)
- Visual Studio credentials when debugging
- Environment variables for CI/CD pipelines

Option 2: Service Principal with Client Secret

For explicit authentication with Service Principal:

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://your-vault.vault.azure.net/keys/key-name",
    "AzureKeyVaultTenantId": "your-tenant-id",
    "AzureKeyVaultClientId": "your-client-id",
    "AzureKeyVaultClientSecret": "your-client-secret"
  }

⚠️ Note: AzureKeyVaultTenantId is now required when using ClientId and ClientSecret (previously optional).

Option 3: Service Principal with Certificate

More secure than client secrets:

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://your-vault.vault.azure.net/keys/key-name",
    "AzureKeyVaultTenantId": "your-tenant-id",
    "AzureKeyVaultClientId": "your-client-id",
    "AzureKeyVaultCertificateThumbprint": "certificate-thumbprint"
  }

The certificate must be installed in the certificate store (CurrentUser\My or LocalMachine\My).

Option 4: User-Assigned Managed Identity

For Azure resources with user-assigned Managed Identity:

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://your-vault.vault.azure.net/keys/key-name",
    "AzureKeyVaultManagedIdentityClientId": "managed-identity-client-id"
  }

Configuration by Environment

Recommended approach for multiple environments:

appsettings.json (base):

{
  "IdentityServer": {
    "Key": {
      "Type": "KeysRotation",
      "StorageKind": "EntityFramework",
      "KeyProtectionOptions": {
        "KeyProtectionKind": "AzureKeyVault",
        "AzureKeyVaultKeyId": "https://vault.vault.azure.net/keys/key-name"
      }
    }
  }
}

appsettings.Development.json:

{
  "IdentityServer": {
    "Key": {
      "KeyProtectionOptions": {
        "AzureKeyVaultKeyId": "https://dev-vault.vault.azure.net/keys/dev-key"
      }
    }
  }
}

Uses Azure CLI in development.

appsettings.Production.json:

{
  "IdentityServer": {
    "Key": {
      "KeyProtectionOptions": {
        "AzureKeyVaultKeyId": "https://prod-vault.vault.azure.net/keys/prod-key"
      }
    }
  }
}

Uses Managed Identity in production.

Azure Key Vault Permissions

Your identity (Service Principal or Managed Identity) needs these permissions:

  • Get (keys)
  • Wrap Key
  • Unwrap Key

Configure in Azure Portal: Key Vault > Access policies

Migration from Old Configuration

Before (obsolete):

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://vault.vault.azure.net/keys/key-name",
    "AzureKeyVaultClientId": "client-id",
    "AzureKeyVaultClientSecret": "client-secret"
  }

After (add TenantId):

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://vault.vault.azure.net/keys/key-name",
    "AzureKeyVaultTenantId": "tenant-id",
    "AzureKeyVaultClientId": "client-id",
    "AzureKeyVaultClientSecret": "client-secret"
  }

Or better (use DefaultAzureCredential):

  "KeyProtectionOptions": {
    "KeyProtectionKind": "AzureKeyVault",
    "AzureKeyVaultKeyId": "https://vault.vault.azure.net/keys/key-name"
  }

X.509 certificate

From certificate file :

  "KeyProtectionOptions": {
    "KeyProtectionKind": "X509",  
    "X509CertificatePath": "C:\\certificates\\theidserver.pfx",
    "X509CertificatePassword": "P@ssw0rd"
  }

If the certificate is loaded from a file, it can be selfsigned/seflencrypted and expired.

From certificate thumbprint :

  "KeyProtectionOptions": {
    "KeyProtectionKind": "X509",
    "X509CertificatePath": "3BCE558E2AD3E0E34A7743EAB5AEA2A9BD2575A0"
  }

Using the thumbprint, the certificate must be valid.

Key rotation options

The section KeyRotationOptions congrols key rotation options. It's binded to KeyRotationOptions

    "KeyRotationOptions": {
      "AutoGenerateKeys": true,
      "NewKeyLifetime": "90.00:00:00",
      "KeyPropagationWindow": "14.00:00:00",
      "MaxServerClockSkew": "00:05:00",
      "KeyRingRefreshPeriod": "24:00:00"
    }

Default RSA key generation options

The section RsaEncryptorConfiguration congrols the default RSA key generation options. It's binded to RsaEncryptorConfiguration

    "RsaEncryptorConfiguration": {
      "EncryptionAlgorithmKeySize": 2048,
      "SigningAlgorithm": "RS256",
      "KeyIdSize": 128,
      "KeyRetirement": "180.00:00:00"
    }

Additional key type genration options

The section AdditionalSigningKeyType controls additional key type generation options. It's a dictionary of 'SigningAlgorithmConfiguration` indexed by signing algorithm.

When the key start with a E the encryption algorithm is ECDsa else the encryption algorithm is Rsa.

For exemple if you want to support ES512 and PS384 in addition of the default RS256 algorithm your configuration can look like that:

"IdentityServer": {
  "Key": {
    "Type": "KeysRotation",
    "StorageKind": "EntityFramework",
    "RsaEncryptorConfiguration": {
      "SigningAlgorithm": "RS256"
    },
    "AdditionalSigningKeyType": {
      "PS384": {
        "SigningAlgorithm": "PS384"
      },
      "ES512": {
        "SigningAlgorithm": "ES512"
      }
    }
  }
}

Additional resources

Authors: Olivier Lefebvre