Authentication
How authentication works in Valvet
Valvet uses a dual-token authentication system for the web UI and a separate bearer token system for node agents.
User Authentication
Login Flow
- User submits username and password to
POST /api/v1/auth/login - Password is verified against the argon2id hash stored in the database
- On success, the API returns a JWT access token and sets an HTTP-only refresh cookie
Access Tokens
- Type: JWT (JSON Web Token)
- Expiry: 15 minutes
- Transport:
Authorization: Bearer <token>header - Contents: User ID, username, role, issued/expiry timestamps
Refresh Tokens
- Expiry: 30 days
- Transport: HTTP-only cookie (not accessible to JavaScript)
- Rotation: Each refresh issues a new token pair and invalidates the old refresh token
Session Management
Users can view and revoke active sessions from Settings → Sessions. Revoking a session invalidates its refresh token immediately.
Node Authentication
Enrollment Tokens
Enrollment tokens are created by admins in the web UI or via the API. They are one-time-use by default and can have an expiry date.
When a node enrolls:
- Node sends the enrollment token to
POST /api/v1/auth/enroll - Hub verifies the token, creates a node record, generates a permanent bearer token
- The permanent token is returned to the node and stored in its local config
- The enrollment token is consumed (uses decremented)
Node Bearer Tokens
- Type: Random token, SHA-256 hashed in the database
- Expiry: None (permanent until revoked)
- Transport:
Authorization: Bearer <token>header on API calls and WebSocket connections
WebSocket Token Rotation
For WebSocket connections, nodes use short-lived tokens:
- Node requests a WebSocket token via
POST /api/v1/nodes/:id/ws-token - Hub returns a token valid for 60 seconds
- Node connects to
/api/v1/ws?token=<ws-token> - Tokens are rotated periodically during the connection lifetime
Password Security
All passwords are hashed with argon2id using the default recommended parameters. Plaintext passwords are never stored or logged.