
# Credential management

This page documents how Ethen handles API keys, provider credentials, and authentication secrets across product surfaces.

## Credential stores

Ethen uses a **provider credential store interface** (`ProviderCredentialStore`) with two implementations:

| Implementation | Backing storage | Use case |
|---|---|---|
| Desktop (`safeStorage`) | Electron `safeStorage.encryptString`/`decryptString` via IPC | Desktop app local model runtime |
| Web (env-var) | `process.env` resolution | Gateway and web-mode operations |

Both implementations follow these security rules:

- No provider key is ever written to plaintext JSON settings.
- Credential references (used for UI display) never include the raw secret value.
- Renderer requests for secrets go through IPC or daemon boundary.
- Web mode continues to resolve keys from environment variables only — `setSecret` and `deleteSecret` are no-ops.

## Known provider credentials

The following provider credentials are recognised by the credential store:

| Provider | Environment variable |
|---|---|
| OpenAI | `OPENAI_API_KEY` |
| Anthropic | `ANTHROPIC_API_KEY` |
| DeepSeek | `DEEPSEEK_API_KEY` |
| OpenAI-compatible | `ETHEN_OPENAI_COMPATIBLE_API_KEY` |
| Google | `GOOGLE_API_KEY` |
| Groq | `GROQ_API_KEY` |
| Mistral | `MISTRAL_API_KEY` |
| Cohere | `COHERE_API_KEY` |
| Together | `TOGETHER_API_KEY` |
| Fireworks | `FIREWORKS_API_KEY` |
| Perplexity | `PERPLEXITY_API_KEY` |
| xAI | `XAI_API_KEY` |

## API key hashing

Gateway API keys are hashed using **SHA-256 with a random salt** before storage:

```
stored = "sha256:{salt}:{digest}"
```

Verification uses constant-time comparison (`crypto.timingSafeEqual`) to prevent timing side-channel attacks. Keys that were never created or have been revoked cannot be verified through the hash alone.

## Key fingerprinting

For identification in dashboards and logs, keys are fingerprinted without exposing the full value:

- **Prefix**: first 8 characters of the key beyond the environment prefix (`ethen_live_` or `ethen_test_`).
- **Suffix**: last 6 characters of the key.
- **Environment prefix**: `ethen_live_` for production keys, `ethen_test_` for test keys.

The raw key is never displayed after creation.

## Secret redaction

Before any content is stored, displayed, or exported, the centralised redaction layer scans for:

- Well-known API key formats (OpenAI, Anthropic, AWS, SendGrid, Firebase, etc.)
- Generic `sk_`/`pk_` prefixed secrets
- Sensitive metadata field names (secrets, tokens, keys, passwords, credentials)

Redacted content replaces matched values with placeholders such as `[REDACTED_API_KEY]` or `[REDACTED_OPENAI_KEY]`.

## Desktop credential store availability

The Desktop `safeStorage`-backed credential store is **unavailable** in:

- Headless or test environments where Electron APIs are not loaded.
- Environments where `safeStorage.isEncryptionAvailable()` returns `false`.

In these environments, Desktop mode falls back to environment variable resolution. The `isAvailable()` method on the store interface can be queried at runtime.

## Managed vault (Connected Apps)

OAuth grants and connector secrets for Connected Apps live in the **managed vault**, not in the stores above:

- The vault service is the only interface that may hold secret values. Production adapters are backed by a managed KMS/vault; database rows hold an opaque `externalRef`, never the value.
- Flow grant secrets resolve to a sealed credential handle reachable only through `reveal()`; logs, errors, caches, and telemetry can only ever see redacted handles.
- Secret kinds: `provider`, `connector`, `webhook`, `desktop`, `oauth_client`. Statuses: `staged`, `active`, `superseded`, `revoked`.
- Every vault touch emits an audit event (created, read, rotated, revoked) with actor, purpose, reference, and version.

## See also

- [BYOK operational guide](/docs/security/byok-operations)
- [Security overview](/docs/security/overview)
- [Data handling and retention](/docs/security/data-handling)
- [Connected Apps overview](/docs/connected-apps/overview)
