fusionauth logo
search-interface-symbol
Quickstarts
API Docs
SDK
search-interface-symbol
talk to an expert
Log In
talk to an expert
Navigate to...
  • Welcome
  • Getting Started
    • Getting Started
    • 5-minute Setup Guide
      • Overview
      • Docker
      • Fast Path
      • Sandbox
    • Setup Wizard & First Login
    • Register a User and Login
    • Self-service Registration
    • Start and Stop FusionAuth
    • Core Concepts
      • Overview
      • Users
      • Roles
      • Groups
      • Registrations
      • Applications
      • Tenants
      • Identity Providers
      • Authentication/Authorization
      • Integration Points
    • Example Apps
      • Overview
      • Dart
      • Go
      • Java
      • JavaScript
      • .NET Core
      • PHP
      • Python
      • Ruby
    • Tutorials
      • Overview
      • Java Spring
      • Python Django
      • Ruby on Rails
  • Installation Guide
    • Overview
    • System Requirements
    • Server Layout
    • Cloud
    • Cluster
    • Docker
    • Fast Path
    • Kubernetes
      • Overview
      • Deployment Guide
      • Minikube Setup
      • Amazon EKS Setup
      • Google GKE Setup
      • Microsoft AKS Setup
    • Kickstart™
    • Homebrew
    • Marketplaces
    • Packages
    • Database
    • FusionAuth App
    • FusionAuth Search
    • Common Configuration
  • Migration Guide
    • Overview
    • General
    • Auth0
    • Keycloak
    • Amazon Cognito
    • Firebase
    • Microsoft Azure AD B2C
    • Tutorial
  • Admin Guide
    • Overview
    • Account Portal
    • Config Management
    • Editions and Features
    • Key Rotation
    • Licensing
    • Monitoring
    • Prometheus Setup
    • Proxy Setup
    • Reference
      • Overview
      • Configuration
      • CORS
      • Data Types
      • Hosted Login Pages Cookies
      • Known Limitations
      • Password Hashes
    • Releases
    • Roadmap
    • Search And FusionAuth
    • Securing
    • Switch Search Engines
    • Technical Support
    • Troubleshooting
    • Upgrading
    • WebAuthn
  • Login Methods
    • Identity Providers
      • Overview
      • Apple
      • Epic Games
      • External JWT
        • Overview
        • Example
      • Facebook
      • Google
      • HYPR
      • LinkedIn
      • Nintendo
      • OpenID Connect
        • Overview
        • Amazon Cognito
        • Azure AD
        • Discord
        • Github
        • Okta
      • Sony PlayStation Network
      • Steam
      • Twitch
      • Twitter
      • SAML v2
        • Overview
        • ADFS
        • Azure AD
        • Okta
      • SAML v2 IdP Initiated
        • Overview
        • Okta
      • Xbox
    • OIDC & OAuth 2.0
      • Overview
      • Endpoints
      • Tokens
      • OAuth Modes
      • URL Validation
    • Passwordless
      • Overview
      • Magic Links
      • WebAuthn & Passkeys
    • SAML v2 IdP
      • Overview
      • Google
      • PagerDuty
      • Tableau Cloud
      • Zendesk
  • Developer Guide
    • Overview
    • API Gateways
      • Overview
      • Amazon API Gateway
      • Kong Gateway
      • ngrok Cloud Edge
    • Client Libraries & SDKs
      • Overview
      • Dart
      • Go
      • Java
      • JavaScript
      • .NET Core
      • Node
      • OpenAPI
      • PHP
      • Python
      • React
      • Ruby
      • Typescript
    • Events & Webhooks
      • Overview
      • Writing a Webhook
      • Securing Webhooks
      • Events
        • Overview
        • Audit Log Create
        • Event Log Create
        • JWT Public Key Update
        • JWT Refresh
        • JWT Refresh Token Revoke
        • Kickstart Success
        • Group Create
        • Group Create Complete
        • Group Delete
        • Group Delete Complete
        • Group Update
        • Group Update Complete
        • Group Member Add
        • Group Member Add Complete
        • Group Member Remove
        • Group Member Remove Complete
        • Group Member Update
        • Group Member Update Complete
        • User Action
        • User Bulk Create
        • User Create
        • User Create Complete
        • User Deactivate
        • User Delete
        • User Delete Complete
        • User Email Update
        • User Email Verified
        • User IdP Link
        • User IdP Unlink
        • User Login Failed
        • User Login Id Dup. Create
        • User Login Id Dup. Update
        • User Login New Device
        • User Login Success
        • User Login Suspicious
        • User Password Breach
        • User Password Reset Send
        • User Password Reset Start
        • User Password Reset Success
        • User Password Update
        • User Reactivate
        • User Reg. Create
        • User Reg. Create Complete
        • User Reg. Delete
        • User Reg. Delete Complete
        • User Registration Update
        • User Reg. Update Complete
        • User Reg. Verified
        • User 2FA Method Add
        • User 2FA Method Remove
        • User Update
        • User Update Complete
    • Guides
      • Overview
      • Application Specific Email Templates
      • Authentication Tokens
      • Exposing A Local Instance
      • JSON Web Tokens
      • Key Master
      • Localization and Internationalization
      • Multi-Factor Authentication
      • Multi-Tenant
      • Passwordless
      • Registration-based Email Verification
      • Searching With Elasticsearch
      • Securing Your APIs
      • Silent Mode
      • Single Sign-on
      • Two Factor (pre 1.26)
    • Integrations
      • Overview
      • CleanSpeak
      • Kafka
      • Twilio
    • Plugins
      • Overview
      • Writing a Plugin
      • Custom Password Hashing
    • User Control & Gating
      • Overview
      • Gate Unverified Users
      • Gate Unverified Registrations
      • User Account Lockout
  • Customization
    • Email & Templates
      • Overview
      • Configure Email
      • Email Templates
      • Email Variables
      • Message Templates
    • Lambdas
      • Overview
      • Apple Reconcile
      • Client Cred. JWT Populate
      • Epic Games Reconcile
      • External JWT Reconcile
      • Facebook Reconcile
      • Google Reconcile
      • HYPR Reconcile
      • JWT Populate
      • LDAP Connector Reconcile
      • LinkedIn Reconcile
      • Nintendo Reconcile
      • OpenID Connect Reconcile
      • SAML v2 Populate
      • SAML v2 Reconcile
      • SCIM Group Req. Converter
      • SCIM Group Resp. Convtr.
      • SCIM User Req. Converter
      • SCIM User Resp. Converter
      • Self-Service Registration
      • Sony PSN Reconcile
      • Steam Reconcile
      • Twitch Reconcile
      • Twitter Reconcile
      • Xbox Reconcile
    • Messengers
      • Overview
      • Generic Messenger
      • Twilio Messenger
    • Themes
      • Overview
      • Examples
      • Helpers
      • Localization
      • Template Variables
      • Kickstart Custom Theme
  • Premium Features
    • Overview
    • Advanced Registration Forms
    • Advanced Threat Detection
    • Application Specific Themes
    • Breached Password Detection
    • Connectors
      • Overview
      • Generic Connector
      • LDAP Connector
      • FusionAuth Connector
    • Entity Management
    • SCIM
      • Overview
      • Azure AD Client
      • Okta Client
      • SCIM-SDK
    • Self Service Account Mgmt
      • Overview
      • Updating User Data & Password
      • Add Two-Factor Authenticator
      • Add Two-Factor Email
      • Add Two-Factor SMS
      • Add WebAuthn Passkey
      • Customizing
      • Troubleshooting
    • WebAuthn
  • APIs
    • Overview
    • Authentication
    • Errors
    • API Explorer
    • Actioning Users
    • API Keys
    • Applications
    • Audit Logs
    • Connectors
      • Overview
      • Generic
      • LDAP
    • Consents
    • Emails
    • Entity Management
      • Overview
      • Entities
      • Entity Types
      • Grants
    • Event Logs
    • Families
    • Forms
    • Form Fields
    • Groups
    • Identity Providers
      • Overview
      • Links
      • Apple
      • External JWT
      • Epic Games
      • Facebook
      • Google
      • HYPR
      • LinkedIn
      • Nintendo
      • OpenID Connect
      • SAML v2
      • SAML v2 IdP Initiated
      • Sony PlayStation Network
      • Steam
      • Twitch
      • Twitter
      • Xbox
    • Integrations
    • IP Access Control Lists
    • JWT
    • Keys
    • Lambdas
    • Login
    • Message Templates
    • Messengers
      • Overview
      • Generic
      • Twilio
    • Multi-Factor/Two Factor
    • Passwordless
    • Reactor
    • Registrations
    • Reports
    • SCIM
      • Overview
      • SCIM User
      • SCIM Group
      • SCIM EnterpriseUser
      • SCIM Service Provider Config.
    • System
    • Tenants
    • Themes
    • Users
    • User Actions
    • User Action Reasons
    • User Comments
    • WebAuthn
    • Webhooks
  • Release Notes

    Key Rotation

    In FusionAuth, there are multiple types of keys, including API keys and JWT signing keys. In addition, the client secret value for your application and entities can be considered a key to be rotated as well.

    Rotating these keys regularly is an important part of a defense-in-depth strategy. Such rotation ensures even if a key is compromised, the length of time it will be useful to attackers is limited. In addition, when you regularly rotate keys, you will necessarily have built systems allowing you to rotate keys at will. This might be a good idea if you suspect an attack or when an employee departs.

    • Types of Keys to Rotate

    • Examples of Key Rotation Processes

      • API Key Rotation

      • JWT Signing Key Rotation

      • Client Secret Rotation

    • Challenges of Key Rotation

      • Ensuring Clients' Keys Are Updated

      • Determining Key Age

      • Updating JWT Signing Key Usage

    Types of Keys to Rotate

    As mentioned above, in FusionAuth, there are multiple kinds of keys: API keys, JWT signing keys, and client secrets. These are used for different purposes.

    API keys manage FusionAuth functionality and are used by scripts or applications to authenticate with FusionAuth and perform actions like adding users or updating tenant configuration. API keys are arbitrary strings. They are managed using the API Keys API or in the Settings → API Keys area of the administrative user interface. You can also learn more about them in the API Key authentication documentation.

    JWT signing keys, on the other hand, are used to sign JSON web tokens (JWTs). These keys are then used by anything consuming the JWT to verify the signature. This assures the consuming application that FusionAuth did indeed sign the token. JWT signing keys are cryptographic keys stored in FusionAuth. They are managed using the Keys API or in the Settings → Key Master area of the administrative user interface. You can also learn more about JWT signing in the JWT expert advice section.

    Client secrets are used by confidential OAuth clients to authenticate with FusionAuth during one of the OAuth grants, such as the authorization code grant or the client credentials grant. They are also used to sign OIDC `id_token`s. If used for user logins, they are managed using the Applications API or in the Applications area of the administrative user interface. If used for entity management and the client credentials grant, they are managed using the Entities API or in the Entity Management → Entities area of the administrative user interface. You can also learn more about client secrets in the OAuth documentation.

    Examples of Key Rotation Processes

    Each type of key has a slightly different rotation process. Rotation steps for time-based rotations are outlined below.

    If you suspect or know of a key compromise, the criteria of whether to rotate a key changes, but the rotation steps are the same.

    API Key Rotation

    Suppose you are using API key A to manage a FusionAuth instance. To rotate this API key, you need to perform the following steps.

    • Find information about key A, including when it was created and what its Id is.

    • Determine how long it has been in use. If it has been in use long enough to rotate, proceed. Otherwise ignore it.

    • Create a new key, B with identical permissions to A. This ensures continuity of access.

    • Store off all needed metadata for key B, including when it was brought into service.

    • Update all applications, scripts and programs which use key A to use key B.

    • Remove key A.

    JWT Signing Key Rotation

    In contrast, suppose you are rotating a JWT signing key, JS1. To rotate such a key, follow these steps:

    • Find information about key JS1, including when it was created and what its Id is.

    • Determine how long it has been in use. If it has been in use long enough to rotate, proceed. Otherwise ignore it.

    • Create a new key, JS2. You typically want to ensure JS2 uses the same algorithm and length as JS1.

    • Store off all needed metadata for key JS2, including when it was brought into service.

    • Update the FusionAuth configuration to ensure that JS2 is used for all applications and tenants for which JS1 was used.

    • Wait until all keys signed by JS1 have expired. The exact length of time depends on your configured JWT lifetime. For instance, if your JWTs last for five minutes, wait for ten minutes to allow for clock skew.

    • Delete key JS1.

    In this case, FusionAuth is assumed to be the only process that is using JS1 or JS2. If there are external dependencies (for example, if the JS1 and JS2 keys are RSA asymmetric keys and the private keys are externally managed or need to be synced with other software), then the process gets a little more complicated.

    You need to import the key, instead of create it, and update other systems which use JS1 to use JS2.

    To handle the scenario where JS2 needs to be imported to FusionAuth:

    • Determine it is time to rotate JS1.

    • Import a new key, JS2.

    • Update the FusionAuth configuration to ensure that JS2 is used for all applications and tenants for which JS1 was used.

    • Update any other pieces of software which use JS1 to use JS2.

    • Wait until all keys signed by JS1 have expired. The exact length of time depends on your configured JWT lifetime. For instance, if your JWTs last for five minutes, wait for ten minutes to allow for clock skew.

    • Delete key JS1.

    • Note when JS2 entered into service.

    Client Secret Rotation

    Suppose you are using client secret A for an application. The application uses the authorization code grant. To rotate this client secret, you need to perform the following steps.

    • Find information about A, including when the FusionAuth Application was configured to use it and what that corresponding Application Id is.

    • Determine how long it has been in use. If it has been in use long enough to rotate, proceed. Otherwise ignore it.

    • Create a new random string, B. In general, this string should be high entropy and long enough to be a good candidate for an HMAC secret. This is because a client secret may be part of the process to sign an id_token. See the OIDC specification for more.

    • Store off all needed metadata for key B, including when the application was updated to use it.

    • Update all web applications, mobile applications, scripts and programs which use client secret A to use B.

    • Update the correct FusionAuth Application configuration. Use PATCH or PUT to update the application.oauthConfiguration.clientSecret value.

    Challenges of Key Rotation

    There are a couple of challenges when implementing key rotation in FusionAuth.

    Ensuring Clients' Keys Are Updated

    First, you want to ensure that no valid client is using an old API key before you delete it. Deleting a key while it is still in use will cause other software using that key to fail and be denied access. You have a couple of options to avoid this:

    • Use a central secrets repository. If all software pulls any required keys from a central secrets repository such as AWS Secrets Manager or Heroku environment variables, then you update the key in only one place. However, implementation of centralized application secrets is beyond the scope of this document.

    • Automate the pushing of secrets to all clients that need the key.

    • Allow for a grace period to allow clients to update their key before deleting it.

    For client secrets, this problem is magnified because while you can have multiple API keys, you cannot have multiple client secrets for any given application or entity. In this case, you may be able work around this by having your client support multiple different client secrets and trying them in sequence. There’s also an open issue to have FusionAuth support a grace period for client secrets.

    This problem doesn’t arise in the same manner for JWT signing keys because they have a built in grace period: the expiration of the JWTs. You can definitely cause issues by removing a JWT signing key before all the keys it has signed have expired, but because JWT signing keys are only used by FusionAuth to sign JWTs and have a built-in expiration time, it is easy to use the grace period option above.

    Determining Key Age

    Another challenge is determining when a key should be rotated.

    You currently don’t have the ability to search for a key by creation instant.

    Therefore, you must store the creation and age data separately. To be able to rotate keys, store the following attributes:

    • id. This is the identifier of the key and is used to manipulate and delete keys via the API.

    • inserted. The instant when the key was created.

    • expires. The instant when the key expires. Storing this value allows different keys to be valid for different durations.

    • deleteAfter. The instant after which this key should be removed. This value may be the same as the expires value. Having this value be after the expires instant is useful as a grace period during which the key shouldn’t be used, but will still work.

    You can either store this information in an external datastore or in a FusionAuth data field. For the latter option, store the information in JSON, on an object like the tenant, a specific user, or an entity. The latter two options are good choices when you are using the Elasticsearch search engine because you can then leverage the respective Search APIs, as the data field is indexed. This allows you to keep everything contained within FusionAuth.

    Here’s an example of what that data might look like.

    Storing key rotation data
    
    {
      "apikeys" : [
        {
          "id" : "41e6deca-0e39-46e7-804b-68b0bc94a761",
          "inserted" : 1628022201033,
          "expires" : 1628022205033,
          "deleteAfter" : 1628022208033
        },
        {
          "id" : "5b56deca-0e39-46e7-804b-68b0bc94a981",
          "inserted" : 1628022202033,
          "expires" : 1628022207033,
          "deleteAfter" : 1628022209033
        }
      ]
    }

    At regular intervals, perhaps run by cron or another scheduling program, a rotation script or program:

    • Notes the current time.

    • Retrieves the entire data structure.

    • Walks it. For each entry:

      • Sees if the key has a deleteAfter value before the current time. If so, delete the key.

      • Checks if the key has an expires value before the current time. These are expired keys.

      • If a key is expired, create a new key to replace it.

      • Push the new key to the secrets manager or otherwise notify clients that rotation has occurred.

      • Marks the expired key for deletion by setting the deleteAfter attribute to the correct value.

    As mentioned above, rather than use a FusionAuth data field, you could also use a table in a relational database or other datastore to store key metadata.

    Updating JWT Signing Key Usage

    Another challenge particular to JWT signing keys is finding all the locations where the expired key is used.

    The easiest way to do this is to retrieve all Tenant and Application objects and look for the key Id. Here are the configuration locations to examine:

    • tenant.jwtConfiguration.accessTokenKeyId

    • tenant.jwtConfiguration.idTokenKeyId

    • application.jwtConfiguration.accessTokenKeyId

    • application.jwtConfiguration.idTokenKeyId

    Each of the above configuration objects must be modified to use the new key, rather than the expired one.

    Feedback

    How helpful was this page?

    See a problem?

    File an issue in our docs repo

    Have a question or comment to share?

    Visit the FusionAuth community forum.

    © 2023 FusionAuth
    How-to
    Blog
    Expert Advice
    Download
    Subscribe for developer updates