Networking & Security
HelloJohn's network security model — rate limiting, CORS configuration, TLS requirements, security headers, and IP allowlisting.
TLS / HTTPS
All production HelloJohn instances must run behind TLS. The server itself does not terminate TLS — run it behind a reverse proxy (nginx, Caddy, Traefik, Cloudflare) that handles SSL.
server {
listen 443 ssl;
server_name auth.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/auth.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/auth.yourdomain.com/privkey.pem;
location / {
proxy_pass http://localhost:3100;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto https;
}
}Set X-Forwarded-Proto: https in your reverse proxy. HelloJohn uses this header to determine if the request is over HTTPS. Without it, some security checks may behave incorrectly.
CORS
Configure allowed origins per-tenant. Requests from unlisted origins are rejected with 403 Forbidden.
# Comma-separated list of allowed origins
HELLOJOHN_ALLOWED_ORIGINS=https://app.yourdomain.com,https://admin.yourdomain.comOr per-tenant via the API:
curl -X PATCH https://your-instance.com/cp/v1/tenants/tnt_01HABCDEF \
-H "Authorization: Bearer {cp_admin_token}" \
-d '{"allowed_origins": ["https://app.yourdomain.com"]}'CORS preflight: HelloJohn handles OPTIONS preflight requests automatically. No additional configuration needed for standard CORS headers.
Rate limiting
HelloJohn applies rate limits per IP and per client to protect against brute force and abuse.
Default limits
| Endpoint | Limit | Window |
|---|---|---|
POST /v1/auth/sign-in | 10 requests | 1 minute per IP |
POST /v1/auth/sign-up | 5 requests | 1 minute per IP |
POST /v1/auth/refresh | 30 requests | 1 minute per session |
POST /v1/mfa/verify | 5 requests | 5 minutes per user |
POST /v1/auth/forgot-password | 3 requests | 10 minutes per IP |
| All other endpoints | 100 requests | 1 minute per client key |
Rate limit response
When a rate limit is exceeded, HelloJohn returns:
HTTP/1.1 429 Too Many Requests
Retry-After: 45
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1700000045
{
"error": "rate_limit_exceeded",
"message": "Too many requests. Please try again in 45 seconds.",
"retry_after": 45
}Configuring rate limits
# Disable rate limiting (development only)
HELLOJOHN_RATE_LIMIT_ENABLED=false
# Redis for distributed rate limiting (required for multi-instance)
HELLOJOHN_REDIS_URL=redis://localhost:6379For multi-instance deployments, configure Redis. Without Redis, rate limits are tracked in-memory per instance and won't be coordinated across replicas.
Security headers
HelloJohn automatically sets the following response headers:
| Header | Value | Purpose |
|---|---|---|
X-Content-Type-Options | nosniff | Prevent MIME sniffing |
X-Frame-Options | DENY | Prevent clickjacking |
Referrer-Policy | strict-origin-when-cross-origin | Limit referrer leakage |
Strict-Transport-Security | max-age=63072000; includeSubDomains | Force HTTPS |
Content-Security-Policy | Configurable | Prevent XSS |
You can add or override headers in your reverse proxy:
add_header X-Custom-Header "value" always;IP allowlisting
Restrict access to the Control Plane API to specific IP ranges:
# Only allow these IPs to access /cp/* endpoints
HELLOJOHN_CP_ALLOWED_IPS=10.0.0.0/8,203.0.113.0/24For the Data Plane, IP allowlisting is not recommended (your users' IPs are unknown). Use it only for server-to-server API key endpoints.
Trusted proxies
If running behind a load balancer, configure trusted proxy IPs so HelloJohn reads X-Forwarded-For for the real client IP:
# Trust these proxies for X-Forwarded-For
HELLOJOHN_TRUSTED_PROXIES=10.0.0.0/8Without this, all requests appear to come from the proxy IP, breaking per-IP rate limiting.
Ports
| Port | Default | Description |
|---|---|---|
| HTTP | 3100 | Main API server (HTTP, not HTTPS) |
| Metrics | 9090 | Prometheus metrics endpoint |
| Health | 3100/health | Liveness/readiness probe |
Health checks
# Liveness probe
GET /health
→ 200 OK { "status": "ok" }
# Readiness probe (checks DB connection)
GET /health/ready
→ 200 OK { "status": "ready", "db": "ok", "redis": "ok" }
→ 503 Service Unavailable { "status": "not_ready", "db": "error" }Next steps
Database Schema
HelloJohn's database schema — global tables for the Control Plane and per-tenant tables for the Data Plane. Entity relationships, primary keys, and key indexes.
Authentication Overview
HelloJohn supports email/password, OAuth (9 providers), magic links, passkeys, and MFA. Learn which auth method to use and how they work together.