Add forgot-password flow with admin-mediated reset links
Task #18: self-service "Forgot password?" flow on the sign-in page, plus an admin-mediated delivery path so tokens actually reach users without email infrastructure. Changes: - New password_reset_tokens table (SHA-256 hashed token, 1h TTL, single-use) added via schema + raw SQL. - Public endpoints: POST /auth/forgot-password (identical response for valid/invalid identifiers, no account enumeration), POST /auth/reset-password/verify, POST /auth/reset-password. Raw tokens are never returned or logged — only id + expiry. - Admin-only endpoint: POST /auth/admin/users/:id/issue-reset-link returns a one-time reset URL (origin + hex token) so admins can share it with the user out-of-band until email delivery lands. - Frontend: "Forgot password?" link on login, new /forgot-password and /reset-password pages, admin Users list gets a KeyRound button opening a modal with the generated URL and a Copy button. Public routes /forgot-password and /reset-password registered in AuthContext. - Bilingual EN/AR copy for all new screens and admin modal. Verification: full end-to-end test passed — admin generated link, user reset password via link, logged in with new password, and reused token was rejected as invalid (single-use enforced). Follow-ups proposed: #25 transactional email delivery, #26 rate limiting on the public reset endpoints.
This commit is contained in:
@@ -33,6 +33,34 @@ export interface LoginBody {
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface ForgotPasswordBody {
|
||||
/** Username or email */
|
||||
identifier: string;
|
||||
}
|
||||
|
||||
export interface ForgotPasswordResponse {
|
||||
success: boolean;
|
||||
}
|
||||
|
||||
export interface ResetPasswordBody {
|
||||
token: string;
|
||||
/** @minLength 6 */
|
||||
newPassword: string;
|
||||
}
|
||||
|
||||
export interface VerifyResetTokenBody {
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface AdminResetLinkResponse {
|
||||
resetUrl: string;
|
||||
expiresAt: string;
|
||||
}
|
||||
|
||||
export interface VerifyResetTokenResponse {
|
||||
valid: boolean;
|
||||
}
|
||||
|
||||
export interface UpdateLanguageBody {
|
||||
language: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user