Complete Email verification before starting this flow. Accounts with MFA enabled receive a short-lived pre-authentication token before AuthOS establishes the full session.
Login with Email and Password
After email verification, users can authenticate with their email and password.
Basic Login
async function loginWithPassword(email: string, password: string) {
try {
// The SDK automatically handles token storage and configuration
await sso.auth.login({
email: email,
password: password
});
console.log('Login successful');
return true;
} catch (error) {
if (error instanceof SsoApiError) {
if (error.statusCode === 401) {
console.error('Invalid email or password');
} else if (error.statusCode === 403) {
console.error('Email not verified. Please check your email.');
} else {
console.error('Login failed:', error.message);
}
}
return false;
}
}
Login with MFA Support
If the user has MFA enabled, the login will return a pre-authentication token instead of a full session token. The full session is only stored after successful MFA verification:
async function loginWithPasswordAndMfa(email: string, password: string) {
try {
const tokens = await sso.auth.login({
email: email,
password: password
});
// Check if this is a pre-auth token (5 minute expiration = 300 seconds)
if (tokens.expires_in === 300) {
// User has MFA enabled - need to verify MFA code
// Session is NOT saved yet - waiting for MFA verification
return {
requiresMfa: true,
preauthToken: tokens.access_token
};
}
// Normal login without MFA - session is automatically saved
return {
requiresMfa: false,
success: true
};
} catch (error) {
if (error instanceof SsoApiError) {
throw error;
}
throw new Error('Login failed');
}
}
Complete Login Form with MFA
import { useState } from 'react';
import { SsoClient, SsoApiError } from '@drmhse/sso-sdk';
const sso = new SsoClient({
baseURL: process.env.REACT_APP_SSO_URL
});
export function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [mfaCode, setMfaCode] = useState('');
const [preauthToken, setPreauthToken] = useState<string | null>(null);
const [error, setError] = useState('');
const [loading, setLoading] = useState(false);
const handlePasswordLogin = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
setLoading(true);
try {
const tokens = await sso.auth.login({
email,
password
});
// Check if MFA is required
if (tokens.expires_in === 300) {
setPreauthToken(tokens.access_token);
setLoading(false);
return;
}
// Normal login without MFA - session automatically saved, redirect to dashboard
window.location.href = '/dashboard';
} catch (err) {
if (err instanceof SsoApiError) {
if (err.statusCode === 401) {
setError('Invalid email or password');
} else if (err.statusCode === 403) {
setError('Please verify your email before logging in');
} else {
setError(err.message);
}
} else {
setError('Login failed. Please try again.');
}
setLoading(false);
}
};
const handleMfaVerification = async (e: React.FormEvent) => {
e.preventDefault();
setError('');
setLoading(true);
try {
// MFA verification automatically saves the full session
await sso.auth.verifyMfa(preauthToken!, mfaCode);
// Session is now authenticated, redirect to dashboard
window.location.href = '/dashboard';
} catch (err) {
if (err instanceof SsoApiError) {
setError('Invalid MFA code. Please try again.');
} else {
setError('Verification failed. Please try again.');
}
setLoading(false);
}
};
// Show MFA verification form
if (preauthToken) {
return (
<form onSubmit={handleMfaVerification}>
<h2>Two-Factor Authentication</h2>
<p>Enter the 6-digit code from your authenticator app</p>
<div className="form-group">
<input
type="text"
value={mfaCode}
onChange={(e) => setMfaCode(e.target.value.replace(/\D/g, ''))}
maxLength={6}
placeholder="000000"
required
autoFocus
/>
</div>
{error && <div className="error">{error}</div>}
<button type="submit" disabled={loading}>
{loading ? 'Verifying...' : 'Verify'}
</button>
<button
type="button"
onClick={() => {
setPreauthToken(null);
setMfaCode('');
setError('');
}}
>
Back to Login
</button>
</form>
);
}
// Show password login form
return (
<form onSubmit={handlePasswordLogin}>
<h2>Sign In</h2>
<div className="form-group">
<label htmlFor="email">Email Address</label>
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
required
placeholder="you@example.com"
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</div>
{error && <div className="error">{error}</div>}
<button type="submit" disabled={loading}>
{loading ? 'Signing In...' : 'Sign In'}
</button>
<div className="links">
<a href="/forgot-password">Forgot password?</a>
<a href="/register">Create account</a>
</div>
</form>
);
}
Next step
For lost credentials, implement Password reset. For authenticated password changes, continue to Account management.