Files
nick-doc/03 - API Reference/Authentication API.md
2026-05-23 20:35:34 +03:30

11 KiB

title, tags
title tags
Authentication API
api
auth
reference

Authentication API

All endpoints are mounted under /api/auth/* in backend/src/app.ts. The routes file is backend/src/services/auth/authRoutes.ts and the WebAuthn sub-routes are in passkeyRoutes.ts. Controller logic lives in authController.ts and authService.ts.

Two distinct identities are involved: a User (models/User.ts) and a TempVerification document that holds pending registration data until the email code is confirmed. Tokens are signed JWTs (access + refresh) created in authService. See Authentication Flow for the high-level lifecycle diagram.

Registration

POST /api/auth/register

Description: Start a new registration. Creates a TempVerification document and emails an 8-digit verification code. The actual User is only created once the code is verified. Auth required: No Request body:

{
  email: string;
  firstName?: string;      // default "کاربر"
  lastName?: string;       // default "جدید"
  role?: "buyer" | "seller"; // default "buyer"
  password?: string;       // accepted now or at verify-email-code time
  referralCode?: string;   // optional, links to referrer for [[Points API]]
}

Response 200:

{ "success": true, "message": "Verification code sent ...", "data": { "email": "x@y.z" } }

Errors: 400 validation, 409 USER_EXISTS if email already registered. Side effects:

  • Upserts a TempVerification row.
  • Sends emailService.sendVerificationCodeEmail.
  • No socket emission yet (user does not exist). Source: authController.register

POST /api/auth/verify-email-code

Description: Confirms the registration code. Creates the User, deletes the TempVerification, processes any referral, issues JWT tokens, and starts the session in Redis. Auth required: No Request body:

{
  email: string;
  code: string;            // 8 digits
  password?: string;       // required if not provided at register
}

Response 200:

{
  "success": true,
  "message": "Email verified",
  "data": {
    "user": { "_id": "...", "email": "...", "role": "buyer", ... },
    "tokens": { "accessToken": "...", "refreshToken": "..." }
  }
}

Errors: 400 invalid/expired code, 404 no pending verification, 409 email already taken. Side effects:

  • Creates User, deletes TempVerification.
  • Calls Points API referral hook when referralCode was supplied (emits referral-signup to user-<referrerId>).
  • Stores refresh token in user.refreshTokens.
  • Welcome email via emailService.sendWelcomeEmail.

GET /api/auth/verify-email/:token

Description: Legacy URL-based verification (link in email). Marks isEmailVerified=true. Auth required: No Response 200: { "success": true, "message": "Email verified successfully" } Errors: 400 invalid/expired token.

POST /api/auth/resend-verification

Description: Re-issues the 8-digit code for a pending or unverified user. Auth required: No Request body: { email: string } Response 200: { "success": true, "message": "Verification code resent" } Errors: 400 invalid email, 404 no user/temp record, 429 rate-limited (Redis).

POST /api/auth/force-verify-user

Description: Development-only helper to mark a user verified without going through email. Auth required: No (intended for dev only — gate with env in prod)

Login & sessions

POST /api/auth/login

Description: Email/password login. Validates credentials with bcrypt, signs JWT pair, stores refresh token on user, returns sanitized user object. Auth required: No Request body:

{
  email: string;
  password: string;
}

Response 200:

{
  "success": true,
  "message": "Login successful",
  "data": {
    "user": { "_id": "...", "email": "...", "role": "buyer", "firstName": "..." },
    "tokens": { "accessToken": "...", "refreshToken": "..." }
  }
}

Errors:

  • 400 validation
  • 401 invalid credentials
  • 403 email not verified
  • 423 account locked (after repeated failures, tracked in Redis via rateLimitService) Side effects:
  • Updates user.lastLoginAt.
  • Pushes refresh token onto user.refreshTokens.
  • Redis session start via sessionService.

POST /api/auth/refresh-token

Description: Exchanges a refresh token for a new access token. Rotates the refresh token. Auth required: No (refresh token in body) Request body: { refreshToken: string } Response 200: { "success": true, "data": { "tokens": { "accessToken": "...", "refreshToken": "..." } } } Errors: 401 token expired / not present in user record, 403 user disabled.

POST /api/auth/logout

Description: Removes the current refresh token from the user record and clears the Redis session. Auth required: Bearer JWT Response 200: { "success": true, "message": "Logged out" } Side effects: redisService session removed.

Google OAuth

POST /api/auth/google/signup

Description: Verifies a Google ID token, creates a new User (no password), optionally links a referral, returns JWT tokens. Auth required: No Request body:

{
  googleToken: string;
  role?: "buyer" | "seller";
  referralCode?: string;
}

Response 200: Same shape as verify-email-code response. Errors: 400 invalid Google token, 409 email already registered (suggest sign-in instead).

POST /api/auth/google/signin

Description: Verifies a Google ID token and signs in an existing user. Will not create a new account. Auth required: No Request body: { googleToken: string } Response 200: { success, data: { user, tokens } } Errors: 400 invalid token, 404 no user with that Google email.

Passkey / WebAuthn

Routes are nested under /api/auth/ via passkeyRoutes. Service: passkeyService.ts.

POST /api/auth/passkey/authenticate/challenge

Description: Generates a sign-in challenge that the browser/authenticator will sign. No userId required — the assertion will identify the user. Auth required: No Response 200: { "success": true, "challenge": { /* PublicKeyCredentialRequestOptions */ } }

POST /api/auth/passkey/authenticate

Description: Verifies the WebAuthn assertion and, on success, returns a JWT pair. Auth required: No Request body: { challenge, assertion } (assertion is the browser's navigator.credentials.get() output). Response 200: { "success": true, "userId": "...", "user": { ... }, "tokens": { ... } } Errors: 400 missing fields, 404 Passkey not found, 500 verification error.

POST /api/auth/passkey/register/challenge

Description: Generates a registration challenge for the authenticated user. Auth required: Bearer JWT Response 200: { "success": true, "challenge": { /* PublicKeyCredentialCreationOptions */ } }

POST /api/auth/passkey/register

Description: Verifies a new passkey registration and stores the credential on the user. Auth required: Bearer JWT Request body: { challenge, credential } Response 200: { "success": true, "message": "Passkey registered successfully" }

GET /api/auth/passkey/list

Description: Returns the calling user's registered passkeys (id, label, created date). Auth required: Bearer JWT Response 200: { "success": true, "passkeys": [...] }

DELETE /api/auth/passkey/:passkeyId

Description: Removes a passkey by id. Auth required: Bearer JWT Response 200: { "success": true, "message": "Passkey removed successfully" }

Password management

POST /api/auth/request-password-reset

Description: Generates a reset token, stores it on the user, and emails a reset link plus a numeric code. Auth required: No Request body: { email: string } Response 200: { "success": true, "message": "Password reset email sent" } (always returns success to avoid email enumeration). Side effects: emailService.sendPasswordResetEmail; rate-limited per IP via Redis.

POST /api/auth/reset-password

Description: Sets a new password using a token from the reset email. Wipes refresh tokens. Auth required: No Request body:

{
  token: string;
  password: string;        // 6+ chars, mixed case + digit
}

Response 200: { "success": true, "message": "Password updated" } Errors: 400 invalid/expired token or weak password.

POST /api/auth/reset-password-with-code

Description: Alternative reset flow using a numeric code instead of a tokenised URL. Auth required: No Request body: { email, code, password } Response 200: { "success": true }

POST /api/auth/change-password

Description: Authenticated password change. Auth required: Bearer JWT Request body:

{
  currentPassword: string;
  newPassword: string;     // 6+ chars, mixed case + digit
}

Response 200: { "success": true, "message": "Password updated" } Errors: 400 validation, 401 wrong current password. Side effects: Clears user.refreshTokens (forces re-login on other devices).

Current user / profile

GET /api/auth/profile

Description: Returns the full sanitized User document for the caller. Auth required: Bearer JWT Response 200: { "success": true, "data": { /* User */ } }

PUT /api/auth/profile (and POST /api/auth/update-profile)

Description: Updates the caller's profile (first/last name, phone, bio, website, language/currency preferences). Auth required: Bearer JWT Request body: Partial profile, see updateProfileValidation:

{
  firstName?: string;       // 2-50
  lastName?: string;        // 2-50
  profile?: {
    phone?: string;         // E.164-ish
    bio?: string;           // <=500
    website?: string;       // URL
  };
  preferences?: {
    language?: "en" | "fa" | "ar";
    currency?: "USD" | "EUR" | "IRR" | "AED";
  };
}

Response 200: Updated user. Errors: 400 validation.

Account deletion

DELETE /api/auth/account

Description: Permanently deletes the caller's account after re-authenticating with password. Auth required: Bearer JWT Request body: { password: string } Response 200: { "success": true, "message": "Account deleted" } Errors: 401 bad password. Side effects: Removes User document, clears Redis session, cascades configured by dataCleanupService.

Error codes summary

HTTP App code Meaning
400 Validation Error express-validator rejected the body
401 Bad credentials / missing token
403 Email not verified or insufficient role
409 USER_EXISTS Email already in use
423 Account temporarily locked after failed logins

See Error Codes for the global error shape.