Overview
BunShip implements a stateful JWT authentication system. Short-lived access tokens (15 minutes) authorize API requests, while long-lived refresh tokens (7 days) are backed by database sessions that can be individually revoked. Two-factor authentication, account lockout, and API key auth are included out of the box.Auth Flow
1
Register
The user submits their email, password, and name. BunShip validates the password against strength rules, hashes it with Argon2id, creates the user record, and sends a verification email.
2
Verify email
The user clicks the link in their verification email. The API marks
emailVerified with the current timestamp.3
Login
The user submits their email and password. On success, the API returns an access token, a refresh token, and basic user info.
4
Make authenticated requests
Include the access token in the
Authorization header of subsequent requests.5
Refresh when the access token expires
When the access token expires (after 15 minutes), call the refresh endpoint to get a new pair. The old refresh token is rotated — each refresh token can only be used once.
JWT Structure
BunShip uses two separate JWT secrets and the jose library for signing and verification.- Access Token
- Refresh Token
Payload:
Session Management
Every login creates a database-backed session record. Sessions store the hashed refresh token, the client’s user agent, IP address, and an expiration timestamp.- List sessions —
GET /api/v1/users/sessions - Revoke one session —
DELETE /api/v1/users/sessions/:id - Revoke all sessions —
DELETE /api/v1/users/sessions(logs out everywhere)
The maximum number of concurrent sessions per user defaults to 5 and is configurable via
featuresConfig.auth.maxSessionsPerUser.Two-Factor Authentication
BunShip supports TOTP-based two-factor authentication (compatible with Google Authenticator, Authy, 1Password, and similar apps) plus single-use backup codes.Setup Flow
1
Request 2FA setup
The user provides their current password. The API generates a TOTP secret, a QR code URI, and 10 backup codes.
2
Verify with a TOTP code
The user enters a 6-digit code from their authenticator app. This confirms the secret was saved correctly and activates 2FA on the account.
3
Login now requires a second factor
Subsequent login attempts return a
requiresTwoFactor: true error if the twoFactorCode field is omitted:TOTP Parameters
Backup Codes
- 10 codes generated per setup
- Each code is an 8-character hexadecimal string
- Codes are hashed with SHA-256 before storage (the plaintext is never persisted)
- Each code can only be used once — the
usedAttimestamp is set on consumption - Re-running 2FA setup regenerates all backup codes and invalidates the previous set
Password Policies
BunShip validates password strength at registration and password reset. The rules are defined infeaturesConfig.auth.password:
Passwords are hashed using Argon2id with the following parameters (via Bun’s native
Bun.password API or the argon2 library):
- Memory: 65536 KB
- Iterations: 3
- Parallelism: 4
BunShip never stores plaintext passwords. The
passwordHash field in the users table contains
only the Argon2id hash output.Account Lockout
To protect against brute-force attacks, BunShip tracks failed login attempts and temporarily locks accounts.
The lockout logic in
auth.service.ts:
The login endpoint uses constant-time password verification even when the user does not exist,
preventing timing-based user enumeration.
API Key Authentication
API keys provide an alternative to JWT tokens for server-to-server integrations and automated scripts. Keys are scoped to an organization and carry explicit permission scopes.How API Keys Work
- A team member with
api-keys:createpermission generates a key through the API or dashboard - The full key is shown once (format:
bsk_live_...); only the prefix and hash are stored - The caller includes the key in the
Authorizationheader:Bearer bsk_live_... - The API resolves the key to an organization and checks that the key’s scopes grant the required permission
Available Scopes
Key Properties
Limits
See API Keys for usage details and the API Reference for endpoint documentation.
Auth Middleware Reference
BunShip provides two auth middleware variants:Supported Auth Methods
Email + Password
Traditional registration and login with password strength validation and Argon2id hashing.
Magic Link
Passwordless login via a one-time link sent to the user’s email address.
Google OAuth
Social login with Google. Requires
GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET environment
variables.GitHub OAuth
Social login with GitHub. Requires
GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET environment
variables.featuresConfig.auth:

