Skip to main content

Email & Password Authentication

Email and password is the foundational authentication method in Ithbat IAM. This guide covers the complete flow: registration with email verification, login with JWT token issuance, password reset, and authenticated password changes.

Base URL

All authentication endpoints live under:

https://api.ithbat.io/api/v1/auth

All requests require the X-Tenant-ID header unless stated otherwise.


Registration

Request

POST /api/v1/auth/register

Required header: X-Tenant-ID: <tenant-uuid>

{
"email": "[email protected]",
"firstName": "Sara",
"familyName": "Al-Rashidi",
"fatherName": "Ahmad",
"grandfatherName": "Khalid",
"password": "SecurePass123!"
}
FieldTypeRequiredDescription
emailstringYesUser's email address
firstNamestringYesGiven name
familyNamestringYesFamily/last name
fatherNamestringNoFather's name (used in MENA naming conventions)
grandfatherNamestringNoGrandfather's name
passwordstringYesMust be at least 8 characters

Response — 201 Created

{
"userId": "usr_01J8X...",
"email": "[email protected]",
"displayName": "Sara Al-Rashidi",
"tenantId": "ten_01J8X...",
"message": "Registration successful. Please check your email to verify your account."
}
note

The account is created immediately, but the user cannot log in until their email address is verified (unless the tenant has email verification disabled in settings).

Password Requirements

  • Minimum 8 characters
  • Additional complexity rules (uppercase, digits, special characters) are configured per tenant via the password policy settings

Email Verification

After registration, Ithbat IAM sends a verification email containing a time-limited token. The token expires after 24 hours.

Verify Email

POST /api/v1/auth/verify-email

{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response — 200 OK

{
"message": "Email verified successfully"
}

Resend Verification Email

POST /api/v1/auth/resend-verification

{
"email": "[email protected]"
}

The response is always 200 OK with a generic message to prevent email enumeration:

{
"message": "If the email exists and is not verified, a verification link has been sent"
}
tip

Pass X-Tenant-ID if you know the tenant. If omitted, the system resolves the tenant from the email domain automatically.


Login

POST /api/v1/auth/login

Request

{
"email": "[email protected]",
"password": "SecurePass123!"
}

X-Tenant-ID is optional — when omitted, the tenant is resolved from the email domain. Always send it when you know it to avoid the extra lookup.

Response — 200 OK (standard login)

{
"accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...",
"idToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600,
"user": {
"id": "usr_01J8X...",
"tenantId": "ten_01J8X...",
"email": "[email protected]",
"firstName": "Sara",
"fatherName": "Ahmad",
"grandfatherName": "Khalid",
"familyName": "Al-Rashidi",
"displayName": "Sara Al-Rashidi",
"roles": ["member"],
"permissions": ["profile:read", "profile:write"]
}
}

Response — 200 OK (MFA required)

When MFA is enabled on the account, the initial login response does not include tokens. Instead:

{
"mfaRequired": true,
"mfaToken": "mfa_challenge_token_here"
}

Use this mfaToken to complete the second factor challenge. See the MFA guide for the full flow.


Registration → Verification → Login Flow

sequenceDiagram
participant Client
participant Ithbat as Ithbat IAM
participant Email as Email Service

Client->>Ithbat: POST /api/v1/auth/register
Ithbat->>Ithbat: Validate fields, hash password
Ithbat->>Email: Send verification email
Ithbat-->>Client: 201 { userId, message }

Email-->>Client: Verification link (24h TTL)
Client->>Ithbat: POST /api/v1/auth/verify-email { token }
Ithbat->>Ithbat: Mark email as verified
Ithbat-->>Client: 200 { message: "Email verified successfully" }

Client->>Ithbat: POST /api/v1/auth/login { email, password }
Ithbat->>Ithbat: Verify credentials
Ithbat-->>Client: 200 { accessToken, refreshToken, idToken, user }

Password Reset

The password reset flow is three steps: initiate (sends email), validate token (optional UI check), complete reset.

Step 1 — Initiate Reset

POST /api/v1/auth/password-reset/initiate

{
"email": "[email protected]"
}

The response is always 200 OK with a generic message regardless of whether the email exists:

{
"message": "If the email exists, a password reset link has been sent"
}

The reset token expires after 1 hour.

warning

Never tell users whether an email is registered in your system. The generic response is intentional — it prevents account enumeration attacks.

Step 2 — Validate Token (optional)

Use this endpoint to check token validity before showing the password reset form. This avoids displaying an input form to a user with an expired token.

POST /api/v1/auth/password-reset/validate

{
"token": "abc123def456..."
}

Response — 200 OK

{
"valid": true,
"message": "Token is valid"
}

Step 3 — Complete Reset

POST /api/v1/auth/password-reset/complete

{
"token": "abc123def456...",
"newPassword": "NewSecurePass456!"
}

Response — 200 OK

{
"message": "Password reset successfully"
}

After a successful reset, all active sessions for the user are invalidated.


Change Password (Authenticated)

Allows an authenticated user to change their own password. Requires the current password as confirmation.

POST /api/v1/auth/change-password

Required header: Authorization: Bearer <accessToken>

{
"current_password": "SecurePass123!",
"new_password": "NewSecurePass456!",
"revoke_other_sessions": true
}
FieldTypeRequiredDescription
current_passwordstringYesThe user's current password
new_passwordstringYesMinimum 8 characters
revoke_other_sessionsbooleanNoIf true, signs out all other active sessions

Response — 200 OK

{
"message": "Password changed successfully"
}

Logout

POST /api/v1/auth/logout

Required header: Authorization: Bearer <accessToken>

{
"refreshToken": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4..."
}

Passing refreshToken revokes that specific token. If omitted, the server revokes the session associated with the access token.

Response — 200 OK

{
"message": "Logged out successfully"
}

Code Examples

cURL — Register

curl -X POST https://api.ithbat.io/api/v1/auth/register \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: ten_01J8X..." \
-d '{
"email": "[email protected]",
"firstName": "Sara",
"familyName": "Al-Rashidi",
"password": "SecurePass123!"
}'

cURL — Login

curl -X POST https://api.ithbat.io/api/v1/auth/login \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: ten_01J8X..." \
-d '{
"email": "[email protected]",
"password": "SecurePass123!"
}'

JavaScript SDK

import { IthbatSDK } from '@ithbatiam/sdk';

const ithbat = new IthbatSDK({
tenantId: 'ten_01J8X...',
baseUrl: 'https://api.ithbat.io',
});

// Register
const registration = await ithbat.auth.register({
email: '[email protected]',
firstName: 'Sara',
familyName: 'Al-Rashidi',
password: 'SecurePass123!',
});

// Login
const session = await ithbat.auth.login({
email: '[email protected]',
password: 'SecurePass123!',
});

console.log(session.accessToken);
console.log(session.user.displayName);

// Password reset
await ithbat.auth.initiatePasswordReset({ email: '[email protected]' });

// Complete reset with token from email link
await ithbat.auth.resetPassword({
token: 'abc123...',
newPassword: 'NewSecurePass456!',
});

Error Handling

HTTP StatusError CodeCause
400VALIDATION_ERRORMissing required field
400VALIDATION_ERRORX-Tenant-ID header missing on register
401UNAUTHORIZEDInvalid credentials
401UNAUTHORIZEDEmail not yet verified
403FORBIDDENAccount suspended or locked
404NOT_FOUNDTenant not found for email domain
429RATE_LIMITEDToo many login attempts

Error Response Format

{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid credentials",
"details": null
}
}
danger

Login endpoints do not distinguish between "wrong password" and "account does not exist" in the error message. Both return Invalid credentials. This prevents user enumeration.


Next Steps