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 userStep 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-livedStep 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/:userIdAuthorization
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
| Item | Deleted? |
|---|---|
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:
- Cleans up database documents
- Deletes uploaded files
- Calls
DELETE /api/users/:projectId/users/:userIdas the final step
Response
Success (200):
{
"success": true,
"message": "User deleted successfully"
}Error responses:
| Status | Code | Meaning |
|---|---|---|
| 400 | MISSING_PARAMS | Missing projectId or userId |
| 401 | Unauthorized | No token / invalid token |
| 403 | SELF_DELETE_ONLY | End-user tried to delete another user |
| 403 | NO_DELETE_PERMISSION | Admin lacks delete permission |
| 403 | PROJECT_MISMATCH | Target user does not belong to this project |
| 404 | User not found | No user with that ID in this project |
| 500 | Failed to delete user | Server 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)