> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nullpass.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Change Password

> Change user password

## Endpoint

```
POST /api/auth/password
```

## Overview

Changes the authenticated user's password. Requires the current password for verification. Password is hashed with bcrypt before storage.

## Request

<ParamField body="currentPassword" type="string" required>
  Current password for verification
</ParamField>

<ParamField body="newPassword" type="string" required>
  New password. Minimum 8 characters.
</ParamField>

## Response

<ResponseField name="success" type="boolean">
  Always `true` on success
</ResponseField>

<ResponseField name="message" type="string">
  "Password changed successfully"
</ResponseField>

## Implementation Details

### Process Flow

1. **Authentication**: Verifies user is authenticated
2. **Current Password Check**: Compares provided password with stored hash
3. **Password Hashing**: Hashes new password with bcrypt (10 rounds)
4. **Update**: Updates password hash in database
5. **Audit Logging**: Logs `PASSWORD_CHANGE` event

### Code Reference

```16:68:nullpass_clean/src/app/api/auth/password/route.ts theme={null}
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

<ResponseField name="200" type="OK">
  Password changed successfully
</ResponseField>

<ResponseField name="400" type="Bad Request">
  Validation error (new password too short, etc.)
</ResponseField>

<ResponseField name="401" type="Unauthorized">
  Invalid current password or missing authentication
</ResponseField>

<ResponseField name="404" type="Not Found">
  User not found
</ResponseField>

<ResponseField name="403" type="Forbidden">
  Blocked by Arcjet
</ResponseField>

## Example Request

```bash theme={null}
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

```json theme={null}
{
  "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


## OpenAPI

````yaml POST /auth/password
openapi: 3.1.0
info:
  title: Null Pass API
  description: >-
    Internal API documentation for Null Pass authentication and service
    management system
  version: 1.0.0
servers:
  - url: https://auth.nullpass.xyz/api
security: []
paths:
  /auth/password:
    post:
      tags:
        - Authentication
      summary: Change Password
      description: Change user password
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ChangePasswordRequest'
      responses:
        '200':
          description: Password changed successfully
      security:
        - bearerAuth: []
components:
  schemas:
    ChangePasswordRequest:
      type: object
      required:
        - currentPassword
        - newPassword
      properties:
        currentPassword:
          type: string
        newPassword:
          type: string
          minLength: 8
        verificationCode:
          type: string
          description: Required if 2FA is enabled
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````