Passwordless Authentication
Passwordless authentication lets users sign in by clicking a link sent to their email address. There is no password to remember, no password to breach. Ithbat IAM issues a single-use, time-limited magic link that, when clicked, completes authentication and returns tokens.
How It Works
- The user enters their email address in your application.
- Your application calls
POST /api/v1/auth/passwordless/start. - Ithbat IAM generates a cryptographically random token, stores it temporarily, and sends a magic link email.
- The user clicks the link in their email.
- Your application extracts the token from the link and calls
POST /api/v1/auth/passwordless/verify. - Ithbat IAM validates the token and returns access, refresh, and ID tokens.
sequenceDiagram
participant User
participant App as Your App
participant Ithbat as Ithbat IAM
participant Email as Email Service
User->>App: Enter email address
App->>Ithbat: POST /api/v1/auth/passwordless/start { email }
Ithbat->>Ithbat: Generate single-use token
Ithbat->>Email: Send magic link email
Ithbat-->>App: 200 { message }
App-->>User: "Check your email"
Email-->>User: Magic link (e.g. https://app.example.com/verify?token=...)
User->>App: Click magic link
App->>Ithbat: POST /api/v1/auth/passwordless/verify { token }
Ithbat->>Ithbat: Validate token (one-time, expiry check)
Ithbat-->>App: 200 { accessToken, refreshToken, idToken, user }
App-->>User: Signed in
Start Passwordless Login
POST /api/v1/auth/passwordless/start
Request
{
"email": "[email protected]",
"tenant_id": "ten_01J8X..."
}
| Field | Type | Required | Description |
|---|---|---|---|
email | string | Yes | The user's email address |
tenant_id | string | No | Tenant UUID. If omitted, resolved from email domain |
Response — 200 OK
{
"message": "Magic link sent to your email address"
}
The response is always 200 OK regardless of whether the email address exists in the system. This prevents email enumeration.
Verify the Magic Link Token
POST /api/v1/auth/passwordless/verify
Request
{
"token": "a1b2c3d4e5f6...",
"tenant_id": "ten_01J8X..."
}
| Field | Type | Required | Description |
|---|---|---|---|
token | string | Yes | The token extracted from the magic link URL |
tenant_id | string | No | Tenant UUID. Usually embedded in the magic link URL |
Response — 200 OK
{
"accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"refreshToken": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...",
"idToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"tokenType": "Bearer",
"expiresIn": 3600,
"user": {
"id": "usr_01J8X...",
"tenantId": "ten_01J8X...",
"email": "[email protected]",
"firstName": "Sara",
"familyName": "Al-Rashidi",
"displayName": "Sara Al-Rashidi",
"roles": ["member"],
"permissions": ["profile:read", "profile:write"]
}
}
Implementing the Magic Link URL
The magic link in the email points to a URL in your application, not directly to the Ithbat IAM API. Your application receives the token as a query parameter, then calls the verify endpoint.
Recommended link format:
https://app.example.com/auth/magic-link?token=a1b2c3d4e5f6...
Your application's handler at /auth/magic-link extracts the token parameter and calls the verify API.
Security Considerations
Token Expiry
Magic link tokens are single-use and expire after a short period. Tokens that have been consumed or expired return an error. The expiry window is configured per tenant in security settings.
Do not log magic link URLs or tokens. They are equivalent to passwords for a single authentication session.
One-Time Use
Each token is invalidated immediately upon successful verification. Clicking the link a second time returns an error. This prevents replay attacks.
Link Delivery Security
- Magic links are only as secure as the user's email account.
- Consider requiring users with sensitive roles to use a stronger method (TOTP or WebAuthn).
- Email delivery uses TLS in transit.
Token Scope
Magic link tokens are tenant-scoped. A token generated for one tenant cannot be used to authenticate against a different tenant.
Code Examples
cURL — Start Passwordless
curl -X POST https://api.ithbat.io/api/v1/auth/passwordless/start \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"tenant_id": "ten_01J8X..."
}'
cURL — Verify Token
curl -X POST https://api.ithbat.io/api/v1/auth/passwordless/verify \
-H "Content-Type: application/json" \
-d '{
"token": "a1b2c3d4e5f6...",
"tenant_id": "ten_01J8X..."
}'
JavaScript SDK
import { IthbatSDK } from '@ithbatiam/sdk';
const ithbat = new IthbatSDK({
tenantId: 'ten_01J8X...',
baseUrl: 'https://api.ithbat.io',
});
// Step 1: Request magic link
await ithbat.auth.startPasswordless({ email: '[email protected]' });
// Show: "Check your inbox for a sign-in link"
// Step 2: Handle magic link callback in your app
// URL: https://app.example.com/auth/magic-link?token=...
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('token');
if (token) {
const session = await ithbat.auth.verifyPasswordless({ token });
console.log('Signed in as:', session.user.displayName);
// Store session.accessToken and session.refreshToken
}
React Example
import { useState } from 'react';
import { IthbatSDK } from '@ithbatiam/sdk';
const ithbat = new IthbatSDK({ tenantId: 'ten_01J8X...' });
function PasswordlessLoginForm() {
const [email, setEmail] = useState('');
const [sent, setSent] = useState(false);
const handleSubmit = async (e) => {
e.preventDefault();
await ithbat.auth.startPasswordless({ email });
setSent(true);
};
if (sent) {
return <p>Check your inbox — a sign-in link is on its way.</p>;
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Enter your email"
required
/>
<button type="submit">Send Sign-in Link</button>
</form>
);
}
Error Handling
| HTTP Status | Error Code | Cause |
|---|---|---|
400 | VALIDATION_ERROR | email or token field missing |
401 | UNAUTHORIZED | Token is invalid, expired, or already used |
403 | FORBIDDEN | User account is suspended |
429 | RATE_LIMITED | Too many requests for this email |
Next Steps
- Email & Password — traditional authentication as an alternative or fallback
- MFA — require a second factor in addition to passwordless
- Token Lifecycle — understand the tokens returned after verification
- WebAuthn / Passkeys — an even stronger passwordless option using device biometrics