Skip to content

Authentication

Describe the authentication model for both human users and edge nodes.

Users authenticate at POST /api/v1/auth/login and receive a stateless HS256 JWT. The token’s custom claims (internal/auth) are tid (tenant), sub (user id), email and role, plus standard iss/aud/exp. Every /api/v1 request carries it as a Bearer token; the middleware validates it, rejects tokens missing tid/sub, and pins the request to the tenant. WebSocket endpoints (/ws/supervisor, /ws/agent) verify the token from a ?token= query parameter since browsers can’t set headers on the upgrade.

Edge nodes use a separate scheme: a raw API key (issued at registration) presented as a bearer token and matched against the SHA-256 digest in nodes.api_key_hash.

Terminal window
AUTH_JWT_SECRET=... # signing secret, >= 16 bytes
AUTH_JWT_ISSUER=get2dial
AUTH_JWT_AUDIENCE=get2dial-control
AUTH_JWT_TTL_SECONDS=43200 # 12h
AUTH_BCRYPT_COST=12
AUTH_BOOTSTRAP_TOKEN= # empty disables POST /api/v1/auth/bootstrap
DEFAULT_TENANT_DOMAIN=dev.get2dial.local # login fallback workspace

Login accepts {email, password, tenant_domain?}. With tenant_domain omitted, the workspace is resolved from the email (the password disambiguates collisions), falling back to DEFAULT_TENANT_DOMAIN. A successful login returns a JWT the web app sends on every subsequent request:

GET /api/v1/auth/me
Authorization: Bearer <jwt>
  • JWTs are statelessPOST /api/v1/auth/logout is audit-only; there is no server-side revocation yet, so keep the TTL sane.
  • Failed logins lock the account after 10 attempts for 15 minutes and return generic errors to avoid enumeration.
  • Rotating AUTH_JWT_SECRET invalidates all outstanding tokens.