# Harden a FusionAuth Production Instance

Learn which settings to change to secure a FusionAuth instance before it goes into production.

> For the index of this section of the site, see [llms.txt](https://fusionauth.io/docs/llms.txt)

A new FusionAuth instance uses defaults that are convenient for development. Before you put an instance into production, work through the steps on this page. Each step links to the full reference for the setting it changes.

The first section applies to every instance, including FusionAuth Cloud. The second section applies only when you self-host, because FusionAuth Cloud manages that infrastructure for you. See [Who Secures What](https://fusionauth.io/docs/cloud/cloud-vs-self-hosted.md#who-secures-what) for the split.

For a broader checklist to audit against, see the [OWASP Application Security Verification Standard](https://owasp.org/www-project-application-security-verification-standard/).

## Secure Every Instance

These steps change settings in the Admin UI, so they work the same on FusionAuth Cloud and self-hosted instances.

### Protect Admin Accounts

An admin account can change every setting and read every user, so protect these accounts first:

1.  Confirm that the authenticator app method is enabled at Tenants -> Your Tenant -> Multi-Factor . It is enabled on the default Tenant and available on every plan.
2.  Have each administrator [enable MFA on their account](https://fusionauth.io/docs/lifecycle/authenticate-users/multi-factor-authentication.md#enable-mfa-for-a-user).
3.  On the Enterprise plan, set the **On login policy** of the FusionAuth Application to `Required` at Applications -> FusionAuth -> Multi-Factor . This requires MFA for the Admin UI without requiring it for your other Applications.
4.  Give each administrator only the [Admin UI roles](https://fusionauth.io/docs/get-started/core-concepts/types/roles.md#admin-ui-roles) they need. For example, support staff need `user_support_manager`, not `admin`.

### Strengthen Passwords

Configure the password policy at Tenants -> Your Tenant -> Password :

1.  Raise **Minimum length**. The default is `8`. [NIST SP 800-63B](https://pages.nist.gov/800-63-4/sp800-63b.html) recommends at least 15 characters when a password is the only factor. Length helps more than character-type rules, so you can leave those off.
2.  Enable [breached password detection](https://fusionauth.io/docs/operate/secure/breached-password-detection.md) on the Starter plan and above. It rejects passwords that appear in known breaches.
3.  Configure [account lockout](https://fusionauth.io/docs/lifecycle/authenticate-users/setting-up-user-account-lockout.md). FusionAuth counts failed logins by default, but doesn't lock an account until you select a **User action** under **Failed authentication settings**.

To avoid passwords altogether, offer [passkeys](https://fusionauth.io/docs/lifecycle/authenticate-users/passkeys.md).

### Shorten Token and Session Lifetimes

A stolen token works until it expires, so keep lifetimes short. Configure these at the Tenant level, and override them per Application where needed:

1.  Lower **JWT duration** at Tenants -> Your Tenant -> JWT . The default is `3600` seconds. Use the shortest value your applications handle well, such as 5 to 15 minutes.
2.  Set **Refresh token usage** to `One-time use` in the same tab. Each refresh then returns a new refresh token and invalidates the old one, which the [OAuth 2.0 Security Best Current Practice](https://datatracker.ietf.org/doc/html/rfc9700#name-refresh-token-protection) recommends for public clients.
3.  Lower **Refresh token duration** from the default of 30 days if users can sign in more often. Set **Refresh token expiration** to sliding window with a maximum lifetime to keep active users signed in up to a fixed limit.
4.  Review **Session timeout** at Tenants -> Your Tenant -> OAuth . This is how long an [SSO session](https://fusionauth.io/docs/lifecycle/authenticate-users/logout-session-management.md#fusionauth-sso) can be idle. The default is `3600` seconds.

See the [Tenant JWT settings](https://fusionauth.io/docs/get-started/core-concepts/types/tenants.md#jwt) for every option.

### Require PKCE

PKCE stops an intercepted authorization code from being exchanged for tokens. For each Application, set **PKCE** to `Required` at Applications -> Your Application -> OAuth . The default is `Not required`.

If a server-side application can't send a code verifier, use `Not required when using client authentication` for it instead. See [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) for how PKCE works.

### Restrict API Keys

An API Key with no endpoints selected can call every API, so create keys with only the access they need at Settings -> API Keys :

1.  Select only the **Endpoints** and methods the key's consumer calls.
2.  In a multi-tenant instance, select a **Tenant** to limit the key to that Tenant.
3.  Set an **Expiration** for keys that have a limited lifetime.
4.  Set **Retrievable** to `Not Retrievable` so the key value can't be read again after you create it.
5.  On the Enterprise plan, add an **Access Control List** to limit the IP addresses that can use the key.

Store one unrestricted key in a secrets vault for emergencies, and don't use it day to day. See [API Key Permissions](https://fusionauth.io/docs/apis/authentication.md#api-key-permissions) for details, and [Key Rotation](https://fusionauth.io/docs/operate/secure/key-rotation.md) to rotate API Keys and signing keys.

### Monitor Security Events

Send login events to your logging or security monitoring system with a [webhook](https://fusionauth.io/docs/extend/events-and-webhooks.md). Useful events include [user.login.failed](https://fusionauth.io/docs/extend/events-and-webhooks/events/user/login/user-login-failed.md), [user.password.breach](https://fusionauth.io/docs/extend/events-and-webhooks/events/user/password/user-password-breach.md), and on the Enterprise plan, [user.login.suspicious](https://fusionauth.io/docs/extend/events-and-webhooks/events/user/login/user-login-suspicious.md).

When you enable these events at Tenants -> Your Tenant -> Webhooks , set **Transaction setting** to `No Webhooks are required to succeed`. Otherwise an outage in your monitoring system blocks logins. [Sign the webhook](https://fusionauth.io/docs/extend/events-and-webhooks/signing.md) so your receiver can verify each event came from FusionAuth.

The [audit log](https://fusionauth.io/docs/apis/audit-logs.md) records changes made in the Admin UI. Changes made directly with an API Key aren't recorded unless your code adds an entry with the Audit Log API.

### Limit What the Login Pages Reveal

Some hosted page responses reveal whether an account exists, such as the message for a locked account. FusionAuth already avoids this on the forgot password page. See [Account Enumeration](https://fusionauth.io/docs/operate/secure/account-enumeration.md) to decide which responses to change.

## Secure a Self-Hosted Instance

When you self-host, you also secure the network, the database, and the search engine.

```mermaid
graph TD
    client[Browser or app] -->|HTTPS| proxy["`**Reverse proxy**
    TLS, security headers,
    rate limits, Admin UI allowlist`"]
    proxy -->|Private network| fa["`**FusionAuth**
    Trusted proxies,
    production runtime mode`"]
    fa -->|TLS| db[(Database)]
    fa -->|Localhost or private network| search[(Search engine)]
```

Where the self-hosted controls apply. FusionAuth Cloud manages everything except the FusionAuth configuration.

### Put FusionAuth Behind a Proxy

Run FusionAuth behind a [reverse proxy](https://fusionauth.io/docs/operate/deploy/proxy-setup.md), and use the proxy to:

1.  Terminate TLS with TLS 1.2 or later, and redirect HTTP to HTTPS.
2.  Add the [security headers](https://fusionauth.io/docs/operate/deploy/proxy-setup.md#security-headers) that FusionAuth doesn't send.
3.  [Restrict the Admin UI](https://fusionauth.io/docs/operate/deploy/proxy-setup.md#restricting-the-admin-ui) to your administrators' networks.
4.  Rate limit requests per IP address. FusionAuth's own [rate limits](https://fusionauth.io/docs/operate/secure/advanced-threat-detection.md#customizable-rate-limiting) count actions per user, so they don't stop requests that never name a user.

Then [block direct access](https://fusionauth.io/docs/operate/deploy/proxy-setup.md#locking-fusionauth-down) to FusionAuth on port `9011` from everywhere except the proxy.

### Trust Only Your Proxies

FusionAuth reads the client IP address from the `X-Forwarded-For` header. By default it trusts every proxy, so a client can forge the header to change the IP address used for IP ACLs and logs. At Settings -> System -> Networking , set **Trust policy** to `Only Configured` and list your proxy addresses. See [Networking Configuration](https://fusionauth.io/docs/operate/secure/networking.md).

### Secure the Database and Search Engine

The database holds password hashes and personal data, and the search engine holds a copy of user data:

1.  Encrypt the database connection with TLS. See **`database.url`** in the [configuration reference](https://fusionauth.io/docs/reference/configuration.md) for an example.
2.  Give FusionAuth its own database user, and restrict access to the database and its backups. See [Database Access](https://fusionauth.io/docs/operate/secure.md#database-access).
3.  Keep the search engine off public networks. A single-node install binds it to localhost by default. See [Required Ports](https://fusionauth.io/docs/operate/secure.md#required-ports) for clusters.

### Protect Configuration and Secrets

1.  Set **`fusionauth-app.runtime-mode`** to `production`. In the default `development` mode, FusionAuth shows the interactive Maintenance Mode pages to anyone who reaches the instance while the database needs setup or an update.
2.  Keep database passwords and other secrets out of version control. Make the configuration file readable only by the user that runs FusionAuth, or inject secrets as environment variables from a secrets manager. See [Configuration Information](https://fusionauth.io/docs/operate/secure.md#configuration-information).
3.  If you use [Kickstart](https://fusionauth.io/docs/get-started/download-and-install/development/kickstart.md), [reference secrets with environment variables](https://fusionauth.io/docs/get-started/download-and-install/development/kickstart.md#using-environment-variables), and replace the API Key it creates once the instance is running.

### Stay Up to Date

Updates include security fixes. To hear about them, subscribe to the [release notes feed](https://fusionauth.io/docs/releases.xml), and assign the `Security Officer` role to your account at [account.fusionauth.io](https://account.fusionauth.io) to join the security announcement list. Follow [Update a Production Instance](https://fusionauth.io/docs/update/prod-instance.md) to apply updates safely.

Related

[Operate Secure Learn how to secure your installation by limiting network traffic. securityhardening](https://fusionauth.io/docs/operate/secure.md)

[APIs Authorize API API documentation for the FusionAuth Authorize OAuth2 endpoint. pkce](https://fusionauth.io/docs/apis/oauth/authorize.md)

[APIs Token API API documentation for the FusionAuth Token OAuth2 endpoint. pkce](https://fusionauth.io/docs/apis/oauth/token.md)

[APIs Disable Multi-Factor API API documentation for the FusionAuth Disable Multi-Factor API. mfa](https://fusionauth.io/docs/apis/two-factor/disable-multi-factor.md)
---

## Other pages in Secure

> For the full index of this section, see [Operate](https://fusionauth.io/docs/llms-operate.txt).

- [Account Enumeration](https://fusionauth.io/docs/operate/secure/account-enumeration.md): Learn which FusionAuth responses reveal whether an account exists, and how to reduce what they reveal.
- [Advanced Threat Detection](https://fusionauth.io/docs/operate/secure/advanced-threat-detection.md): Learn about the FusionAuth Advanced Threat Detection feature that provides various tools to secure your application.
- [Breached Password Detection](https://fusionauth.io/docs/operate/secure/breached-password-detection.md): Learn how to configure and use breached password detection.
- [CIMD Security](https://fusionauth.io/docs/operate/secure/cimd-security.md): Learn how FusionAuth protects itself when it fetches a Client ID Metadata Document from a URL a third party controls.
- [Compliance Frameworks](https://fusionauth.io/docs/operate/secure/compliance.md): Learn how FusionAuth conforms to various compliance frameworks.
- [CORS Reference](https://fusionauth.io/docs/operate/secure/cors.md): Learn about FusionAuth and Cross-Origin Resource Sharing (CORS) configuration.
- [Secure](https://fusionauth.io/docs/operate/secure.md): Learn how to secure your installation by limiting network traffic.
- [Key Master](https://fusionauth.io/docs/operate/secure/key-master.md): An overview of FusionAuth Key Master, used to manage signing keys and certificates.
- [Key Rotation](https://fusionauth.io/docs/operate/secure/key-rotation.md): Learn how to rotate keys in FusionAuth.
- [Networking Configuration](https://fusionauth.io/docs/operate/secure/networking.md): Learn about FusionAuth networking configuration, especially IP resolution.
- [Token Storage](https://fusionauth.io/docs/operate/secure/token-storage.md): Learn how to secure tokens generated by FusionAuth.
