Documentation
Guides
Authentication

Authentication Guide

Complete guide to implementing authentication in your app.

Overview

Moontraze authentication supports:

  • Email/password registration
  • Login with optional TOTP 2FA
  • MON Authenticator enrollment
  • Password reset via TOTP
  • Change password while logged in
  • Logout
  • Delete end-user account

Moontraze issues and manages all auth tokens for you. You don't need to worry about token secrets, expiry handling, or internal token types — just call the SDK methods, and the correct token is attached to every request automatically.

Signup Flow

Step 1: Register User

const result = await moon.auth.register('user@example.com', 'secret123', 'John');
moon.setToken(result.token);

Step 2: Enroll TOTP (Optional)

const enroll = await moon.auth.enrollTotp();
// enroll.qrPayload — otpauth:// URL
// Show this as QR code to user

Step 3: Confirm TOTP

const code = await promptUser('Enter 6-digit code from app');
await moon.auth.confirmTotp(code);

Login Flow

Step 1: Login

const result = await moon.auth.login('user@example.com', 'secret123');

Step 2: Check if TOTP required

if (result.requiresTotp) {
  const code = await promptUser('Enter code');
  const verified = await moon.auth.verifyTotp(result.loginTicket, code);
  moon.setToken(verified.token);
} else {
  moon.setToken(result.token);
}

Logout

moon.auth.logout();

Change Password (Logged In)

await moon.auth.changePassword('currentSecret', 'newSecret123');

Forgot Password Flow

Step 1: Verify TOTP

const verify = await moon.auth.forgotPasswordVerify('user@example.com', '123456');
// verify.verifyToken — short-lived

Step 2: Reset Password

await moon.auth.forgotPasswordReset(
  'user@example.com',
  verify.verifyToken,
  'newSecret123',
);

Delete End-User Account

Project owners and permitted admins can delete any end-user from their project's Authentication section. End-users can delete their own account.

This endpoint removes only the auth user record. Data stored in the database (posts, chats, reviews, etc.) is not touched — clean it up separately if needed.

Endpoint

DELETE /api/users/:projectId/users/:userId

Authorization

Send the user's JWT token — Moontraze issues and manages it for you:

Authorization: Bearer <token>
X-Project-Id: <projectId>

Moontraze automatically identifies who is making the request and applies the correct permissions:

  • Project owner — can delete any user in their project
  • Admin with delete permission — can delete users in permitted projects
  • End-user — can delete only their own account

You don't need to handle token types, secrets, or permission checks manually. Just send the token and the endpoint does the right thing.

Example — Delete a user

async function deleteUser(
  projectId: string,
  userId: string,
  token: string,
): Promise<{ success: boolean; message: string }> {
  const res = await fetch(
    `https://api.moontraze.com/api/users/${projectId}/users/${userId}`,
    {
      method: 'DELETE',
      headers: {
        Authorization: `Bearer ${token}`,
        'X-Project-Id': projectId,
      },
    },
  );
 
  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(err.error || `HTTP ${res.status}`);
  }
 
  return res.json();
  // { success: true, message: 'User deleted successfully' }
}

Example — End-user deletes their own account

async function deleteOwnAccount(
  projectId: string,
  userToken: string,
): Promise<{ success: boolean; message: string }> {
  // Extract userId from the JWT payload
  const payload = JSON.parse(atob(userToken.split('.')[1]));
  const userId = payload.userId;
 
  if (!userId) throw new Error('Invalid token payload');
 
  const res = await fetch(
    `https://api.moontraze.com/api/users/${projectId}/users/${userId}`,
    {
      method: 'DELETE',
      headers: {
        Authorization: `Bearer ${userToken}`,
        'X-Project-Id': projectId,
      },
    },
  );
 
  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(err.error || `HTTP ${res.status}`);
  }
 
  return res.json();
}

Safety rules

  • End-users can only delete their own account. Attempting to delete another user returns 403 SELF_DELETE_ONLY.
  • Owners can delete any user within their own project.
  • Admins need explicit delete permission from the owner.
  • Cross-project requests return 403 PROJECT_MISMATCH.
  • Deletion is permanent — there is no undo.

What gets deleted

ItemDeleted?
User record (Authentication section)Yes
Database documents (users/{uid}, posts, chats, reviews)No — clean up separately
Uploaded files (avatars, attachments)No — clean up separately

For full account cleanup (data + files + auth user), build a dedicated account deletion flow on your backend that:

  1. Cleans up database documents
  2. Deletes uploaded files
  3. Calls DELETE /api/users/:projectId/users/:userId as the final step

Response

Success (200):

{
  "success": true,
  "message": "User deleted successfully"
}

Error responses:

StatusCodeMeaning
400MISSING_PARAMSMissing projectId or userId
401UnauthorizedNo token / invalid token
403SELF_DELETE_ONLYEnd-user tried to delete another user
403NO_DELETE_PERMISSIONAdmin lacks delete permission
403PROJECT_MISMATCHTarget user does not belong to this project
404User not foundNo user with that ID in this project
500Failed to delete userServer error

Best Practices

  • Never store TOTP secret on client
  • Show QR code as image (not text)
  • Handle errors gracefully
  • Always use HTTPS
  • Store tokens securely (not in localStorage for sensitive apps)