Appearance
First Login Flow
This page documents the login flow when a user logs in for the first time or when password change is required.
Overview
When a user's account is newly created or an administrator forces a password reset, the MustChangePassword flag is set to true. In this case, the login flow returns a temporary token that only allows password change operations.
Triggers for Mandatory Password Change
| Condition | Description |
|---|---|
IsFirstLogin = true | User has never logged in |
MustChangePassword = true | Admin-forced password reset |
PasswordExpiresAt < NOW() | Password has expired (policy-based) |
Sequence Diagram
100% 💡 Use Ctrl + Scroll para zoom | Arraste para navegar
Step-by-Step Explanation
Phase 1: Initial Login Attempt
1.1 Credential Validation
The user provides valid credentials. The system verifies:
- Email exists
- Password is correct
- AppId is valid
1.2 Password Change Check
After successful credential validation, the system checks:
csharp
bool requiresPasswordChange =
user.IsFirstLogin ||
user.MustChangePassword ||
(user.PasswordExpiresAt.HasValue && user.PasswordExpiresAt < DateTime.UtcNow);1.3 Temporary Token Generation
If password change is required, a limited-purpose token is generated:
json
{
"sub": "user-id",
"purpose": "password_change",
"exp": 1706885400 // 10 minutes from now
}1.4 Response
json
{
"requiresPasswordChange": true,
"reason": "first_login", // or "password_expired", "admin_reset"
"temporaryToken": "eyJhbGciOiJIUzI1NiIs..."
}Phase 2: Password Change
2.1 Submit New Password
json
{
"temporaryToken": "eyJhbGciOiJIUzI1NiIs...",
"newPassword": "NewSecurePassword123!",
"confirmPassword": "NewSecurePassword123!"
}2.2 Password History Check
The system prevents password reuse by checking against the last N passwords:
sql
SELECT PasswordHash
FROM UserPasswordHistory
WHERE UserId = @userId
ORDER BY SetAt DESC
LIMIT 5Configuration
The number of passwords to remember is configurable via PasswordPolicyOptions.HistoryCount.
2.3 Password Strength Validation
Default password requirements:
| Rule | Requirement |
|---|---|
| Minimum length | 8 characters |
| Uppercase | At least 1 |
| Lowercase | At least 1 |
| Numbers | At least 1 |
| Special characters | At least 1 |
2.4 Save New Password
The system:
- Hashes the new password
- Updates the user record
- Saves old password to history
- Resets flags:
MustChangePassword = false,IsFirstLogin = false
Phase 3: Complete Login
After password change, the user must log in again with the new password. This follows the standard Login Flow.
Error Scenarios
| Error | HTTP Status | Cause |
|---|---|---|
| Token expired | 401 | Temporary token expired (10 min) |
| Password reuse | 400 | New password matches a recent one |
| Weak password | 400 | Doesn't meet strength requirements |
| Passwords don't match | 400 | newPassword ≠ confirmPassword |
Security Considerations
Temporary Token Limitations
The temporary token:
- Has a short expiration (10 minutes)
- Can only be used for password change
- Contains minimal claims (no roles/permissions)
- Is invalidated after successful password change
Password History
Password history prevents:
- Reusing recent passwords
- Cycling through passwords to return to a favorite
- Predictable password rotation
Code Example
Client-Side Flow (TypeScript)
typescript
async function handleLogin(email: string, password: string) {
const response = await authService.login({ email, password, appId });
if (response.requiresPasswordChange) {
// Redirect to password change form
sessionStorage.setItem('tempToken', response.temporaryToken);
router.push('/change-password');
return;
}
// Normal login success
authStore.setTokens(response.accessToken, response.refreshToken);
router.push('/dashboard');
}
async function handlePasswordChange(newPassword: string) {
const tempToken = sessionStorage.getItem('tempToken');
await authService.changePassword({
temporaryToken: tempToken,
newPassword,
confirmPassword: newPassword
});
sessionStorage.removeItem('tempToken');
// Now login with new password
router.push('/login');
}Related Flows
- Login Flow - Standard login with default tenant
- Switch Tenant - When user has no default tenant