Account Management

Change an authenticated user's password or add one to an OAuth-created account

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

Use these flows after authentication. Existing password users must prove their current password; OAuth-created users can add a password to enable an additional login method.

Change Password (Authenticated Users)

Authenticated users can change their password by providing their current password for verification.

Basic Password Change

async function changePassword(currentPassword: string, newPassword: string) {
  try {
    const response = await sso.user.changePassword({
      current_password: currentPassword,
      new_password: newPassword
    });

    console.log(response.message);
    // "Password changed successfully"
    return true;
  } catch (error) {
    if (error instanceof SsoApiError) {
      if (error.statusCode === 401) {
        console.error('Current password is incorrect');
      } else {
        console.error('Password change failed:', error.message);
      }
    }
    return false;
  }
}

Change Password Form

import { useState } from 'react';
import { SsoClient, SsoApiError } from '@drmhse/sso-sdk';

interface ChangePasswordFormProps {
  sso: SsoClient;
}

export function ChangePasswordForm({ sso }: ChangePasswordFormProps) {
  const [currentPassword, setCurrentPassword] = useState('');
  const [newPassword, setNewPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [error, setError] = useState('');
  const [success, setSuccess] = useState(false);
  const [loading, setLoading] = useState(false);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError('');
    setSuccess(false);

    if (newPassword !== confirmPassword) {
      setError('New passwords do not match');
      return;
    }

    if (newPassword.length < 8) {
      setError('New password must be at least 8 characters');
      return;
    }

    if (newPassword === currentPassword) {
      setError('New password must be different from current password');
      return;
    }

    setLoading(true);

    try {
      await sso.user.changePassword({
        current_password: currentPassword,
        new_password: newPassword
      });

      setSuccess(true);
      // Clear form
      setCurrentPassword('');
      setNewPassword('');
      setConfirmPassword('');
    } catch (err) {
      if (err instanceof SsoApiError) {
        if (err.statusCode === 401) {
          setError('Current password is incorrect');
        } else {
          setError(err.message);
        }
      } else {
        setError('Failed to change password. Please try again.');
      }
    } finally {
      setLoading(false);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <h2>Change Password</h2>

      <div className="form-group">
        <label htmlFor="currentPassword">Current Password</label>
        <input
          id="currentPassword"
          type="password"
          value={currentPassword}
          onChange={(e) => setCurrentPassword(e.target.value)}
          required
        />
      </div>

      <div className="form-group">
        <label htmlFor="newPassword">New Password</label>
        <input
          id="newPassword"
          type="password"
          value={newPassword}
          onChange={(e) => setNewPassword(e.target.value)}
          required
          placeholder="At least 8 characters"
        />
      </div>

      <div className="form-group">
        <label htmlFor="confirmPassword">Confirm New Password</label>
        <input
          id="confirmPassword"
          type="password"
          value={confirmPassword}
          onChange={(e) => setConfirmPassword(e.target.value)}
          required
        />
      </div>

      {error && <div className="error">{error}</div>}
      {success && (
        <div className="success">Password changed successfully!</div>
      )}

      <button type="submit" disabled={loading}>
        {loading ? 'Changing Password...' : 'Change Password'}
      </button>
    </form>
  );
}

Set Password for OAuth Users

Users who originally signed up via OAuth (GitHub, Google, Microsoft) don’t have a password. They can set a password to enable password-based login.

Set Password

async function setPasswordForOAuthUser(newPassword: string) {
  try {
    const response = await sso.user.setPassword({
      new_password: newPassword
    });

    console.log(response.message);
    // "Password set successfully"
    return true;
  } catch (error) {
    if (error instanceof SsoApiError) {
      if (error.errorCode === 'DUPLICATE_CONSTRAINT') {
        console.error('Password already set. Use change password instead.');
      } else {
        console.error('Failed to set password:', error.message);
      }
    }
    return false;
  }
}

Set Password Form with Detection

import { useState, useEffect } from 'react';
import { SsoClient, SsoApiError } from '@drmhse/sso-sdk';

interface SetPasswordFormProps {
  sso: SsoClient;
}

export function SetPasswordForm({ sso }: SetPasswordFormProps) {
  const [hasPassword, setHasPassword] = useState<boolean | null>(null);
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [error, setError] = useState('');
  const [success, setSuccess] = useState(false);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    checkPasswordStatus();
  }, []);

  const checkPasswordStatus = async () => {
    try {
      const profile = await sso.user.getProfile();
      // Check if user has password (this would be in profile if available)
      // Or attempt to set password and handle the 409 error
      setHasPassword(false); // Assume no password for OAuth users
    } catch (error) {
      console.error('Failed to check password status:', error);
    }
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError('');
    setSuccess(false);

    if (password !== confirmPassword) {
      setError('Passwords do not match');
      return;
    }

    if (password.length < 8) {
      setError('Password must be at least 8 characters');
      return;
    }

    setLoading(true);

    try {
      await sso.user.setPassword({
        new_password: password
      });

      setSuccess(true);
      setHasPassword(true);
      setPassword('');
      setConfirmPassword('');
    } catch (err) {
      if (err instanceof SsoApiError) {
        if (err.errorCode === 'DUPLICATE_CONSTRAINT') {
          setError('You already have a password set. Use the change password form instead.');
          setHasPassword(true);
        } else {
          setError(err.message);
        }
      } else {
        setError('Failed to set password. Please try again.');
      }
    } finally {
      setLoading(false);
    }
  };

  if (hasPassword === true) {
    return (
      <div className="info-message">
        <p>You already have a password set.</p>
        <p>Use the "Change Password" option if you want to update it.</p>
      </div>
    );
  }

  if (hasPassword === null) {
    return <div>Loading...</div>;
  }

  return (
    <form onSubmit={handleSubmit}>
      <h2>Set Password</h2>
      <p>
        You signed up using a social account. Set a password to enable
        email/password login.
      </p>

      <div className="form-group">
        <label htmlFor="password">New Password</label>
        <input
          id="password"
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          required
          placeholder="At least 8 characters"
        />
      </div>

      <div className="form-group">
        <label htmlFor="confirmPassword">Confirm Password</label>
        <input
          id="confirmPassword"
          type="password"
          value={confirmPassword}
          onChange={(e) => setConfirmPassword(e.target.value)}
          required
        />
      </div>

      {error && <div className="error">{error}</div>}
      {success && (
        <div className="success">
          Password set successfully! You can now log in with email and password.
        </div>
      )}

      <button type="submit" disabled={loading}>
        {loading ? 'Setting Password...' : 'Set Password'}
      </button>
    </form>
  );
}

Next step

Review Troubleshooting and security before releasing password authentication to production.