# Config encryption

CrossWatch can encrypt secret values before writing them to `config.json`.

This protects secrets **at rest**, but it does not protect a compromised host.

{% hint style="warning" %}
Configuration encryption is included starting with v0.9.13 and is enabled by default.

It does **not** replace normal host security, file permissions, or backup hygiene.
{% endhint %}

### What gets encrypted

Secret fields are encrypted when CrossWatch saves `config.json`.

Common examples:

* `api_key`
* `access_token`
* `refresh_token`
* `client_secret`
* `account_token`
* `pms_token`
* `password`
* keys ending in `_token`

Typical affected providers:

* Plex
* Trakt
* SIMKL
* AniList
* MDBList
* TMDb (Sync)
* Tautulli

### What stays plain text

Non-secret settings stay readable.

Examples:

* server URLs
* booleans
* timeouts
* page sizes
* feature toggles

That keeps `config.json` usable for troubleshooting.

### Stored format

Encrypted values are written with an `enc:v1:` prefix.

Example:

```
enc:v1:...
```

If a value does not use that prefix, CrossWatch treats it as plain text.

This lets older plain-text configs continue to load.

### Master key source order

CrossWatch checks for the master key in this order:

1. `CW_CONFIG_KEY`
2. `CROSSWATCH_CONFIG_KEY`
3. `/config/.cw_master_key`

If an environment variable is set, it wins.

If not, CrossWatch falls back to `/config/.cw_master_key`.

{% hint style="warning" %}
Anyone with both the encrypted config and the matching master key can decrypt the secrets.

Protect both.
{% endhint %}

### Save and migration behavior

Existing plain-text secrets are not rewritten immediately.

They are encrypted the next time CrossWatch saves `config.json` through the normal save path.

That means:

* old installs still load
* encrypted and plain-text values can coexist during transition
* a normal save migrates secret fields to encrypted form

If you still see plain-text secrets after enabling encryption, save the config once.

### UI behavior

The browser does not decrypt secrets.

The backend handles decrypt and encrypt operations.

In normal config views:

* the backend reads and decrypts secrets
* the UI receives a redacted version
* secret fields appear masked or empty

That means the browser does not need the master key.

### Backup and restore

To restore an encrypted config, you need both:

* `config.json`
* the matching master key

If you restore `config.json` without the key, CrossWatch cannot decrypt stored secrets.

Recommended practice:

* back up config and key together
* store the key securely
* avoid casual exports that include secrets or key material

### Moving to another machine

When migrating CrossWatch:

1. Move `config.json`.
2. Move the matching master key, or set the same environment variable.
3. Start CrossWatch.
4. Verify provider authentication still works.

If you move only `config.json`, encrypted secrets will not load.

### Key rotation

If you change the master key, existing secrets must be re-encrypted.

Safe flow:

1. Start with the old key.
2. Decrypt existing values.
3. Switch to the new key.
4. Save config again.

Do not replace the key and expect old encrypted values to keep working.

### Troubleshooting

#### `config.json` still shows plain-text secrets

Check these first:

* Has the config been saved since encryption was enabled?
* Is another code path writing raw JSON?

#### Authentication broke after a restore or move

Check these first:

* Is the correct master key present?
* Did the environment variable change?
* Is `/config/.cw_master_key` missing or different?

#### UI shows masked values

That usually means a secret is already stored.

It does not mean the real value is literally the mask.

### Related pages

* [Configuration (config.json)](https://wiki.crosswatch.app/crosswatch/configuration-config-json)
* [Default config values](https://wiki.crosswatch.app/crosswatch/configuration-config-json/default-config-values)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://wiki.crosswatch.app/crosswatch/configuration-config-json/config-encryption.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
