The Pay Plugin uses API keys for authentication. API keys should never be hardcoded in configuration files that are committed to version control.
✅ DO:
- Store API keys in environment variables
- Use
.envfiles for local development (never commit) - Use secret management systems in production (HashiCorp Vault, AWS Secrets Manager, etc.)
- Rotate API keys regularly
- Use different keys for different environments
- Apply principle of least privilege to key scopes
❌ DON'T:
- Hardcode API keys in
config.json - Commit API keys to version control
- Share API keys in plain text
- Use production keys in development
- Use the same key across all environments
Set the PAY_API_KEYS environment variable with comma-separated values:
export PAY_API_KEYS=key1,key2,key3
build\windows-msvc\examples\pay-server\Release\PayServer.exeOr use a single key with PAY_API_KEY:
export PAY_API_KEY=your-single-api-key
build\windows-msvc\examples\pay-server\Release\PayServer.exe- Copy the example file:
cp .env.example .env- Edit
.envwith your actual keys:
PAY_API_KEYS=test-dev-key,performance-test-key,admin-test-key- Source the file before running:
source .env
build\windows-msvc\examples\pay-server\Release\PayServer.exeWARNING: Never commit .env to version control! It's already in .gitignore.
# docker-compose.yml
version: '3.8'
services:
pay-server:
image: pay-server:latest
secrets:
- api_keys
environment:
- PAY_API_KEYS_FILE=/run/secrets/api_keys
secrets:
api_keys:
file: ./secrets/api_keys.txtapiVersion: v1
kind: Secret
metadata:
name: pay-api-keys
type: Opaque
stringData:
keys: "key1,key2,key3"
---
apiVersion: apps/v1
kind: Deployment
spec:
template:
spec:
containers:
- name: pay-server
env:
- name: PAY_API_KEYS
valueFrom:
secretKeyRef:
name: pay-api-keys
key: keysaws secretsmanager create-secret \
--name prod/pay/api-keys \
--secret-string "key1,key2,key3"
# Application retrieves using AWS SDKvault kv put secret/pay/api-keys \
keys="key1,key2,key3"Configure scopes in config.json to control what each key can do:
{
"custom_config": {
"pay": {
"api_key_scopes": {
"test-dev-key": ["read", "write", "admin", "order_query", "refund_query", "refund"],
"performance-test-key": ["read", "write", "order_query", "refund_query"],
"admin-test-key": ["read", "write", "admin", "order_query", "refund_query", "refund", "reconcile"],
"prod-api-key": ["read", "order_query"]
},
"api_key_default_scopes": ["read"]
}
}
}Scopes are resolved from the request path relative to the configured
base_path (default /api/pay). The enforced scopes are:
| Scope | Endpoint it gates | Description |
|---|---|---|
order_query |
GET {base}/query |
Query payment orders |
refund |
POST {base}/refund |
Create refunds |
refund_query |
GET {base}/refund/query |
Query refund status |
reconcile |
GET {base}/reconcile/summary |
Access reconciliation data |
Note: routes that resolve to no scope (e.g. create payment, QR create, the
metrics endpoints) are not scope-gated — only a valid API key is required.
Other scope strings (such as read) may appear in a key's scope list but are
not matched by any route and have no effect.
# Using X-Api-Key header
curl -H "X-Api-Key: test-dev-key" \
http://localhost:5566/api/pay/query?order_no=test_123
# Using Authorization Bearer header
curl -H "Authorization: Bearer test-dev-key" \
http://localhost:5566/api/pay/query?order_no=test_123# Test each key has appropriate scopes
for key in "test-dev-key" "performance-test-key" "admin-test-key"; do
echo "Testing key: $key"
curl -s -H "X-Api-Key: $key" \
-H "X-Api-Key: test-dev-key" \
http://localhost:5566/api/pay/query?order_no=test_123
doneTo rotate API keys without downtime:
- Add new key to environment variables
- Update clients to use new key
- Monitor for successful migration
- Remove old key from environment variables
- Restart server
Example:
# Phase 1: Add new key
export PAY_API_KEYS="old-key,new-key"
# Phase 2: After clients updated (e.g., 24 hours later)
export PAY_API_KEYS="new-key"
# Phase 3: Restart service
systemctl restart pay-serverCause: No API keys in environment variables or config.json
Solution: Set PAY_API_KEYS or PAY_API_KEY environment variable
Cause: Request doesn't include X-Api-Key or Authorization header
Solution: Add API key to request headers
Cause: Provided API key is not in the allowed list
Solution: Check environment variables and ensure key is present
Cause: API key doesn't have permission for this endpoint
Solution: Check api_key_scopes in config.json and verify key has required scope
- API keys stored in environment variables
- No hardcoded keys in config.json
-
.envfile in.gitignore - Different keys for dev/staging/prod
- Key scopes follow least privilege principle
- Key rotation procedure documented
- Secret management system configured (if applicable)
- Monitoring for unauthorized access attempts
- Incident response plan for compromised keys