Secret Offloading
MirApi provides two ways to keep upstream API credentials out of your application code and out of your logs. Both approaches inject the Authorization header into the upstream request at the proxy edge — your backend code never needs to hold plaintext secrets.
Option 1: Ephemeral Pass-Through (X-Identity-Key)
Section titled “Option 1: Ephemeral Pass-Through (X-Identity-Key)”Pass your API key in the X-Identity-Key header. MirApi reads it into memory, injects it as the Authorization header into the upstream request, and never writes it to any log or persistent storage.
curl -X POST https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Target-URL: https://api.stripe.com/v1/charges" \ -H "X-Identity-Key: Bearer sk_live_xxxxxxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{"amount": 2000, "currency": "usd", "source": "tok_visa"}'What happens:
X-Identity-Key: Bearer sk_live_...is read from your request header- The header is stripped from the request (never forwarded as
X-Identity-Key) Authorization: Bearer sk_live_...is injected into the upstream request- Stripe receives a standard
Authorizationheader - The key value is never written to any log
Your application logs may show the outbound header name but the value should be kept in your secrets manager. MirApi’s internal logs never record header values.
Use Cases for X-Identity-Key
Section titled “Use Cases for X-Identity-Key”# Stripe paymentcurl -X POST https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Target-URL: https://api.stripe.com/v1/charges" \ -H "X-Identity-Key: Bearer sk_live_..." \ -d '{"amount": 2000, "currency": "usd", "source": "tok_visa"}'
# OpenAI chat completioncurl -X POST https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Target-URL: https://api.openai.com/v1/chat/completions" \ -H "X-Identity-Key: Bearer sk-proj-..." \ -H "Content-Type: application/json" \ -d '{"model": "gpt-4o", "messages": [{"role": "user", "content": "Hello"}]}'
# Twilio (with Basic auth format)curl -X POST https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Target-URL: https://api.twilio.com/2010-04-01/Accounts/$ACCOUNT_SID/Messages" \ -H "X-Identity-Key: Basic $TWILIO_B64_CREDENTIALS" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "To=+1234567890&From=+0987654321&Body=Hello"
# Any API that uses a custom API key header — use the header directly insteadcurl https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Target-URL: https://api.sendgrid.com/v3/mail/send" \ -H "Authorization: Bearer SG.xxx..." # Pass directly if the key isn't secret from logsOption 2: Encrypted Database Storage (X-Proxy-Master-Key)
Section titled “Option 2: Encrypted Database Storage (X-Proxy-Master-Key)”Store your upstream credentials encrypted in the MirApi database. At request time, provide the decryption passphrase in X-Proxy-Master-Key. The gateway decrypts the credential and injects it as Authorization — your passphrase and the plaintext credential are never stored together.
This approach is more secure for production environments because:
- Your application only stores the master passphrase (not the upstream API keys)
- Rotating upstream credentials is done in the MirApi dashboard — no code deploys needed
- Multiple credentials can be managed centrally
Setting Up Encrypted Credentials
Section titled “Setting Up Encrypted Credentials”- Open your MirApi dashboard → Credentials → Add Credential
- Enter:
- Name: A label (e.g.,
stripe-production) - Target host pattern:
api.stripe.com(or a substring match) - Value: Your API key (
sk_live_...) - Encryption passphrase: Your master key
- Name: A label (e.g.,
- The dashboard encrypts the value using AES-GCM and stores only the ciphertext
Using Encrypted Credentials
Section titled “Using Encrypted Credentials”# Gateway matches credential by target host ("api.stripe.com" matches the stored pattern)curl -X POST https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Target-URL: https://api.stripe.com/v1/charges" \ -H "X-Proxy-Master-Key: my-master-passphrase" \ -H "Content-Type: application/json" \ -d '{"amount": 2000, "currency": "usd", "source": "tok_visa"}'The gateway:
- Reads
X-Proxy-Master-Keyfrom the request - Looks up credentials in the database that match the target hostname
- Decrypts the stored ciphertext using the provided passphrase
- Injects
Authorization: Bearer sk_live_...into the upstream request - The passphrase and plaintext are discarded from memory after the request
Explicit Credential Selection
Section titled “Explicit Credential Selection”If you have multiple credentials matching the same hostname, specify which one to use:
# Production credentialcurl -X POST https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Target-URL: https://api.stripe.com/v1/charges" \ -H "X-Proxy-Master-Key: my-master-passphrase" \ -H "X-Credential-ID: 4a2e5d18-df99-4d66-a212-3cb5d9f0f9b3" \ -d '{"amount": 2000}'
# Staging credential (different UUID, same passphrase)curl -X POST https://proxy.mirapi.io/ \ -H "X-MirApi-Key: $MIRAPI_KEY" \ -H "X-Target-URL: https://api.stripe.com/v1/charges" \ -H "X-Proxy-Master-Key: my-master-passphrase" \ -H "X-Credential-ID: 9b7c3f21-aa44-4e9d-bc01-1234567890ab" \ -d '{"amount": 100}'Credential Rotation
Section titled “Credential Rotation”Rotating a compromised key requires only a dashboard update — no code change or deployment:
- In the dashboard, find the credential
- Update the value with the new API key (re-encrypted with the same passphrase)
- All future requests immediately use the new key
Comparison
Section titled “Comparison”X-Identity-Key | X-Proxy-Master-Key | |
|---|---|---|
| Storage | Passed per-request, never stored | Stored encrypted in DB |
| Setup | None — just include the header | Requires dashboard setup |
| Key rotation | Change value in your app/secrets manager | Change only in MirApi dashboard |
| Best for | Development, simple setups, or keys already in your secrets manager | Production multi-service environments |