Login and Sessions

Implement password login, MFA continuation, and an authenticated React session

AuthOS release 0.8.2 TypeScript SDK 0.8.0 Latest-only documentation
Updated Jul 15, 2026 Edit this page
On this page

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.