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

{{secret:SECRET_NAME}}
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:
{
  "Authorization": "Bearer {{secret:stripe_prod_key}}"
}
At runtime, KnoxCall replaces this with:
{
  "Authorization": "Bearer sk_live_abc123xyz789..."
}

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:
{
  "Authorization": "Bearer {{secret:stripe_prod_key}}"
}

Step 3: Save

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

Common Header Patterns

Bearer Token

{
  "Authorization": "Bearer {{secret:api_key}}"
}
Used by: Stripe, GitHub, most REST APIs

API Key Header

{
  "X-API-Key": "{{secret:sendgrid_api_key}}"
}
Used by: SendGrid, Mailgun, custom APIs

Basic Authentication

{
  "Authorization": "Basic {{secret:basic_auth_credentials}}"
}
Note: Secret value should be base64-encoded username:password

Custom Headers

{
  "X-Custom-Token": "{{secret:custom_token}}",
  "X-Webhook-Secret": "{{secret:webhook_secret}}",
  "X-Client-ID": "{{secret:client_id}}"
}

Injecting Secrets in Body

For POST, PUT, PATCH requests, inject secrets into the request body.

Step 1: Edit Route

  1. Go to route
  2. Scroll to Inject Body section

Step 2: Add Body with Secrets

{
  "api_key": "{{secret:printnode_api_key}}",
  "data": {
    "user_id": "12345"
  }
}

Step 3: Save

✅ Body now includes decrypted secret value!

Common Body Patterns

Simple API Key

{
  "api_key": "{{secret:service_api_key}}"
}

Nested Objects

{
  "credentials": {
    "username": "admin",
    "password": "{{secret:admin_password}}"
  }
}

Database Connection

{
  "connection_string": "{{secret:database_url}}",
  "timeout": 30
}

Multiple Secrets

{
  "payment_key": "{{secret:stripe_key}}",
  "email_key": "{{secret:sendgrid_key}}",
  "sms_key": "{{secret:twilio_key}}"
}

Multiple Secrets in One Route

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

Example: Multi-Service Integration

Route: notification-service Headers:
{
  "X-Email-Key": "{{secret:sendgrid_api_key}}",
  "X-SMS-Key": "{{secret:twilio_auth_token}}"
}
Body:
{
  "email_config": {
    "api_key": "{{secret:sendgrid_api_key}}"
  },
  "sms_config": {
    "auth_token": "{{secret:twilio_auth_token}}",
    "account_sid": "{{secret:twilio_account_sid}}"
  },
  "push_config": {
    "server_key": "{{secret:fcm_server_key}}"
  }
}
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:
    Name: stripe_prod_key
    Value: sk_live_abc123...
    
  2. Staging:
    Name: stripe_staging_key
    Value: sk_test_xyz789...
    
  3. Development:
    Name: stripe_dev_key
    Value: sk_test_dev123...
    

Configure Route Per Environment

Base environment (production):
{
  "Authorization": "Bearer {{secret:stripe_prod_key}}"
}
Override for staging:
{
  "Authorization": "Bearer {{secret:stripe_staging_key}}"
}
Override for development:
{
  "Authorization": "Bearer {{secret:stripe_dev_key}}"
}

How to Set Up

  1. Go to route → Environment Overrides tab
  2. Select “staging”
  3. Edit Inject Headers:
    {
      "Authorization": "Bearer {{secret:stripe_staging_key}}"
    }
    
  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:
{
  "method": "GET",
  "inject_headers_json": {
    "Authorization": "Bearer {{secret:api_read_only_key}}"
  }
}
POST method config:
{
  "method": "POST",
  "inject_headers_json": {
    "Authorization": "Bearer {{secret:api_full_access_key}}"
  }
}
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

Request: POST to route in "staging" environment

Lookup order:
1. Check: staging → POST method config → secrets
2. If not found: staging → default config → secrets
3. If not found: base (production) → POST method config → secrets
4. If not found: base (production) → default config → secrets

Template Syntax Rules

✅ Correct Syntax

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

❌ Common Mistakes

// ❌ Single braces
{
  "Authorization": "Bearer {secret:stripe_key}"
}

// ❌ No prefix
{
  "Authorization": "Bearer {{stripe_key}}"
}

// ❌ Wrong prefix
{
  "Authorization": "Bearer {{env:stripe_key}}"
}

// ❌ Spaces inside
{
  "Authorization": "Bearer {{ secret:stripe_key }}"
}

// ❌ Hyphens in name
{
  "Authorization": "Bearer {{secret:stripe-key}}"
}

Real-World Examples

Example 1: Stripe Payments

Secret:
Name: stripe_prod_key
Value: sk_live_abc123xyz789...
Route config:
{
  "inject_headers_json": {
    "Authorization": "Bearer {{secret:stripe_prod_key}}",
    "Content-Type": "application/json"
  }
}
Actual request sent to Stripe:
POST /v1/charges HTTP/1.1
Host: api.stripe.com
Authorization: Bearer sk_live_abc123xyz789...
Content-Type: application/json

{"amount": 1000, "currency": "usd"}

Example 2: SendGrid Email

Secret:
Name: sendgrid_api_key
Value: SG.abc123xyz789...
Route config:
{
  "inject_headers_json": {
    "Authorization": "Bearer {{secret:sendgrid_api_key}}",
    "Content-Type": "application/json"
  },
  "inject_body_json": {
    "personalizations": [{
      "to": [{"email": "[email protected]"}]
    }],
    "from": {"email": "[email protected]"},
    "subject": "Welcome!",
    "content": [{
      "type": "text/html",
      "value": "<p>Welcome!</p>"
    }]
  }
}

Example 3: Database Access

Secret:
Name: postgres_connection_url
Value: postgres://user:pass@host:5432/db
Route config:
{
  "inject_body_json": {
    "connection_string": "{{secret:postgres_connection_url}}",
    "query": "SELECT * FROM users WHERE id = $1",
    "params": [123]
  }
}

Example 4: PrintNode Printing

Secret:
Name: printnode_api_key
Value: abc123xyz789...
Route config:
{
  "inject_headers_json": {
    "Authorization": "Basic {{secret:printnode_api_key}}"
  },
  "inject_body_json": {
    "printerId": 123,
    "title": "Receipt",
    "contentType": "pdf_uri",
    "content": "https://example.com/receipt.pdf",
    "source": "KnoxCall POS"
  }
}

Example 5: Multi-Service Orchestration

Secrets:
stripe_key
sendgrid_key
twilio_key
Route config:
{
  "inject_headers_json": {
    "X-Service": "orchestrator"
  },
  "inject_body_json": {
    "actions": [
      {
        "service": "payment",
        "api_key": "{{secret:stripe_key}}",
        "action": "charge"
      },
      {
        "service": "email",
        "api_key": "{{secret:sendgrid_key}}",
        "action": "send_receipt"
      },
      {
        "service": "sms",
        "api_key": "{{secret:twilio_key}}",
        "action": "send_notification"
      }
    ]
  }
}

Combining Secrets with Other Templates

You can combine secrets with other template variables (coming soon):
{
  "Authorization": "Bearer {{secret:api_key}}",
  "X-User-ID": "{{header:x-user-id}}",
  "X-Request-ID": "{{uuid}}"
}
Currently supported:
  • {{secret:name}} - Inject secrets
Coming soon:
  • {{header:name}} - Pass through headers
  • {{env:name}} - Environment variables
  • {{uuid}} - Generate UUID

Security Considerations

What Gets Logged

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

Secret Transmission

Flow:
1. Client makes request to KnoxCall

2. KnoxCall receives request

3. Loads route configuration

4. Sees {{secret:stripe_key}} template

5. Decrypts secret SERVER-SIDE

6. Replaces template with plaintext

7. Forwards request to backend

8. Backend receives real API key

9. Client NEVER sees the plaintext!

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:
    {
      "X-Test-Secret": "{{secret:test_api_key}}"
    }
    
  3. Make request:
    curl -X POST https://YOUR-SUBDOMAIN.knoxcall.com/anything \
      -H "x-knoxcall-route: test-route" \
      -H "x-knoxcall-key: YOUR_KEY"
    
  4. Check response:
    {
      "headers": {
        "X-Test-Secret": "your-actual-secret-value-here"
      }
    }
    
✅ If you see actual value, injection works!

Quick Reference

Use CaseTemplate SyntaxExample
Header{{secret:name}}"Authorization": "Bearer {{secret:api_key}}"
Body{{secret:name}}"api_key": "{{secret:api_key}}"
MultipleMultiple templates{{secret:key1}} and {{secret:key2}}
EnvironmentDifferent secret per envProduction: {{secret:prod_key}}

Next Steps


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.