Endpoint
Overview
Changes the authenticated user’s password. Requires the current password for verification. Password is hashed with bcrypt before storage.
Request
Current password for verification
New password. Minimum 8 characters.
Response
“Password changed successfully”
Implementation Details
Process Flow
- Authentication: Verifies user is authenticated
- Current Password Check: Compares provided password with stored hash
- Password Hashing: Hashes new password with bcrypt (10 rounds)
- Update: Updates password hash in database
- Audit Logging: Logs
PASSWORD_CHANGE event
Code Reference
export async function POST(request: NextRequest) {
const corsResponse = handleCors(request)
if (corsResponse) return corsResponse
const blocked = await protectRoute(request, { requested: 2 })
if (blocked) return blocked
const auth = await requireAuth(request)
if ('error' in auth) return auth.error
try {
const body = await request.json()
const validated = changePasswordSchema.parse(body)
const user = await prisma.user.findUnique({
where: { id: auth.userId },
select: {
id: true,
passwordHash: true,
},
})
if (!user || !user.passwordHash) {
return errorResponse('User not found', 404, request.headers.get('origin'))
}
const isValid = await bcrypt.compare(validated.currentPassword, user.passwordHash)
if (!isValid) {
logger.warn('Password change failed: Invalid current password', auth.userId)
return errorResponse('Invalid current password', 401, request.headers.get('origin'))
}
const newPasswordHash = await bcrypt.hash(validated.newPassword, 10)
await prisma.user.update({
where: { id: auth.userId },
data: {
passwordHash: newPasswordHash,
},
})
await createAuditLog(auth.userId, 'PASSWORD_CHANGE', {})
return jsonResponse({ success: true, message: 'Password changed successfully' }, 200, request.headers.get('origin'))
} catch (error: any) {
if (error.name === 'ZodError') {
logger.warn('Password change validation error:', error.errors)
return errorResponse(error.errors[0].message, 400, request.headers.get('origin'))
}
logger.error('Change password error:', error)
return errorResponse('Internal server error', 500, request.headers.get('origin'))
}
}
Status Codes
Password changed successfully
Validation error (new password too short, etc.)
Invalid current password or missing authentication
Example Request
curl -X POST https://auth.nullpass.xyz/api/auth/password \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"currentPassword": "oldpassword123",
"newPassword": "newsecurepassword456"
}'
Example Response
{
"success": true,
"message": "Password changed successfully"
}
Security Considerations
- Current password must be verified before change
- New password is hashed with bcrypt (10 rounds)
- Rate limiting applied (2 requests per bucket)
- All password changes are logged in audit trail
- Old password hash is completely replaced (no history kept)
Audit Events
- PASSWORD_CHANGE: Password successfully changed
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Required if 2FA is enabled
Password changed successfully