# How API Keys Are Secured and Stored in the SecureStorageService Extension

> Learn how API keys are secured and stored in the SecureStorageService extension. Discover how VS Code's SecretStorage API encrypts credentials at the OS level for safe access.

- Repository: [Harold Martin/secure-design](https://github.com/hbmartin/secure-design)
- Tags: deep-dive
- Published: 2026-03-03

---

**The `SecureStorageService` wraps VS Code's `SecretStorage` API to encrypt and store API keys at the OS level, ensuring credentials never appear in plain-text configuration files and remain accessible only through validated `get`, `set`, and `remove` operations.**

The `hbmartin/secure-design` extension handles sensitive provider credentials using a dedicated `SecureStorageService` that abstracts away direct secret management. This service implements the `StorageAdapter` interface required by the AI SDK, ensuring that API keys are secured and stored within the extension's architecture using platform-native encryption rather than vulnerable configuration files.

## Architecture of the SecureStorageService

### Implementing the StorageAdapter Interface

The service fulfills the `StorageAdapter` contract in [`src/services/secureStorageService.ts`](https://github.com/hbmartin/secure-design/blob/main/src/services/secureStorageService.ts), requiring a constructor that receives a `vscode.SecretStorage` instance injected by the extension host. This dependency injection pattern isolates secret handling from business logic, allowing the underlying storage mechanism to be swapped without modifying consumer code.

### OS-Level Encryption via VS Code SecretStorage

Rather than implementing custom encryption, the service delegates to VS Code's native `SecretStorage` API. When storing values, VS Code encrypts data using the OS credential manager—Keychain on macOS, Credential Locker on Windows, and secret-service on Linux—ensuring API keys remain encrypted at rest and accessible only to the extension process.

## How API Keys Are Secured and Stored

### Storing Keys with the Set Method

The `set` method serializes key-value pairs to JSON before encryption. When `CustomAgentService` persists a provider token, it calls `secureStore.set('openaiApiKey', { token: 'sk-...' })`, which invokes `secrets.store(key, json)`. VS Code encrypts the JSON payload before writing it to the user's secret store, preventing the raw token from appearing in logs or configuration files.

```typescript
// Obtain the VS Code secret storage from the extension context
const secretStorage = context.secrets;

// Create the wrapper service
const secureStore = new SecureStorageService(secretStorage);

// Store the OpenAI key
await secureStore.set('openaiApiKey', { token: 'sk-...' });

```

### Retrieving and Validating Credentials

Retrieval follows the reverse path through the `get` method. The service fetches the raw JSON string via `secrets.get(key)`, then parses it back into an object. To prevent type corruption, the implementation validates the structure using `assertRecordStringString`, guaranteeing the result conforms to `{[string]: string}`. Parsing errors are caught and logged silently, ensuring malformed data never propagates to calling services.

```typescript
const stored = await secureStore.get('openaiApiKey');
if (stored) {
    const token = stored.token;   // use the token with the OpenAI client
}

```

### Removing Sensitive Data

When users revoke credentials or uninstall the extension, the `remove` method forwards deletion requests to `secrets.delete(key)`. This immediately purges the encrypted entry from the OS credential manager, leaving no residual key material on the filesystem.

```typescript
await secureStore.remove('openaiApiKey');

```

## Integration with Extension Services

The `CustomAgentService` in [`src/services/customAgentService.ts`](https://github.com/hbmartin/secure-design/blob/main/src/services/customAgentService.ts) consumes `SecureStorageService` to persist provider API keys under dedicated identifiers like `"openaiApiKey"`, `"anthropicApiKey"`, or `"openrouterApiKey"`. By depending on the `StorageAdapter` interface rather than concrete implementation details, the agent service remains agnostic to whether credentials are stored in VS Code's secret storage, a remote vault, or a future alternative backend.

## Summary

- The `SecureStorageService` wraps VS Code's `SecretStorage` to provide OS-level encryption for API keys without custom cryptography.
- Credentials are stored as encrypted JSON via the `set` method, retrieved and validated via `get`, and purged via `remove`.
- The implementation in [`src/services/secureStorageService.ts`](https://github.com/hbmartin/secure-design/blob/main/src/services/secureStorageService.ts) enforces type safety through `assertRecordStringString` validation.
- By implementing the `StorageAdapter` interface, the service decouples secret management from business logic in `CustomAgentService`.

## Frequently Asked Questions

### Where are API keys physically stored when using SecureStorageService?

API keys are encrypted by VS Code's `SecretStorage` and stored in the operating system's native credential manager—Keychain on macOS, Credential Locker on Windows, or the secret-service daemon on Linux—never in the extension's configuration files or workspace storage.

### What happens if the stored JSON data becomes corrupted?

The `get` method in [`src/services/secureStorageService.ts`](https://github.com/hbmartin/secure-design/blob/main/src/services/secureStorageService.ts) wraps JSON parsing in a try-catch block. If parsing fails or the `assertRecordStringString` validation rejects the structure, the method logs the error and returns `undefined`, preventing malformed data from reaching the AI SDK or agent service.

### Can I migrate existing API keys from settings.json to SecureStorageService?

Yes. The `CustomAgentService` can read legacy plain-text values from [`settings.json`](https://github.com/hbmartin/secure-design/blob/main/settings.json) and migrate them by calling `secureStorageService.set()` with the appropriate provider key, then prompt the user to remove the sensitive value from their configuration file to complete the migration to encrypted storage.

### Is the SecureStorageService dependent on VS Code specific APIs?

Yes. The service directly depends on `vscode.SecretStorage` injected through the constructor in [`src/services/secureStorageService.ts`](https://github.com/hbmartin/secure-design/blob/main/src/services/secureStorageService.ts). While this ties the implementation to the VS Code extension host, the `StorageAdapter` interface abstraction allows future ports to other environments by implementing the same contract with a different storage backend.