Skip to main content

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

🍪 Cookie Settings