# How to Securely Manage Secrets and Environment Variables in Agent-Native Projects

> Securely manage secrets and environment variables in agent-native projects. Learn how agent-native uses encrypted vaults and guard scripts for robust security.

- Repository: [Builder.io/agent-native](https://github.com/BuilderIO/agent-native)
- Tags: how-to-guide
- Published: 2026-06-29

---

**Agent-native projects store all runtime secrets in an AES-256-GCM encrypted vault accessed via `saveCredential` and `resolveCredential`, while static analysis guard scripts enforce that only deployment-level variables like `DATABASE_URL` may reside in environment files.**

The BuilderIO/agent-native framework eliminates hard-coded secrets by storing sensitive data in an encrypted database vault rather than source files or plain-text environment variables. When you need to securely manage secrets and environment variables in agent-native applications, the platform provides a credential API that encrypts values with user, organization, or workspace scope while enforcing compliance through automated guard scripts.

## Understanding the Vault Architecture

Agent-native persists runtime secrets in an encrypted `app_secrets` table rather than in `process.env`. The encryption layer in [`packages/core/src/credentials/index.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/credentials/index.ts) uses **AES-256-GCM** to seal values at rest, decrypting them only when `resolveCredential` is invoked. Master encryption keys derived from `SECRETS_ENCRYPTION_KEY` or `BETTER_AUTH_SECRET`—defined in [`packages/core/src/secrets/crypto.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/secrets/crypto.ts)—protect the vault, and the application will fail to start if these are absent.

This architecture ensures that **API keys, OAuth tokens, and service credentials** never appear in source control or shell environments. Instead, the framework scopes each secret to a specific user, organization, or workspace, enabling fine-grained access control across multi-tenant deployments.

## The Core Credential API

The [`packages/core/src/credentials/index.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/credentials/index.ts) module exposes three primary functions for secret lifecycle management.

### Storing Secrets with `saveCredential`

To encrypt and persist a secret, invoke `saveCredential` with a key identifier and the plaintext value. The function automatically encrypts the payload and inserts it into the `app_secrets` table.

```typescript
import { saveCredential } from "@agent-native/core/credentials";

await saveCredential("OPENAI_API_KEY", "sk-mySecret", {
  // Optional: default scope is the current user
  // scope: "org", 
  // orgId: "12345"
});

```

The scope parameter determines visibility: omitting it defaults to the authenticated user, while `"org"` or `"workspace"` allows shared access across team boundaries.

### Retrieving Secrets with `resolveCredential`

When your action or route requires a secret, call `resolveCredential` to decrypt the value on demand. The function traverses the scope hierarchy—user, then organization, then workspace—returning the most specific match.

```typescript
import { resolveCredential } from "@agent-native/core/credentials";

const apiKey = await resolveCredential("OPENAI_API_KEY");
// Returns decrypted plaintext ready for the provider SDK

```

### Scoping and Deletion

To rotate or revoke credentials, use `deleteCredential` to remove the encrypted row, then re-save with a new value if needed.

```typescript
import { deleteCredential } from "@agent-native/core/credentials";

await deleteCredential("OPENAI_API_KEY");
// Re-save with rotated value via saveCredential

```

Deletion is immediate and scope-aware; calling it without specifying a scope removes only the user-scoped entry.

## Development vs. Production Patterns

During local development, agent-native loads the workspace root `.env` into `process.env` via [`packages/core/src/vite/client.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/vite/client.ts) for convenience. This allows rapid iteration without vault setup, but the framework treats these values as temporary placeholders.

In production, the **guard script** located at `scripts/guard-no-env-credentials.mjs` performs static analysis to block any read of `process.env.<KEY>` inside credential-related logic. Only whitelisted deployment variables—such as `DATABASE_URL`—are permitted. This enforcement guarantees that production builds cannot accidentally leak secrets through environment variables.

## Deployment-Level Environment Variables

While runtime secrets belong in the vault, infrastructure configuration remains in environment variables. The following variables are required and must be defined at deploy time:

- **`SECRETS_ENCRYPTION_KEY`** – Master key for the AES-256-GCM vault
- **`BETTER_AUTH_SECRET`** – Secondary encryption seed for credential operations
- **`DATABASE_URL`** – Connection string for the application database

These values are validated in [`packages/core/src/secrets/crypto.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/secrets/crypto.ts). The guard script explicitly allows `process.env` access for these keys while rejecting all others in sensitive code paths.

## Enforcement Through Guard Scripts

The repository ships with `scripts/guard-no-env-credentials.mjs`, a static analysis tool that runs in CI to prevent credential leakage. It scans for patterns like `process.env.OPENAI_API_KEY` and errors if found outside of whitelisted configuration files. This automation ensures that developers cannot bypass the vault API, maintaining the security invariant that **plaintext secrets never enter source control**.

## Summary

- **Use the vault API** – Store all runtime secrets via `saveCredential` and retrieve them with `resolveCredential` from [`packages/core/src/credentials/index.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/credentials/index.ts).
- **Scope appropriately** – Assign secrets to user, organization, or workspace contexts to enforce least-privilege access.
- **Protect master keys** – Provide `SECRETS_ENCRYPTION_KEY` and `BETTER_AUTH_SECRET` at deployment; the app refuses to start without them.
- **Reserve `.env` for infrastructure** – Only deployment-level variables like `DATABASE_URL` may use `process.env`; runtime secrets trigger guard-script failures.
- **Automate compliance** – Run `scripts/guard-no-env-credentials.mjs` in CI to block accidental credential commits.

## Frequently Asked Questions

### What happens if I try to read a secret from `process.env` in production?

The static analysis guard script in `scripts/guard-no-env-credentials.mjs` will fail the build with an error. Agent-native explicitly forbids reading `process.env.<SECRET>` in credential-related code, allowing only whitelisted variables like `DATABASE_URL` to be accessed via environment variables.

### How do I rotate an existing API key in the vault?

First call `deleteCredential("KEY_NAME")` to remove the old encrypted entry, then immediately invoke `saveCredential("KEY_NAME", "new-value")` with the rotated token. The change takes effect immediately for subsequent `resolveCredential` calls.

### Can I share secrets across my entire organization?

Yes. Pass `scope: "org"` and an `orgId` when calling `saveCredential`. This stores the secret at the organization level in the `app_secrets` table, making it available to all members while still encrypting it at rest with AES-256-GCM.

### Is the `.env` file safe for local development secrets?

The workspace root `.env` is loaded by [`packages/core/src/vite/client.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/vite/client.ts) for convenience during development, but these values are never permitted in production builds. Treat `.env` as a local-only scratchpad; always migrate secrets to the vault before deploying.