Skip to main content

Using Secrets in Routes

Learn how to inject encrypted secrets into your route requests using KnoxCall’s template system.

Template Syntax

Secrets are injected using template syntax in your route configuration.

Basic Format

Components:
  • {{ - Opening delimiter
  • secret: - Type identifier (required)
  • SECRET_NAME - Your secret’s name
  • }} - Closing delimiter

Example

If you have a secret named stripe_prod_key:
At runtime, KnoxCall replaces this with:

Injecting Secrets in Headers

The most common use case - adding secrets to HTTP headers.

Step 1: Edit Route

  1. Go to Routes
  2. Click on your route
  3. Scroll to Inject Headers section

Step 2: Add Header with Secret

Click Add Header or edit the JSON directly:

Step 3: Save

Click Save Changes ✅ All requests through this route now have the secret injected!

Common Header Patterns

Bearer Token

Used by: Stripe, GitHub, most REST APIs

API Key Header

Used by: SendGrid, Mailgun, custom APIs

Basic Authentication

Note: Secret value should be base64-encoded username:password

Custom Headers


Injecting Secrets in the Request Body

KnoxCall can substitute placeholders inside the request body your client sends — not just headers. This lets your application reference secrets by name (or by ID) without ever holding the actual values. KnoxCall resolves the placeholders server-side, swaps them for the real decrypted values, and forwards the rewritten body upstream.

How it works

  1. Your client sends a POST/PUT/PATCH with placeholder tokens in the body
  2. KnoxCall reads the body, scans for {{secret:name}} / {{secret_id:uuid}} / {{var:key}}
  3. KnoxCall resolves each reference against your tenant’s secrets for the route’s active environment
  4. KnoxCall rewrites Content-Length and forwards the substituted body to the upstream API
  5. Your application never needs to possess the raw credential

Placeholder forms accepted in the body

Prefer the UUID form ({{secret_id:...}}) wherever possible. A secret’s UUID is permanent and never changes, so your code and templates keep working even if someone renames the secret in the dashboard. The name-based form ({{secret:...}}) is supported for backwards compatibility and readability, but any rename will silently break every reference to it and the next request will hard-fail with “Missing secret”.Also note: {{secret:UUID}} is not a shortcut for ID-based lookup — it would try to find a secret literally named that UUID string and fail. For ID lookups always use the secret_id: prefix.
You can find a secret’s UUID on its detail page in the KnoxCall dashboard, or in the response of the create_secret API / onboarding-agent tool call.

Example — JSON body

Your client code sends this to KnoxCall (UUID form recommended):
What the upstream API actually receives:

Example — form-urlencoded

Example — plain text / XML

Supported Content-Types

KnoxCall only rewrites bodies for text-shaped Content-Types, so binary uploads stay byte-identical:

Safety rules

  • Tenant isolation — clients can only reference secrets belonging to their own tenant. A UUID guessed from another tenant will hard-fail.
  • Environment-aware — KnoxCall resolves secrets against the route’s active environment. If the secret has no value for that environment, the request fails with a clear error (no silent fallback).
  • Size limit — bodies larger than 1 MiB pass through without substitution to protect the proxy (configurable via BODY_INJECTION_MAX_BYTES).
  • UTF-8 required — the body must be valid UTF-8 with no NUL bytes; anything else is treated as binary and passed through untouched.
  • Hard-fail on missing secrets — referencing a secret that doesn’t exist (or has no value in the active environment) returns an error instead of sending an empty string upstream.
  • Logs are scrubbed — audit logs store the body with placeholders intact, never the resolved secret values.

Do I still need headers?

Header injection and body placeholders are independent and can be combined in the same request. Use headers for stable auth (e.g. Authorization: Bearer) and body placeholders for APIs that expect credentials in the payload or for per-call secret selection.

Common Body Patterns

All examples use the recommended UUID form — substitute your actual secret IDs.

Simple API key in body (UUID, rename-safe)

Nested objects

Legacy name form (works, but breaks if the secret is renamed)

Multiple secrets in one request

Mixing a secret with a query-string variable


Multiple Secrets in One Route

You can use multiple different secrets in the same route configuration.

Example: Multi-Service Integration

Route: notification-service Headers:
Body:
Result: All 4 secrets injected in one request!

Environment-Specific Secrets

Use different secrets per environment (dev, staging, production).

Setup

Create environment-specific secrets:
  1. Production:
  2. Staging:
  3. Development:

Configure Route Per Environment

Base environment (production):
Override for staging:
Override for development:

How to Set Up

  1. Go to route → Environment tab
  2. Select “staging”
  3. Edit Inject Headers:
  4. Save
  5. Repeat for “development”
Result:
  • Production uses: stripe_prod_key
  • Staging uses: stripe_staging_key
  • Development uses: stripe_dev_key
All with the same route!

Method-Specific Secrets

Different secrets for different HTTP methods on the same route.

Example Scenario

Route handles both GET (read) and POST (write) to same API:
  • GET needs read-only key
  • POST needs full-access key

Setup

GET method config:
POST method config:
Result:
  • GET requests use read-only key
  • POST requests use full-access key

Secret Resolution Order

When multiple environments and methods are involved, KnoxCall resolves secrets in this order:
  1. Method-specific environment override
  2. Environment override (if method not specified)
  3. Base route configuration

Example


Template Syntax Rules

✅ Correct Syntax

Rules:
  • Double curly braces: {{ and }}
  • Prefix: secret:
  • No spaces inside braces
  • Lowercase with underscores for secret names

❌ Common Mistakes


Real-World Examples

Example 1: Stripe Payments

Secret:
Route config:
Actual request sent to Stripe:

Example 2: SendGrid Email

Secret:
Route config:

Example 3: Database Access

Secret:
Route config:

Example 4: PrintNode Printing

Secret:
Route config:

Example 5: Multi-Service Orchestration

Secrets:
Route config:

Combining Secrets with Other Templates

You can combine secrets with the other supported template forms in a single body or header set:
Supported placeholder forms:
  • {{secret_id:UUID}} - Inject a secret by its UUID (preferred — rename-safe)
  • {{secret:name}} - Inject a secret by its name (legacy — breaks on rename)
  • {{var:QUERY_PARAM}} - Substitute the value of an incoming query-string parameter
These are the only placeholder forms the template engine resolves. Tokens such as {{header:name}}, {{env:name}}, or {{uuid}} are not supported and are passed through to the upstream unchanged.

Security Considerations

What Gets Logged

In KnoxCall logs:
  • Template syntax shown: {{secret:stripe_key}}
  • Actual value: Never logged
Example log entry:
Plaintext value is not exposed in logs for security.

Secret Transmission

Flow:

Best Practices

Do:
  • Use secrets for all sensitive values
  • Separate secrets per environment
  • Rotate secrets regularly
  • Use descriptive secret names
  • Document what each secret is for
Don’t:
  • Hardcode API keys in route configs
  • Use production secrets in development
  • Share secrets via email or chat
  • Commit secrets to git
  • Use generic names like “key” or “secret”

Troubleshooting

Secret Not Replacing

Symptom: Backend receives {{secret:stripe_key}} literally. Causes:
  1. Syntax error in template
  2. Secret doesn’t exist
  3. Secret name typo
Debug steps:
  1. Check template syntax: {{secret:name}}
  2. Verify secret exists: Resources → Secrets
  3. Check spelling matches exactly (case-sensitive)
  4. Look at logs for error messages

Wrong Value Injected

Symptom: Wrong API key being used. Causes:
  1. Using wrong environment
  2. Wrong secret name
  3. Secret not configured for environment
Fix:
  1. Check which environment request is using
  2. Verify environment override has correct secret
  3. Check secret name spelling

Secret Not Found Error

Error: Secret 'api_key' not found Solution:
  1. Go to Resources → Secrets
  2. Check secret exists
  3. Verify name matches template exactly
  4. Check no typos: api_key vs api_key_

Value Not Decrypting

Symptom: Encrypted value sent instead of plaintext. Cause: KnoxCall internal error (very rare). Solution:
  1. Check KnoxCall status
  2. Try creating new secret version
  3. Contact support if persists

Testing Secret Injection

Test Endpoint

Use a test endpoint to verify secret injection:
  1. Create test route:
    • Target: https://httpbin.org/anything
    • Method: POST
  2. Add secret in header:
  3. Make request:
  4. Check response:
✅ If you see actual value, injection works!

Quick Reference


Next Steps

Creating Secrets

How to create and manage secrets

Secrets Overview

Complete secrets guide

Environment Basics

Environment-specific secrets

OAuth2 Flow

Auto-refreshing OAuth2 tokens

Pro Tip: Always test secret injection with a test endpoint (like httpbin.org) before using in production. This lets you verify the actual decrypted value is correct.