Overview
rs-tunnel implements a security model designed to protect sensitive credentials and enforce strict access controls. The API holds all provider secrets, while the CLI receives only the minimum credentials needed to run tunnels.Security Model
FromAGENTS.md:49-54:
Security model
- Provider secrets (
CLOUDFLARE_API_TOKEN, Slack secrets, JWT secrets) belong only in API runtime.- CLI receives short-lived tunnel run token from API; never provider token.
- Do not log secrets, JWTs, refresh tokens, or Cloudflare tokens.
- Keep least-privilege scopes for Cloudflare token (Tunnel + DNS only).
Token Separation
The system uses two types of tokens with clear separation of concerns:Cloudflare API Token
Held by: API server onlyUsed for: Creating tunnels, managing DNS recordsScope: Cloudflare Tunnel + DNS edit permissionsNever exposed to: CLI, end users
Cloudflare Tunnel Token
Held by: CLI (short-lived)Used for: Running
cloudflared processScope: Single tunnel onlyGenerated by: API server per tunnelAPI Token Security
Fromapps/api/src/config/env.ts:35:
Use Cloudflare API tokens with minimal scopes: Tunnel edit + DNS edit for the specific zone only.
Tunnel Token Delivery
Fromapps/api/src/services/tunnel.service.ts:63-92:
- Creates a Cloudflare tunnel using the API token
- Retrieves the tunnel-specific token
- Returns the tunnel token to the CLI
cloudflared but cannot use it to create or delete tunnels.
Authentication Flow
rs-tunnel uses OAuth 2.0 with Slack as the identity provider, plus PKCE for additional security.PKCE Flow
Fromapps/api/src/services/auth.service.ts:37-67:
Generate code verifier
CLI generates a random code verifier and computes the SHA-256 code challenge.
Start OAuth flow
CLI sends code challenge to API, which creates an OAuth session and returns the Slack authorize URL.
PKCE Verification
Fromapps/api/src/services/auth.service.ts:146-149:
PKCE (Proof Key for Code Exchange) adds security to OAuth flows for public clients like the CLI.
JWT and Refresh Tokens
Access Token (JWT)
Fromapps/api/src/services/token.service.ts:12-17:
- Default TTL: 15 minutes
- Algorithm: HS256
- Signed with:
JWT_SECRETenvironment variable
Refresh Token
Fromapps/api/src/services/token.service.ts:39-41:
- Default TTL: 30 days
- Format: 48 random bytes, base64url encoded
- Storage: SHA-256 hash stored in database
Token Hashing
Fromapps/api/src/services/token.service.ts:43-45:
Refreshing Access Tokens
Fromapps/api/src/services/auth.service.ts:170-186:
- The old refresh token is revoked (rotation)
- A new access token and refresh token are issued
- This prevents refresh token reuse attacks
Access Controls
Allowed Email Domain
Fromapps/api/src/config/env.ts:28-31:
AGENTS.md:41:
Only emails ending in ALLOWED_EMAIL_DOMAIN are allowed.
Example configuration:
apps/api/src/services/auth.service.ts:86-88:
Allowed Slack Workspace
Fromapps/api/src/config/env.ts:32:
AGENTS.md:42:
Slack workspace must match ALLOWED_SLACK_TEAM_ID.
From apps/api/src/services/auth.service.ts:98-100:
Security Best Practices
Secret Management
Environment Variables
Store secrets in
.env files (never committed) or environment variables.Secret Rotation
Rotate secrets periodically:
- JWT_SECRET: Invalidates all sessions
- Cloudflare API token: Update in provider dashboard
- Slack secrets: Regenerate in Slack app settings
Logging Security
FromAGENTS.md:53:
Do not log secrets, JWTs, refresh tokens, or Cloudflare tokens.Never log:
JWT_SECRETCLOUDFLARE_API_TOKENSLACK_CLIENT_SECRET- User access tokens or refresh tokens
- Cloudflare tunnel tokens
- User email (for audit purposes)
- Tunnel IDs
- Request metadata (paths, status codes)
- Error messages (without token values)
Least Privilege
FromAGENTS.md:54:
Keep least-privilege scopes for Cloudflare token (Tunnel + DNS only).Cloudflare API Token Permissions:
- Account: Cloudflare Tunnel (Edit)
- Zone: DNS (Edit) - for the specific zone only
- Account-level admin permissions
- Zone-level admin permissions
- Access to other zones
- Billing or API token management permissions
Create a scoped API token in the Cloudflare dashboard under “My Profile” → “API Tokens”.
Network Security
HTTPS Only
Always run the API behind HTTPS in production.
Rate Limiting
API routes have rate limits to prevent abuse:
- Telemetry: 1200 req/min
- Auth endpoints: Standard limits
Database Security
Connection Encryption
Use SSL/TLS for database connections in production.
Credential Storage
Store refresh tokens as SHA-256 hashes, not plaintext.Implemented in
apps/api/src/services/token.service.ts:43-45Audit Logging
The system logs security-relevant events for audit purposes:Logged Events
Fromapps/api/src/services/auth.service.ts:116-120:
auth.oauth.authorized: User completed OAuth flowtunnel.created: Tunnel createdtunnel.stopped: Tunnel stopped (includes reason)
Audit Log Query
Query audit logs to investigate security incidents:Incident Response
If a security incident occurs:Security Checklist
Before deploying to production:Secrets
- Strong, random JWT_SECRET (32+ chars)
- Scoped Cloudflare API token
- Secrets stored in environment, not code
- No secrets in logs
Access Controls
- ALLOWED_EMAIL_DOMAIN configured
- ALLOWED_SLACK_TEAM_ID configured
- OAuth callback URL is HTTPS
- Rate limits enabled
Network
- API served over HTTPS
- Database connection uses SSL
- API_BASE_URL uses https://
- CORS configured appropriately
Monitoring
- Audit logs enabled
- Failed auth attempts monitored
- Alerts for quota exceeded spikes
- Regular secret rotation schedule

