Skip to main content
The password reset flow consists of three steps:
  1. Request a reset token - User provides email or phone
  2. Verify the reset token - Validate token and show masked identifier
  3. Reset password - Submit new password with token

Step 1: Request Password Reset

Send a password reset link to the user via email or WhatsApp.

Authentication

This endpoint does not require authentication.

Request Body

email
string
User’s email address. Required if phone is not provided.Validation: Must be a valid email format.Example: [email protected]
phone
string
User’s phone number. Required if email is not provided.Example: +525512345678
You must provide either email or phone, but not both.

Response

status
string
Response status, always “success”
message
string
Confirmation message indicating the reset link has been sent

Success Response Example

{
  "status": "success",
  "message": "Password reset link sent successfully"
}

Error Responses

Code Example

curl -X POST https://api.sushigo.local/api/v1/auth/forgot-password \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "email": "[email protected]"
  }'

Step 2: Verify Reset Token

Validate the reset token and retrieve the masked identifier (email or phone) associated with it.

Authentication

This endpoint does not require authentication.

Request Body

t
string
required
Combined reset parameter in the format: {40-char token}.{24-char selector}This token is typically extracted from the reset link URL sent to the user.Validation: Required string.Example: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0.x1y2z3a4b5c6d7e8f9g0h1i2

Response

status
string
Response status, always “success”
masked_identifier
string
The masked email or phone number associated with the reset tokenExample: ju***@example.com or +52***5678

Success Response Example

{
  "status": "success",
  "masked_identifier": "ju***@example.com"
}

Error Responses

Code Example

curl -X POST https://api.sushigo.local/api/v1/auth/verify-reset-token \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "t": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0.x1y2z3a4b5c6d7e8f9g0h1i2"
  }'

Step 3: Reset Password

Reset the user’s password using a valid token and return authentication credentials.

Authentication

This endpoint does not require authentication.

Request Body

t
string
required
Combined reset parameter in the format: {40-char token}.{24-char selector}Same token format as used in the verify step.Validation: Required string.Example: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0.x1y2z3a4b5c6d7e8f9g0h1i2
password
string
required
New password for the user account.Validation: Minimum 8 characters, must match password_confirmation.Example: newpassword123
password_confirmation
string
required
Confirmation of the new password. Must match the password field exactly.Validation: Required, must match password.Example: newpassword123

Response

status
integer
HTTP status code (200 for success)
data
object
The response structure is identical to the login endpoint - the user is automatically authenticated after a successful password reset.

Success Response Example

{
  "status": 200,
  "data": {
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJhdWQiOiIxIiwianRpIjoiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoiLCJpYXQiOjE3MDk4NTYwMDAsIm5iZiI6MTcwOTg1NjAwMCwiZXhwIjoxNzQxMzkyMDAwLCJzdWIiOiIyIiwic2NvcGVzIjpbXX0...",
    "token_type": "Bearer",
    "user": {
      "id": 2,
      "name": "Juan Pérez",
      "email": "[email protected]",
      "roles": [
        {
          "id": 2,
          "name": "inventory-manager"
        }
      ],
      "permissions": [
        {
          "id": 5,
          "name": "view-items"
        }
      ]
    }
  }
}

Error Responses

Code Example

curl -X POST https://api.sushigo.local/api/v1/auth/reset-password \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "t": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0.x1y2z3a4b5c6d7e8f9g0h1i2",
    "password": "newpassword123",
    "password_confirmation": "newpassword123"
  }'

Complete Flow Example

Here’s a complete implementation of the password reset flow:
// 1. Request password reset
async function requestPasswordReset(email) {
  const response = await fetch('/api/v1/auth/forgot-password', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email })
  });
  
  const data = await response.json();
  alert(data.message); // "Password reset link sent successfully"
}

// 2. Verify token (when user clicks the reset link)
async function verifyResetToken(token) {
  const response = await fetch('/api/v1/auth/verify-reset-token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ t: token })
  });
  
  if (!response.ok) {
    throw new Error('Invalid or expired token');
  }
  
  const data = await response.json();
  return data.masked_identifier; // "ju***@example.com"
}

// 3. Reset password
async function resetPassword(token, password, passwordConfirmation) {
  const response = await fetch('/api/v1/auth/reset-password', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      t: token,
      password,
      password_confirmation: passwordConfirmation
    })
  });
  
  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.message);
  }
  
  const data = await response.json();
  
  // Store token and authenticate user
  localStorage.setItem('auth_token', data.data.token);
  
  return data.data.user;
}

// Usage in reset password page
async function handleResetPage() {
  const urlParams = new URLSearchParams(window.location.search);
  const token = urlParams.get('t');
  
  try {
    // Verify token and show masked identifier
    const maskedIdentifier = await verifyResetToken(token);
    document.getElementById('identifier').textContent = maskedIdentifier;
    
    // Handle form submission
    document.getElementById('resetForm').addEventListener('submit', async (e) => {
      e.preventDefault();
      const password = document.getElementById('password').value;
      const confirmation = document.getElementById('confirmation').value;
      
      const user = await resetPassword(token, password, confirmation);
      
      // Redirect to dashboard
      window.location.href = '/dashboard';
    });
  } catch (error) {
    alert('Invalid or expired reset link');
    window.location.href = '/forgot-password';
  }
}

Usage Notes

  • The reset token is a combined string of format {token}.{selector} with a total length of 65 characters (40 + 1 + 24)
  • Tokens typically expire after 1 hour (configurable in backend)
  • After a successful password reset, the user is automatically authenticated with a new access token
  • The old password is invalidated immediately upon reset
  • All existing tokens for the user remain valid unless explicitly revoked
  • The masked identifier in step 2 helps the user confirm they’re resetting the correct account

Build docs developers (and LLMs) love