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.