Skip to main content

Authentication API

All authentication endpoints are public (no Bearer token required) unless noted otherwise. They are subject to rate limiting. Include X-Tenant-ID when the tenant cannot be inferred from the request.

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


POST /api/v1/auth/login

Authenticate a user with email and password. Returns JWT tokens. If MFA is enabled, the response will include mfaRequired: true and an mfaToken to use for the MFA verification step. In that case, accessToken and refreshToken are absent.

Request Body

FieldTypeRequiredDescription
emailstringYesUser's email address
passwordstringYesUser's password
rememberMebooleanNoExtend session duration
curl -X POST "https://api.ithbat.io/api/v1/auth/login" \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: 3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a" \
-d '{
"email": "[email protected]",
"password": "correct-horse-battery-staple"
}'

Response 200 — Success

{
"success": true,
"data": {
"accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"idToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600,
"user": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"tenantId": "3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a",
"email": "[email protected]",
"firstName": "Alice",
"fatherName": "",
"grandfatherName": "",
"familyName": "Smith",
"displayName": "Alice Smith",
"roles": ["admin"],
"permissions": ["admin"]
}
}
}

Response 200 — MFA Required

{
"mfaRequired": true,
"mfaToken": "mfa_eyJhbGciOiJIUzI1NiJ9..."
}

When mfaRequired is true, accessToken and refreshToken are absent. Call POST /api/v1/auth/mfa/verify with the mfaToken and the user's TOTP code.

Error Codes

CodeHTTPDescription
INVALID_CREDENTIALS401Email or password is incorrect
ACCOUNT_SUSPENDED403Account has been suspended
ACCOUNT_NOT_VERIFIED403Email address has not been verified
TENANT_NOT_FOUND404Tenant not found
TENANT_SUSPENDED403Tenant account is suspended

POST /api/v1/auth/register

Register a new user account in the current tenant. Sends a verification email upon successful registration.

Request Body

FieldTypeRequiredDescription
emailstringYesUser's email address
firstNamestringYesFirst name
fatherNamestringNoFather's name (Arabic naming convention)
grandfatherNamestringNoGrandfather's name (Arabic naming convention)
familyNamestringYesFamily/last name
passwordstringYesPassword (must meet tenant's password policy)
curl -X POST "https://api.ithbat.io/api/v1/auth/register" \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: 3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a" \
-d '{
"email": "[email protected]",
"firstName": "Bob",
"familyName": "Jones",
"password": "SecurePass@2024"
}'

Response 201

{
"success": true,
"data": {
"userId": "b2c3d4e5-f6a7-8901-bcde-f12345678901",
"email": "[email protected]",
"displayName": "Bob Jones",
"tenantId": "3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a",
"message": "Registration successful. Please verify your email address."
}
}

Error Codes

CodeHTTPDescription
DUPLICATE_EMAIL409A user with this email already exists
VALIDATION_ERROR400Password does not meet policy requirements
REGISTRATION_DISABLED403Self-registration is disabled for this tenant

POST /api/v1/auth/refresh

Exchange a valid refresh token for a new access token and refresh token pair. The old refresh token is revoked.

Request Body

FieldTypeRequiredDescription
refreshTokenstringYesA valid refresh token
curl -X POST "https://api.ithbat.io/api/v1/auth/refresh" \
-H "Content-Type: application/json" \
-d '{"refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."}'

Response 200

{
"success": true,
"data": {
"accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"idToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600
}
}

Error Codes

CodeHTTPDescription
TOKEN_INVALID401Refresh token is malformed or has been revoked
TOKEN_EXPIRED401Refresh token has expired

POST /api/v1/auth/logout

Authentication required.

Revoke the current session. Optionally revokes the refresh token to prevent further use.

Request Body

FieldTypeRequiredDescription
refreshTokenstringNoRefresh token to revoke alongside the session
curl -X POST "https://api.ithbat.io/api/v1/auth/logout" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."}'

Response 200

{
"success": true,
"message": "Logged out successfully"
}

POST /api/v1/auth/change-password

Authentication required.

Change the authenticated user's password. Optionally revoke all other active sessions after the change.

Request Body

FieldTypeRequiredDescription
current_passwordstringYesCurrent password
new_passwordstringYesNew password (minimum 8 characters)
revoke_other_sessionsbooleanNoRevoke all sessions except the current one (default: false)
curl -X POST "https://api.ithbat.io/api/v1/auth/change-password" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"current_password": "OldPass@2023",
"new_password": "NewPass@2024",
"revoke_other_sessions": true
}'

Response 200

{
"success": true,
"data": {
"message": "Password changed successfully"
}
}

Error Codes

CodeHTTPDescription
INVALID_CREDENTIALS401Current password is incorrect
VALIDATION_ERROR400New password does not meet policy requirements

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

Request a password reset email for the given address. Always returns 200 to prevent email enumeration, regardless of whether the address exists.

Request Body

FieldTypeRequiredDescription
emailstringYesEmail address associated with the account
curl -X POST "https://api.ithbat.io/api/v1/auth/password-reset/initiate" \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: 3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a" \
-d '{"email": "[email protected]"}'

Response 200

{
"success": true,
"data": {
"message": "If an account exists for this email, a password reset link has been sent."
}
}

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

Validate a password reset token before presenting the reset form. This avoids showing the form only to fail after submission.

Request Body

FieldTypeRequiredDescription
tokenstringYesToken from the reset email link
curl -X POST "https://api.ithbat.io/api/v1/auth/password-reset/validate" \
-H "Content-Type: application/json" \
-d '{"token": "prst_abc123xyz..."}'

Response 200

{
"success": true,
"data": {
"valid": true
}
}

Response 200 — Invalid token

{
"success": true,
"data": {
"valid": false,
"message": "Token is invalid or has expired"
}
}

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

Complete the password reset using the token from the reset email.

Request Body

FieldTypeRequiredDescription
tokenstringYesToken from the reset email link
newPasswordstringYesNew password (must meet tenant's password policy)
curl -X POST "https://api.ithbat.io/api/v1/auth/password-reset/complete" \
-H "Content-Type: application/json" \
-d '{
"token": "prst_abc123xyz...",
"newPassword": "NewSecurePass@2024"
}'

Response 200

{
"success": true,
"data": {
"message": "Password has been reset successfully. You can now log in with your new password."
}
}

Error Codes

CodeHTTPDescription
TOKEN_INVALID400Reset token is invalid or has already been used
TOKEN_EXPIRED400Reset token has expired
VALIDATION_ERROR400New password does not meet policy requirements

POST /api/v1/auth/verify-email

Verify a user's email address using the token from the verification email.

Request Body

FieldTypeRequiredDescription
tokenstringYesToken from the verification email
curl -X POST "https://api.ithbat.io/api/v1/auth/verify-email" \
-H "Content-Type: application/json" \
-d '{"token": "vfy_abc123xyz..."}'

Response 200

{
"success": true,
"data": {
"message": "Email address verified successfully"
}
}

Error Codes

CodeHTTPDescription
TOKEN_INVALID400Verification token is invalid or has already been used
TOKEN_EXPIRED400Verification token has expired

POST /api/v1/auth/resend-verification

Resend the email verification email to the given address.

Request Body

FieldTypeRequiredDescription
emailstringYesEmail address that needs verification
curl -X POST "https://api.ithbat.io/api/v1/auth/resend-verification" \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: 3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a" \
-d '{"email": "[email protected]"}'

Response 200

{
"success": true,
"message": "Verification email sent"
}

POST /api/v1/auth/passwordless/start

Send a magic link to the specified email address. The link is valid for 15 minutes.

Request Body

FieldTypeRequiredDescription
emailstringYesEmail address to send the magic link to
tenant_idstringNoTenant ID (required if not in X-Tenant-ID header)
curl -X POST "https://api.ithbat.io/api/v1/auth/passwordless/start" \
-H "Content-Type: application/json" \
-H "X-Tenant-ID: 3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a" \
-d '{"email": "[email protected]"}'

Response 200

{
"success": true,
"data": {
"message": "Magic link sent. Check your email to continue."
}
}

POST /api/v1/auth/passwordless/verify

Verify a magic link token and exchange it for JWT tokens.

Request Body

FieldTypeRequiredDescription
tokenstringYesToken from the magic link URL
tenant_idstringNoTenant ID (required if not in X-Tenant-ID header)
curl -X POST "https://api.ithbat.io/api/v1/auth/passwordless/verify" \
-H "Content-Type: application/json" \
-d '{
"token": "plnk_abc123xyz...",
"tenant_id": "3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a"
}'

Response 200

{
"success": true,
"data": {
"accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"idToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600,
"user": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"email": "[email protected]",
"displayName": "Alice Smith",
"roles": ["user"],
"permissions": ["user:read"]
}
}
}

Error Codes

CodeHTTPDescription
TOKEN_INVALID400Magic link token is invalid or has already been used
TOKEN_EXPIRED400Magic link has expired (valid for 15 minutes)

GET /api/v1/auth/social/{provider}/login

Initiate a social login flow. Redirects the browser to the identity provider's authorization page. Supported providers: google, github, microsoft, apple.

Path Parameters

ParameterTypeDescription
providerstringIdentity provider name (e.g., google, github)

Query Parameters

ParameterTypeRequiredDescription
redirect_uristringNoURI to redirect after authentication
statestringNoOpaque value for CSRF protection
curl -L "https://api.ithbat.io/api/v1/auth/social/google/login?redirect_uri=https%3A%2F%2Fapp.acme.com%2Fcallback" \
-H "X-Tenant-ID: 3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a"

This endpoint returns HTTP 302 and redirects to Google's OAuth authorization URL.


GET /api/v1/auth/social/{provider}/callback

OAuth callback endpoint. The identity provider redirects here after user authorization. Ithbat exchanges the authorization code, creates or links the user account, and redirects back to your application with JWT tokens.

This endpoint is called by the identity provider — your application does not call it directly. Configure your OAuth app's redirect URI as https://api.ithbat.io/api/v1/auth/social/&#123;provider&#125;/callback.


POST /api/v1/auth/mfa/setup

Authentication required.

Initialize TOTP MFA setup for the authenticated user. Returns a TOTP secret and QR code URI to display to the user.

curl -X POST "https://api.ithbat.io/api/v1/auth/mfa/setup" \
-H "Authorization: Bearer <access_token>"

Response 200

{
"success": true,
"data": {
"secret": "JBSWY3DPEHPK3PXP",
"qrCodeUri": "otpauth://totp/Ithbat%3Aalice%40acme.com?secret=JBSWY3DPEHPK3PXP&issuer=Ithbat",
"backupCodes": [
"12345-67890",
"23456-78901",
"34567-89012",
"45678-90123",
"56789-01234",
"67890-12345",
"78901-23456",
"89012-34567"
]
}
}

After calling setup, call POST /api/v1/auth/mfa/verify-setup with a valid TOTP code to activate MFA.


POST /api/v1/auth/mfa/verify-setup

Authentication required.

Confirm MFA setup by providing the first valid TOTP code from the authenticator app. MFA is not active until this step is completed.

Request Body

FieldTypeRequiredDescription
codestringYes6-digit TOTP code from the authenticator app
curl -X POST "https://api.ithbat.io/api/v1/auth/mfa/verify-setup" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"code": "123456"}'

Response 200

{
"success": true,
"message": "MFA enabled successfully"
}

POST /api/v1/auth/mfa/verify

Verify an MFA code during the login flow. Use the mfaToken from the login response.

Request Body

FieldTypeRequiredDescription
mfaTokenstringYesThe MFA token returned from the login response
codestringYes6-digit TOTP code from the authenticator app
curl -X POST "https://api.ithbat.io/api/v1/auth/mfa/verify" \
-H "Content-Type: application/json" \
-d '{
"mfaToken": "mfa_eyJhbGciOiJIUzI1NiJ9...",
"code": "123456"
}'

Response 200

{
"success": true,
"data": {
"accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"idToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600,
"user": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"email": "[email protected]",
"displayName": "Alice Smith",
"roles": ["admin"],
"permissions": ["admin"]
}
}
}

Error Codes

CodeHTTPDescription
MFA_TOKEN_INVALID401MFA token is invalid or has expired
MFA_CODE_INVALID401TOTP code is incorrect
MFA_CODE_ALREADY_USED401This TOTP code has already been used

POST /api/v1/auth/mfa/verify-backup

Verify a backup code during the login flow when the authenticator app is unavailable. Each backup code can only be used once.

Request Body

FieldTypeRequiredDescription
mfaTokenstringYesThe MFA token from the login response
codestringYesOne of the backup codes from MFA setup
curl -X POST "https://api.ithbat.io/api/v1/auth/mfa/verify-backup" \
-H "Content-Type: application/json" \
-d '{
"mfaToken": "mfa_eyJhbGciOiJIUzI1NiJ9...",
"code": "12345-67890"
}'

Response 200 — Same token response as POST /api/v1/auth/mfa/verify.


SAML 2.0 Endpoints

For SAML-based enterprise SSO, Ithbat exposes per-tenant SAML service provider endpoints.

MethodPathDescription
GET/api/v1/auth/saml/&#123;tenant_id&#125;/metadataDownload SP metadata XML for IdP configuration
GET/api/v1/auth/saml/&#123;tenant_id&#125;/loginInitiate SAML login (redirects to IdP)
POST/api/v1/auth/saml/&#123;tenant_id&#125;/acsAssertion Consumer Service — receives SAML response from IdP

Configure your SAML identity provider using the metadata URL:

https://api.ithbat.io/api/v1/auth/saml/{tenant_id}/metadata

See the SAML Configuration Guide for full setup instructions.


Social Code Exchange

POST /api/v1/auth/social/exchange

Exchange a social provider authorization code for Ithbat IAM tokens. Use this in SPA or mobile flows where the frontend receives the authorization code directly from the social provider.

Request Body

FieldTypeRequiredDescription
providerstringYesSocial provider (google, github, microsoft, apple)
codestringYesAuthorization code from the provider
tenantIdstringYesTenant ID
redirectUristringYesRedirect URI used in the authorization request
curl -X POST "https://api.ithbat.io/api/v1/auth/social/exchange" \
-H "Content-Type: application/json" \
-d '{
"provider": "google",
"code": "4/0AX4XfWh...",
"tenantId": "3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a",
"redirectUri": "https://app.acme.com/auth/callback"
}'

Response 200

{
"success": true,
"data": {
"accessToken": "eyJhbGciOiJSUzI1NiIs...",
"refreshToken": "dGhpcyBpcyBhIHJlZnJlc2g...",
"tokenType": "Bearer",
"expiresIn": 3600,
"user": {
"id": "u1a2b3c4-d5e6-7890-abcd-ef1234567890",
"email": "[email protected]",
"displayName": "Alice Smith",
"provider": "google"
}
}
}

Social Provider List

GET /api/v1/auth/social/providers

List the social login providers enabled for the current tenant.

curl "https://api.ithbat.io/api/v1/auth/social/providers" \
-H "X-Tenant-ID: 3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a"

Response 200

{
"success": true,
"data": {
"providers": [
{ "id": "google", "name": "Google", "enabled": true },
{ "id": "microsoft", "name": "Microsoft", "enabled": true },
{ "id": "github", "name": "GitHub", "enabled": false }
]
}
}