> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Environment-Specific Secret Values

> Configure different secret values for production, staging, and development environments. One secret, multiple values with automatic environment-based resolution.

# Environment-Specific Secret Values

Use a single secret with different values for each environment. KnoxCall automatically uses the correct value based on the route's active environment—no manual switching required.

## The Problem

Traditional approach requires separate secrets per environment:

```text theme={"dark"}
❌ Old Way: 3 Secrets
├─ stripe_production_key → sk_live_abc123
├─ stripe_staging_key    → sk_test_staging_456
└─ stripe_development_key → sk_test_dev_789

Route config must change per environment:
Production: {{secret:stripe_production_key}}
Staging:    {{secret:stripe_staging_key}}
Development: {{secret:stripe_development_key}}
```

**Problems:**

* Accidental use of production keys in staging
* Manual route config updates when switching environments
* Difficult to audit which env uses which key
* Secret sprawl (3x secrets)

## The Solution

One secret, multiple environment-specific values:

```text theme={"dark"}
✅ New Way: 1 Secret
stripe_api_key
  ├─ production:  sk_live_abc123
  ├─ staging:     sk_test_staging_456
  └─ development: sk_test_dev_789

Route config stays the same:
All environments: {{secret:stripe_api_key}}
```

**Benefits:**

* ✅ Automatic environment-based resolution
* ✅ Hard fail if environment value missing (prevents accidents)
* ✅ Simplified route configuration
* ✅ Clear audit trail per environment

## How It Works

### Step 1: Create Secret

Create a secret normally:

```text theme={"dark"}
Name: stripe_api_key
Type: String
```

Leave the initial value empty—we'll set environment-specific values next.

### Step 2: Configure Environment Values

In the secret detail page:

1. **Select environment** from dropdown (top right)
2. **Enter value** for that environment
3. **Save**
4. **Repeat** for other environments

**Example:**

```text theme={"dark"}
Environment: production
Value: sk_live_4eC39HqLyjWDarjtT1zdp7dc
[Save]

Environment: staging
Value: sk_test_staging_BQokikJOvBiI2HlWgH4olfQ2
[Save]

Environment: development
Value: sk_test_dev_4eC39HqLyjWDarjtT1zdp7dc
[Save]
```

### Step 3: Reference in Route

Use the secret in your route config:

```json theme={"dark"}
{
  "headers": {
    "Authorization": "Bearer {{secret:stripe_api_key}}"
  }
}
```

### Step 4: Automatic Resolution

When a request comes in:

```text theme={"dark"}
1. Client calls route
2. Route has active environment: "production"
3. KnoxCall looks up stripe_api_key environment config
4. Finds production value: sk_live_4eC39HqLyjWDarjtT1zdp7dc
5. Injects value into request
6. Proxies to Stripe API ✅
```

If route is in staging environment:

```text theme={"dark"}
Same route, staging environment:
→ Uses sk_test_staging_BQokikJOvBiI2HlWgH4olfQ2 automatically
```

## Hard Fail Behavior

**Safety feature**: If a secret lacks a value for the requested environment, the request **fails immediately**.

```text theme={"dark"}
Scenario:
- Secret: stripe_api_key
- Configured environments: production, staging
- Route environment: development ❌

Result:
The proxy refuses to inject the secret and the request is blocked.
The client receives:

HTTP 401 Unauthorized
{
  "error": "Unauthorized"
}
```

<Note>
  The detailed reason — `Secret 'stripe_api_key' (<id>) has no value configured for environment 'development'` — is recorded server-side in the request log (`api_requests.error`), not returned to the caller. Error responses are normalized so callers can't enumerate tenant or secret configuration from the status code or message.
</Note>

**Why no fallback?**

* Prevents accidental production key usage in dev/staging
* Forces explicit configuration
* Makes missing config obvious during testing
* Complies with principle of least privilege

**Solution:**
Add the missing environment value or change route's active environment.

## Supported Secret Types

Environment-specific values work with **all secret types**:

### String Secrets

```text theme={"dark"}
API Key: stripe_api_key
  ├─ production:  sk_live_abc123
  ├─ staging:     sk_test_staging_456
  └─ development: sk_test_dev_789
```

### OAuth2 Secrets

```text theme={"dark"}
OAuth Client: google_oauth
  ├─ production:
  │    client_id: prod-client-id.apps.googleusercontent.com
  │    client_secret: GOCSPX-prod-abc123
  │
  ├─ staging:
  │    client_id: staging-client-id.apps.googleusercontent.com
  │    client_secret: GOCSPX-staging-def456
  │
  └─ development:
       client_id: dev-client-id.apps.googleusercontent.com
       client_secret: GOCSPX-dev-ghi789
```

### Certificate Secrets (mTLS)

```text theme={"dark"}
Client Certificate: bank_mtls_cert
  ├─ production:
  │    cert: -----BEGIN CERTIFICATE----- (prod cert)
  │    key: -----BEGIN PRIVATE KEY----- (prod key)
  │
  ├─ staging:
  │    cert: -----BEGIN CERTIFICATE----- (staging cert)
  │    key: -----BEGIN PRIVATE KEY----- (staging key)
  │
  └─ development:
       cert: -----BEGIN CERTIFICATE----- (dev cert)
       key: -----BEGIN PRIVATE KEY----- (dev key)
```

## Advanced Usage

### Partial Environment Coverage

You can configure only the environments you need:

```text theme={"dark"}
Secret: internal_api_key

Configured:
  ✅ production
  ✅ staging
  ❌ development (not configured)

Routes in development environment:
  → Will fail (hard fail)
  → Forces you to add dev value or use different secret
```

### Duplicating Environments

Clone an existing environment's value:

1. Go to secret detail page
2. Select source environment (e.g., "production")
3. Click **Duplicate to another environment**
4. Choose target environment (e.g., "staging")
5. **Modify** the duplicated value if needed
6. Save

**Use case:** Copy production config to staging, then change specific values.

### Deleting Environment Values

**Protected deletion**: Cannot delete an environment value if any route is actively using it in that environment.

```text theme={"dark"}
Scenario:
- Secret: stripe_api_key has production value
- Route "Stripe Charges" is active in production environment
- Try to delete production value

Result:
❌ Error: Cannot delete - 1 route using this secret in production
   Routes: Stripe Charges (route_abc123)
```

**Solution:**

1. Switch routes to different environment, OR
2. Update routes to use different secret, OR
3. Delete the routes first

### Viewing All Environments

In the secret detail page, see all configured environments at a glance:

```text theme={"dark"}
Secret: stripe_api_key

Environment Status:
  ✅ production    (configured, 4 routes using)
  ✅ staging       (configured, 2 routes using)
  ✅ development   (configured, 0 routes using)
  ⚠️  testing      (not configured)
```

## API Reference

### Get Secret Environments

```http theme={"dark"}
GET /admin/secrets/{secret_id}/environments

Response:
{
  "secret_id": "uuid",
  "secret_name": "stripe-prod-key",
  "secret_type": "string",
  "base_environment": "production",
  "environments": [
    {
      "environment_name": "production",
      "created_at": "2025-01-15T10:00:00Z",
      "updated_at": "2025-01-20T14:30:00Z"
    },
    {
      "environment_name": "staging",
      "created_at": "2025-01-15T10:05:00Z",
      "updated_at": "2025-01-15T10:05:00Z"
    }
  ]
}
```

Note: Values are **never** returned via API for security.

### Create/Update Environment Value

```http theme={"dark"}
PUT /admin/secrets/{secret_id}/environments/{environment_name}

Body (String secret only):
{
  "value": "sk_test_abc123"
}

Note: This endpoint only accepts `string` secrets. OAuth2 and certificate secrets have their own
dedicated endpoints for managing environment-level values.
```

### Delete Environment Value

```http theme={"dark"}
DELETE /admin/secrets/{secret_id}/environments/{environment_name}

Response:
{
  "ok": true
}

Or if in use by routes:
{
  "error": "Cannot remove environment 'production' from this secret. It is used by the following routes in that environment: stripe-charges. Remove the secret from those routes first.",
  "routes": [{ "id": "uuid", "name": "stripe-charges" }]
}
```

### Duplicate Environment

```http theme={"dark"}
POST /admin/secrets/{secret_id}/environments/{source_env}/duplicate

Body:
{
  "target_environment": "development"
}

Response:
{
  "ok": true,
  "environment": "development",
  "message": "Successfully created environment 'development' from 'staging'"
}
```

## Migration Guide

### From Naming Convention to Environment Configs

**Before:**

```text theme={"dark"}
Secrets:
  - stripe_production_key
  - stripe_staging_key
  - stripe_development_key

Route config (production):
{
  "Authorization": "Bearer {{secret:stripe_production_key}}"
}
```

**After:**

```text theme={"dark"}
Secret: stripe_api_key
  ├─ production:  (value from stripe_production_key)
  ├─ staging:     (value from stripe_staging_key)
  └─ development: (value from stripe_development_key)

Route config (all environments):
{
  "Authorization": "Bearer {{secret:stripe_api_key}}"
}
```

**Steps:**

1. **Create new secret**: `stripe_api_key` (no initial value)
2. **Copy values**:
   * Environment: production → Paste value from `stripe_production_key`
   * Environment: staging → Paste value from `stripe_staging_key`
   * Environment: development → Paste value from `stripe_development_key`
3. **Update routes**:
   * Change `{{secret:stripe_production_key}}` to `{{secret:stripe_api_key}}`
   * Remove environment-specific references
4. **Test** in staging first
5. **Deploy** to production
6. **Delete old secrets** after 48 hours

## Best Practices

### ✅ Do This

1. **Use environment configs for new secrets**
   * Simpler, safer, better audit trail

2. **Configure all environments you use**
   * Don't leave gaps (hard fail protects you)

3. **Test in staging first**
   * Verify correct values loaded per environment

4. **Use descriptive names**
   * `stripe_api_key` not `secret_42`
   * Easier to manage across environments

5. **Document your environments**
   * Keep a list of which environments exist
   * Standard: production, staging, development

### ❌ Avoid This

1. **Don't mix approaches for same service**
   * Either use env configs OR naming convention
   * Don't use both for Stripe (confusing)

2. **Don't delete environment values carelessly**
   * Check if routes are using them first
   * System prevents deletion, but verify manually

3. **Don't share values across environments**
   * Never use production keys in staging
   * Even if system allows it, don't do it

4. **Don't skip testing after migration**
   * Always test in dev/staging first
   * Verify hard fail works as expected

## Troubleshooting

### "Secret not configured for environment"

**Problem:**

```text theme={"dark"}
Route fails with:
"Secret 'api_key' not configured for environment 'staging'"
```

**Solutions:**

1. Add the missing environment value
2. Change route's active environment
3. Use a different secret that has the environment

### Can't delete environment value

**Problem:**

```text theme={"dark"}
Cannot delete - 3 routes using this secret in production
```

**Solution:**

```sql theme={"dark"}
-- Find routes using this secret
SELECT r.name, r.id
FROM routes r
JOIN route_environment_configs rec ON r.id = rec.route_id
WHERE rec.environment_name = 'production'
AND rec.active = true;

-- Then either:
1. Switch those routes to different environment
2. Update routes to use different secret
3. Accept that you can't delete (it's in use!)
```

### Environment dropdown not showing

**Problem:** Can't see environment selector in secret detail page

**Possible causes:**

1. Secret type doesn't support environments (shouldn't happen - all types do)
2. Browser cache issue - hard refresh (Ctrl+F5)
3. Old UI version - ensure admin-ui is up to date

**Solution:**

```bash theme={"dark"}
cd admin-ui && npm run build
pm2 restart knoxcall
```

### Wrong value being used

**Problem:** Route in staging is using production value

**Debug steps:**

1. Check route's active environment (top right dropdown)
2. Verify secret has value for that environment
3. Check route config uses correct secret name
4. Test with a different route

**Common cause:** Route's active environment is set to "production" even though you think it's staging.

## Security Considerations

### Encryption

All environment values are encrypted individually:

```text theme={"dark"}
Secret: stripe_api_key

Each environment value:
├─ Encrypted with unique data encryption key (DEK)
├─ DEK encrypted with master key (KEK)
├─ Stored: ciphertext + IV + auth tag
└─ Decrypted only when route resolves secret
```

### Audit Trail

Every environment value change is logged:

```sql theme={"dark"}
SELECT
  resource_id,         -- the secret's id
  action,              -- e.g. 'create', 'update', 'rotate', 'delete'
  details,             -- JSON: { name, environment, ... }
  user_id,             -- set for dashboard users (null for API-key access)
  ip_address,
  created_at
FROM audit_logs
WHERE resource_type = 'secret'
  AND resource_id = 'sec_abc123';
```

### Access Control

* Only tenant admins can view/edit secret environment configs
* The client API requires a KnoxCall API key / access token (`Authorization: Bearer <api_key>` or the `x-api-key` header), not a session JWT
* No way to retrieve values via API (write-only)
* Environment values never logged or transmitted in plaintext

### Compliance

Environment-specific secrets help with:

* **PCI DSS**: Separate production and test credentials
* **SOC 2**: Audit trail of secret changes per environment
* **GDPR**: Environment isolation for data protection
* **HIPAA**: Segregation of production and non-production

## Next Steps

<CardGroup cols={2}>
  <Card title="Creating Secrets" icon="key" href="/essentials/secrets/creating-secrets">
    Learn how to create secrets in KnoxCall
  </Card>

  <Card title="Using Secrets in Routes" icon="route" href="/essentials/secrets/using-secrets">
    Reference secrets in route configurations
  </Card>

  <Card title="Environment Basics" icon="layer-group" href="/essentials/environments/environment-basics">
    Understand KnoxCall environments
  </Card>

  <Card title="Secret Rotation" icon="rotate" href="/security/rotation-strategies">
    Best practices for rotating secrets
  </Card>
</CardGroup>

***

<CardGroup cols={2}>
  <Card title="📊 Guide Info" icon="info-circle">
    * **Level**: Intermediate
    * **Time**: 10 minutes
    * **Prerequisites**: Basic understanding of secrets and environments
  </Card>

  <Card title="🏷️ Tags" icon="tags">
    `secrets`, `environments`, `configuration`, `security`, `credentials`
  </Card>
</CardGroup>
