Authentication
Secure your API endpoints with built-in authentication methods. flAPI supports JWT tokens, Basic Auth, API keys, and custom authentication strategies.
Quick Start
Enable authentication in your endpoint configuration:
# sqls/customers.yaml
url-path: /customers/
authentication:
required: true
methods: [jwt] # or [basic], [api-key]
roles: [user, admin] # Optional: Role-based access
request:
- field-name: segment
field-in: query
template-source: customers.sql
Authentication Methods
JWT (JSON Web Tokens)
Best for: Modern web/mobile apps, microservices
# flapi.yaml - Global security configuration
security:
jwt:
secret: ${JWT_SECRET} # Use environment variable
algorithm: HS256
expiration: 3600 # 1 hour
issuer: flapi-server
Endpoint configuration:
# sqls/protected.yaml
authentication:
required: true
methods: [jwt]
roles: [user] # Optional
Usage:
# Get token (implementation-specific)
TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
# Call API with token
curl -H "Authorization: Bearer $TOKEN" \
https://api.example.com/customers/
JWT Payload:
{
"sub": "user123",
"roles": ["user", "admin"],
"exp": 1735689600
}
Basic Authentication
Best for: Simple internal APIs, testing
# flapi.yaml
security:
basic-auth:
users:
- username: admin
password: ${ADMIN_PASSWORD} # Hashed in production
roles: [admin]
- username: viewer
password: ${VIEWER_PASSWORD}
roles: [read]
Endpoint configuration:
authentication:
required: true
methods: [basic]
roles: [admin] # Only admin users
Usage:
curl -u admin:password \
https://api.example.com/admin/users/
API Key Authentication
Best for: Server-to-server integration, third-party access
# flapi.yaml
security:
api-keys:
- key: ${API_KEY_PARTNER_A}
name: Partner A
roles: [api-user]
rate-limit: 10000 # requests/day
- key: ${API_KEY_INTERNAL}
name: Internal Service
roles: [admin]
rate-limit: 1000000
Endpoint configuration:
authentication:
required: true
methods: [api-key]
Usage:
# Header-based (recommended)
curl -H "X-API-Key: sk_live_abc123..." \
https://api.example.com/data/
# Query parameter (less secure)
curl "https://api.example.com/data/?api_key=sk_live_abc123..."
Multiple Methods
Allow multiple authentication methods:
# Endpoint accepts JWT OR API key
authentication:
required: true
methods: [jwt, api-key]
roles: [user]
Role-Based Access Control (RBAC)
Global Roles
Define roles in flapi.yaml
:
security:
roles:
admin:
permissions: [read, write, delete]
user:
permissions: [read, write]
viewer:
permissions: [read]
Endpoint-Level Authorization
Restrict endpoints by role:
# sqls/admin-only.yaml
authentication:
required: true
methods: [jwt]
roles: [admin] # Only admin role
Row-Level Security
Filter data based on user identity:
-- sqls/my-orders.sql
SELECT * FROM orders
WHERE 1=1
{{#context.user.id}}
AND customer_id = '{{context.user.id}}' -- User sees only their orders
{{/context.user.id}}
{{#context.user.roles.admin}}
-- Admins see all orders (no filter)
{{/context.user.roles.admin}}
Column-Level Security
Hide sensitive columns based on role:
-- sqls/customers.sql
SELECT
customer_id,
name,
email
{{#context.user.roles.admin}}
, credit_score -- Only admins see this
, internal_notes
{{/context.user.roles.admin}}
FROM customers
Custom Authentication
Implement custom authentication logic:
# flapi.yaml
security:
custom:
handler: ./auth/custom-handler.py
config:
ldap_server: ${LDAP_SERVER}
api_endpoint: ${AUTH_API}
Security Best Practices
✅ DO
- Use environment variables for secrets
- Enable HTTPS in production
- Set token expiration (1-24 hours)
- Implement rate limiting per user/key
- Log authentication failures
- Use strong secrets (32+ characters)
- Hash passwords (bcrypt, argon2)
- Rotate API keys regularly
❌ DON'T
- Store secrets in YAML files
- Use Basic Auth over HTTP
- Share API keys across services
- Use predictable API keys
- Disable authentication in production
- Expose user tokens in logs
Testing Authentication
Test with curl
# JWT
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8080/customers/
# Basic Auth
curl -u username:password \
http://localhost:8080/customers/
# API Key
curl -H "X-API-Key: test-key-123" \
http://localhost:8080/customers/
Test Authorization
# Should succeed (user has access)
curl -H "Authorization: Bearer $USER_TOKEN" \
http://localhost:8080/orders/
# Should fail 403 (admin required)
curl -H "Authorization: Bearer $USER_TOKEN" \
http://localhost:8080/admin/users/
Error Responses
401 Unauthorized
Missing or invalid credentials:
{
"error": "Unauthorized",
"message": "Missing or invalid authentication token",
"status": 401
}
403 Forbidden
Valid credentials but insufficient permissions:
{
"error": "Forbidden",
"message": "Insufficient permissions. Required role: admin",
"status": 403
}
Environment Configuration
Development
# flapi.yaml
security:
jwt:
secret: dev-secret-change-in-production
expiration: 86400 # 24 hours for dev convenience
export JWT_SECRET="dev-secret-change-in-production"
Production
# flapi.yaml
security:
jwt:
secret: ${JWT_SECRET}
expiration: 3600 # 1 hour
enforce-https: true
# Use strong random secret
export JWT_SECRET=$(openssl rand -hex 32)
Complete Example
# ═══════════════════════════════════════════════════════════════
# flapi.yaml - Global Security
# ═══════════════════════════════════════════════════════════════
security:
enforce-https: true
jwt:
secret: ${JWT_SECRET}
algorithm: HS256
expiration: 3600
issuer: my-company
api-keys:
- key: ${API_KEY_PARTNER}
name: Partner Integration
roles: [api-user]
rate-limit: 10000
roles:
admin:
permissions: [read, write, delete]
user:
permissions: [read, write]
api-user:
permissions: [read]
# ═══════════════════════════════════════════════════════════════
# sqls/orders.yaml - Protected Endpoint
# ═══════════════════════════════════════════════════════════════
url-path: /orders/
authentication:
required: true
methods: [jwt, api-key]
roles: [user, admin]
request:
- field-name: customer_id
field-in: query
required: false
validators:
- type: int
template-source: orders.sql
connection:
- orders-db
-- sqls/orders.sql - Row-level security
SELECT
order_id,
customer_id,
order_date,
total_amount,
status
FROM orders
WHERE 1=1
{{#params.customer_id}}
AND customer_id = {{params.customer_id}}
{{/params.customer_id}}
{{^context.user.roles.admin}}
-- Non-admins see only their own orders
AND customer_id = '{{context.user.id}}'
{{/context.user.roles.admin}}
ORDER BY order_date DESC
Next Steps
- Validation: Validate and sanitize inputs
- Response Format: Structure API responses
- Configuration Service: Manage secrets securely