Skip to main content
Routes define which outbound requests cordon intercepts and what credentials to inject. Each route matches on a destination hostname and specifies an auth type.

Route structure

[[routes]]
name = "stripe"

[routes.match]
host = "api.stripe.com"

[routes.auth]
type = "bearer"

[routes.auth.secret]
source = "1password"
vault = "Engineering"
item = "Stripe API Key"
field = "secret_key"
FieldTypeRequiredDescription
namestringYesIdentifier for the route (used in logs).
match.hoststringYesHostname to match (case-insensitive).
auth.typestringYesbearer, basic, or api_key.
auth.usernamestringbasic onlyUsername for HTTP Basic authentication.
auth.header_namestringapi_key onlyCustom header name for API key injection.
auth.secretobjectYesSecret source reference. See Secret Sources.

Auth types

Bearer token

Injects an Authorization: Bearer <secret> header.
[routes.auth]
type = "bearer"

[routes.auth.secret]
source = "1password"
vault = "Engineering"
item = "Stripe API Key"
field = "secret_key"

Basic auth

Injects an Authorization: Basic <base64(username:secret)> header.
[routes.auth]
type = "basic"
username = "myuser"

[routes.auth.secret]
source = "keyring"
account = "my-basic-cred"

API key header

Injects a custom header with the secret value.
[routes.auth]
type = "api_key"
header_name = "X-Api-Key"

[routes.auth.secret]
source = "keyring"
account = "example-api-key"

How matching works

  • Cordon matches on the hostname of the outbound request (case-insensitive)
  • For matched routes, cordon strips any existing auth header and replaces it with the real credential
  • Unmatched requests are forwarded without modification
  • Routes are evaluated in order; the first match wins
Auth stripping is unconditional for matched routes. If your application sends Authorization: Bearer placeholder, cordon removes it and injects the real token. This is by design — it prevents accidental credential leakage if the application has a real token.

Multiple routes

You can configure multiple routes for different APIs:
[[routes]]
name = "anthropic"

[routes.match]
host = "api.anthropic.com"

[routes.auth]
type = "bearer"

[routes.auth.secret]
source = "1password"
vault = "Engineering"
item = "Anthropic API Key"
field = "credential"

[[routes]]
name = "openai"

[routes.match]
host = "api.openai.com"

[routes.auth]
type = "bearer"

[routes.auth.secret]
source = "1password"
vault = "Engineering"
item = "OpenAI API Key"
field = "credential"

[[routes]]
name = "stripe"

[routes.match]
host = "api.stripe.com"

[routes.auth]
type = "bearer"

[routes.auth.secret]
source = "1password"
vault = "Engineering"
item = "Stripe API Key"
field = "secret_key"

PostgreSQL services

For database connections, cordon can inject credentials at the wire protocol level using TCP services instead of HTTP routes:
[[services]]
name = "prod-db"
listen = 15432
upstream = "db.prod.example.com:5432"
protocol = "postgres"

[services.auth]
type = "password"
username = "app_user"

[services.auth.secret]
source = "1password"
vault = "Engineering"
item = "Postgres Prod"
field = "password"
Connect your application to localhost:15432 instead of the upstream database. Cordon injects the password during the PostgreSQL authentication handshake.