Register
POST /api/auth/register
Creates a new user account and sends a 6-digit verification code to the provided email. If the email already exists but is not yet verified , the password and display name are updated.
Rate limited to 10 requests per 60 seconds .
Request body
Password - minimum 8 characters.
Optional display name for the user.
{
"email" : "user@example.com" ,
"password" : "securePassword123" ,
"displayName" : "John"
}
Response 201
{
"message" : "Verification code sent to email" ,
"email" : "user@example.com"
}
Response 409
Returned when a verified user with this email already exists.
{
"message" : "User already exists"
}
Verify email
POST /api/auth/verify-email
Verifies the user’s email with the 6-digit code sent during registration. On success, the user is automatically logged in and receives tokens.
Rate limited to 5 requests per 60 seconds .
Request body
The email address to verify.
The 6-digit verification code. Must be exactly 6 characters.
{
"email" : "user@example.com" ,
"code" : "482916"
}
Response 200
Returns the user profile, tokens, and service access - identical to a login response.
{
"user" : {
"id" : "cuid_abc123" ,
"email" : "user@example.com" ,
"displayName" : "John" ,
"avatar" : null
},
"token" : "eyJhbGciOiJIUzI1NiIs..." ,
"refreshToken" : "a1b2c3d4e5f6..." ,
"services" : [
{
"service" : "DROP" ,
"tier" : "free" ,
"isPremium" : false ,
"connected" : true
}
],
"banned" : false ,
"disabled" : false
}
Response 401
{
"message" : "Invalid or expired verification code"
}
Resend verification
POST /api/auth/resend-verification
Resends the email verification code. The previous code is invalidated and a new one is generated with a 15-minute expiry .
Rate limited to 3 requests per 60 seconds .
Request body
The email address to resend the verification code to.
Response 200
{
"message" : "Verification code resent successfully"
}
Response 409
{
"message" : "Email is already verified"
}
Login
POST /api/auth/login
Authenticates a user with email and password. If the user has 2FA enabled, the first call returns a requires2FA flag - call login again with the verificationCode field.
Rate limited to 30 requests per 60 seconds .
Request body
TOTP verification code. Required on the second call when 2FA is enabled.
Flow: standard login
{
"email" : "user@example.com" ,
"password" : "securePassword123"
}
Response 200
{
"user" : {
"id" : "cuid_abc123" ,
"email" : "user@example.com" ,
"displayName" : "John" ,
"avatar" : null
},
"token" : "eyJhbGciOiJIUzI1NiIs..." ,
"refreshToken" : "a1b2c3d4e5f6..." ,
"services" : [
{
"service" : "DROP" ,
"tier" : "free" ,
"isPremium" : false ,
"connected" : true
}
],
"banned" : false ,
"disabled" : false
}
Flow: 2FA login (two-step)
Step 1 - Login without verification code:
{
"email" : "user@example.com" ,
"password" : "securePassword123"
}
Response:
{
"user" : {
"id" : "cuid_abc123" ,
"email" : "user@example.com" ,
"displayName" : "John" ,
"avatar" : null
},
"requires2FA" : true ,
"pendingToken" : "eyJhbGciOiJIUzI1NiIs..." ,
"message" : "2FA verification required"
}
Step 2 - Login with TOTP code:
{
"email" : "user@example.com" ,
"password" : "securePassword123" ,
"verificationCode" : "482916"
}
Returns the standard login response with tokens.
Response 401
If the user’s email is not verified, a new verification code is sent automatically. {
"message" : "Email not verified" ,
"emailVerified" : false ,
"email" : "user@example.com"
}
{
"message" : "Invalid credentials"
}
{
"message" : "Invalid 2FA verification code"
}
Refresh tokens
POST /api/auth/refresh
Exchanges a valid refresh token for a new access token and a new refresh token. The old refresh token is revoked immediately (rotation).
Refresh tokens are valid for 30 days . Each refresh token can only be used once - a new one is issued with each rotation.
Request body
The current refresh token.
Response 200
{
"token" : "eyJhbGciOiJIUzI1NiIs..." ,
"refreshToken" : "new_refresh_token_here..."
}
Response 401
{
"message" : "Invalid or expired refresh token"
}
Get current user
GET /api/auth/me
Returns the authenticated user’s profile.
Requires Authorization: Bearer <token> header.
Response 200
{
"user" : {
"id" : "cuid_abc123" ,
"email" : "user@example.com" ,
"avatar" : "cuid_abc123/avatar_1717596600.png" ,
"displayName" : "John" ,
"twoFactorEnabled" : false ,
"createdAt" : "2026-01-15T10:30:00.000Z" ,
"updatedAt" : "2026-06-05T14:30:00.000Z" ,
"serviceAccess" : [ ... ],
"oauthAccounts" : [ ... ]
}
}
Logout
POST /api/auth/logout
Revokes the current session and all associated refresh tokens.
Requires Authorization: Bearer <token> header. The session ID is extracted from the JWT.
Response 200
Delete account
POST /api/auth/delete-account
Permanently deletes the user’s account and all associated data. Requires password confirmation and, if enabled, a 2FA code.
This action is irreversible . All user data, sessions, service entitlements, and audit logs are permanently deleted.
Request body
Required if the account has a password (non-OAuth-only accounts).
Required if 2FA is enabled on the account.
Response 200
Toggle 2FA
POST /api/auth/2fa
Enables or disables two-factor authentication. Enabling 2FA is a two-step process.
Enable 2FA (step 1) - get QR code
Response:
{
"qrCode" : "data:image/png;base64,..." ,
"manualEntryKey" : "JBSWY3DPEHPK3PXP" ,
"secret" : "JBSWY3DPEHPK3PXP"
}
Enable 2FA (step 2) - confirm with TOTP code
{
"enable" : true ,
"verificationCode" : "482916" ,
"secret" : "JBSWY3DPEHPK3PXP"
}
Response:
Disable 2FA
{
"enable" : false ,
"verificationCode" : "482916"
}
Response: