# How Streambert Implements Secure TMDB API Key Storage Using the OS Keychain

> Learn how Streambert secures your TMDB API key by storing it in the OS keychain with Electron's safeStorage. Your token is encrypted and never saved in plain text.

- Repository: [true_lock/streambert](https://github.com/truelockmc/streambert)
- Tags: best-practices
- Published: 2026-05-21

---

**Streambert stores the TMDB Read-Access Token in the operating system's native credential store using Electron's `safeStorage` API, ensuring the JWT token is encrypted and never persisted in plain text.**

Streambert is an open-source streaming application that securely manages TMDB API credentials without exposing sensitive tokens to plain text storage. By leveraging the OS keychain through Electron's secure storage mechanisms, the `truelockmc/streambert` repository implements a robust pattern for protecting user API keys across macOS, Windows, and Linux platforms.

## Understanding the Secure Storage Architecture

### Key Registration and Constants

In [`src/utils/storage.js`](https://github.com/truelockmc/streambert/blob/main/src/utils/storage.js), the application defines `STORAGE_KEYS.API_KEY` (lines 34-38) to uniquely identify the TMDB token within the credential store. This constant provides a consistent lookup key for all storage operations, ensuring the application references the same secure entry regardless of platform.

### The Secure Storage Wrapper

The `secureStorage` object defined in [`src/utils/storage.js`](https://github.com/truelockmc/streambert/blob/main/src/utils/storage.js) (lines 114-126) abstracts the underlying platform-specific implementation. It provides `get` and `set` methods that forward calls to `window.electron.secureGet` and `window.electron.secureSet`. The wrapper includes a no-op fallback for development environments outside Electron, preventing crashes when the secure storage bridge is unavailable while maintaining API consistency.

### Electron IPC Bridge Implementation

The actual encryption and OS keychain interaction occurs in [`src/ipc/storage.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/storage.js), which bridges the renderer process to Electron's `safeStorage` API. This layer handles platform-specific storage mechanisms—macOS Keychain, Windows DPAPI, or Linux libsecret—ensuring the renderer never accesses raw secrets directly and the encryption keys remain within the main process.

## How Streambert Retrieves and Stores the TMDB Token

### Loading the Token at Application Startup

When Streambert initializes, [`src/App.jsx`](https://github.com/truelockmc/streambert/blob/main/src/App.jsx) (lines 35-36) asynchronously retrieves the stored token using `secureStorage.get(STORAGE_KEYS.API_KEY)`. This ensures the TMDB JWT is available for API calls immediately after launch while maintaining encryption at rest. The asynchronous pattern prevents blocking the UI during keychain access, which may require user authentication on some platforms.

### User Input and Persistence Flow

The Settings UI in [`src/pages/SettingsPage.jsx`](https://github.com/truelockmc/streambert/blob/main/src/pages/SettingsPage.jsx) (lines 1609-1664) provides an interface for users to paste their TMDB JWT token. Upon confirmation, the application calls `secureStorage.set(STORAGE_KEYS.API_KEY, token)` to encrypt and persist the credential to the OS keychain. This design ensures the token survives application restarts without exposure to plain text storage mechanisms like `localStorage` or plain JSON files.

## Secure Storage Implementation Examples

Retrieve the TMDB token for API authentication:

```javascript
// Retrieve the TMDB token (used by any API call)
import { secureStorage, STORAGE_KEYS } from '@/utils/storage';

async function loadTmdbToken() {
  const token = await secureStorage.get(STORAGE_KEYS.API_KEY);
  if (!token) throw new Error('TMDB token not set');
  return token;
}

```

Store the TMDB token after user input:

```javascript
// Store the TMDB token after the user pastes it in Settings
import { secureStorage, STORAGE_KEYS } from '@/utils/storage';

async function saveTmdbToken(userInput) {
  const trimmed = userInput.trim();
  await secureStorage.set(STORAGE_KEYS.API_KEY, trimmed);
  // Token is now safely persisted in the OS keychain
}

```

Make authenticated requests using the securely stored token:

```javascript
// Making an authenticated TMDB request (uses the stored token)
import { getApiKey } from '@/utils/storage';
import { TMDB_BASE } from '@/utils/api';

export async function fetchTmdb(path) {
  const token = await getApiKey(); // reads from secure storage
  const res = await fetch(`${TMDB_BASE}${path}`, {
    headers: { Authorization: `Bearer ${token}` },
  });
  if (!res.ok) throw new Error(`TMDB ${res.status}`);
  return res.json();
}

```

## Summary

- **Constant Registration**: `STORAGE_KEYS.API_KEY` in [`src/utils/storage.js`](https://github.com/truelockmc/streambert/blob/main/src/utils/storage.js) provides the unique identifier for the TMDB token in the OS credential store.
- **Abstraction Layer**: The `secureStorage` wrapper forwards calls to Electron's `safeStorage` while providing fallbacks for non-Electron environments.
- **Platform Integration**: [`src/ipc/storage.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/storage.js) handles platform-specific encryption via macOS Keychain, Windows DPAPI, or Linux libsecret without exposing secrets to the renderer.
- **Lifecycle Management**: The token loads asynchronously at startup in [`src/App.jsx`](https://github.com/truelockmc/streambert/blob/main/src/App.jsx) and persists through the settings interface in [`src/pages/SettingsPage.jsx`](https://github.com/truelockmc/streambert/blob/main/src/pages/SettingsPage.jsx).
- **Security Guarantee**: This architecture ensures the TMDB JWT never appears in plain text storage or unencrypted memory dumps.

## Frequently Asked Questions

### Where does Streambert store the TMDB API key?

Streambert stores the TMDB Read-Access Token in the operating system's native credential store—macOS Keychain on Apple devices, Windows DPAPI on Windows, or Linux libsecret on Linux distributions—via Electron's `safeStorage` API as implemented in [`src/ipc/storage.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/storage.js). This prevents the token from being written to disk in plain text.

### Is the TMDB token encrypted when stored?

Yes, the token is encrypted by the OS-provided keystore before being written to disk. Electron's `safeStorage` encrypts the data using platform-specific mechanisms, ensuring the JWT token is never persisted in plain text or accessible to other applications without proper system authentication.

### What happens if the OS keychain is unavailable?

The `secureStorage` wrapper in [`src/utils/storage.js`](https://github.com/truelockmc/streambert/blob/main/src/utils/storage.js) (lines 114-126) includes a no-op fallback mechanism that returns empty values rather than throwing errors when running outside Electron or when the secure storage bridge is inaccessible. However, the token will not persist between sessions in such development scenarios.

### How does the renderer process access the secure storage?

The renderer process communicates with the main process through the IPC bridge defined in [`src/ipc/storage.js`](https://github.com/truelockmc/streambert/blob/main/src/ipc/storage.js). The renderer calls `window.electron.secureGet` and `window.electron.secureSet`, which are exposed via context isolation, delegating to Electron's `safeStorage` methods without exposing encryption keys or raw credentials to the frontend code.