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
{{- Opening delimitersecret:- Type identifier (required)SECRET_NAME- Your secret’s name}}- Closing delimiter
Example
If you have a secret namedstripe_prod_key:
Injecting Secrets in Headers
The most common use case - adding secrets to HTTP headers.Step 1: Edit Route
- Go to Routes
- Click on your route
- 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
API Key Header
Basic Authentication
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
- Your client sends a POST/PUT/PATCH with placeholder tokens in the body
- KnoxCall reads the body, scans for
{{secret:name}}/{{secret_id:uuid}}/{{var:key}} - KnoxCall checks that each secret named is one the route’s own template already sends (see below), then resolves it against your tenant’s secrets for the route’s active environment
- KnoxCall rewrites
Content-Lengthand forwards the substituted body to the upstream API - Your application never needs to possess the raw credential
Which secrets your client may name
A placeholder your client sends resolves only for a secret the route already sends: one that the route’s own header or body template references, for the method you are calling. The same rule applies to placeholders your client puts in request headers. If your client names any other secret in your account, KnoxCall refuses the request with403 and X-Knox-Error: client_placeholder_not_bound. The secret it names is never decrypted, and nothing reaches the upstream API. The error message is the same whether or not the named secret exists.
If KnoxCall cannot complete that check, for example during a brief database outage, it refuses the request with 503 and X-Knox-Error: client_placeholder_binding_unavailable rather than forwarding it. Nothing reaches the upstream API, and the request is safe to retry.
This stops a credential that can call one route from pulling a different route’s secret into a request it controls.
- Same secret, either form. If the route’s template sends
{{secret_id:550e8400-e29b-41d4-a716-446655440000}}, your client may send that placeholder or the same secret by name,{{secret:stripe_prod_key}}. - This method’s template. If the route has a different configuration per HTTP method, only the configuration for the method you are calling counts. A secret that only the
DELETEconfiguration sends cannot be named in aPOST. - Not the mTLS certificate. A route’s client certificate is presented during the TLS handshake and never sent in a request, so a client cannot name it.
- Accounts created before this rule was deployed are report-only until they are switched over: the placeholder still resolves, and each use is recorded in your audit log as
route.client_placeholder_not_bound. Accounts created since are refused as described above.
Placeholder forms accepted in the body
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;YOUR_ACCESS_TOKEN is a kc_… OAuth access token — see Authentication):
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.
- Route binding — clients can only reference a secret the route itself already sends. Any other secret is refused with
403 client_placeholder_not_boundbefore it is decrypted; accounts created before this rule was deployed are report-only until switched over (see Which secrets your client may name). - 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?
Yes: configure the route’s template first. A placeholder your client sends, in the body or in a header, resolves only for a secret that the route’s owninject_headers_json or inject_body_json template already references for the method you are calling. Any other secret is refused with 403 client_placeholder_not_bound, so a client placeholder is not a way to pick a secret per call.
Use the route’s header template for stable auth (e.g. Authorization: Bearer). Use a body placeholder where the upstream API expects that same credential inside the payload.
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:
Environment-Specific Secrets
Use different secrets per environment (dev, staging, production).Setup
Create environment-specific secrets:-
Production:
-
Staging:
-
Development:
Configure Route Per Environment
Base environment (production):How to Set Up
- Go to route → Environment tab
- Select “staging”
- Edit Inject Headers:
- Save
- Repeat for “development”
- Production uses:
stripe_prod_key - Staging uses:
stripe_staging_key - Development uses:
stripe_dev_key
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:- 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:- Method-specific environment override
- Environment override (if method not specified)
- Base route configuration
Example
Template Syntax Rules
✅ Correct Syntax
- 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:Example 2: SendGrid Email
Secret:Example 3: Database Access
Secret:Example 4: PrintNode Printing
Secret:Example 5: Multi-Service Orchestration
Secrets:Combining Secrets with Other Templates
You can combine secrets with the other supported template forms in a single body or header set:{{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
{{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
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
- 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:
- Syntax error in template
- Secret doesn’t exist
- Secret name typo
- Check template syntax:
{{secret:name}} - Verify secret exists: Resources → Secrets
- Check spelling matches exactly (case-sensitive)
- Look at logs for error messages
Wrong Value Injected
Symptom: Wrong API key being used. Causes:- Using wrong environment
- Wrong secret name
- Secret not configured for environment
- Check which environment request is using
- Verify environment override has correct secret
- Check secret name spelling
Secret Not Found Error
Error:Secret 'api_key' not found
Solution:
- Go to Resources → Secrets
- Check secret exists
- Verify name matches template exactly
- Check no typos:
api_keyvsapi_key_
Value Not Decrypting
Symptom: Encrypted value sent instead of plaintext. Cause: KnoxCall internal error (very rare). Solution:- Check KnoxCall status
- Try creating new secret version
- Contact support if persists
Testing Secret Injection
Test Endpoint
Use a test endpoint to verify secret injection:-
Create test route:
- Target:
https://httpbin.org/anything - Method: POST
- Target:
-
Add secret in header:
-
Make request:
-
Check response:
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.