1House Global API Documentation

Password Reset

Comprehensive guide for the forgot password flow

Overview

The password reset flow uses a 6-digit verification code sent via email. The process is secure, rate-limited, and includes multiple validation steps.

Security Features

  • 6-digit verification codes
  • 1-hour code expiration
  • SHA-256 code hashing
  • Rate limiting (2 minutes between requests)
  • Maximum 5 attempts per 24 hours
  • Email enumeration prevention
  • Session invalidation on reset
  • API key authentication required

Authentication Required

All password reset endpoints require an x-api-key header:

x-api-key: your-api-key

Contact your platform administrator to obtain an API key for your application.

Password Reset Flow

Step 1: Request Password Reset

Endpoint: POST /auth/forgot-password

Headers:

Content-Type: application/json
x-api-key: your-api-key

Request Body:

{
  "email": "user@example.com"
}

Response:

{
  "success": true,
  "message": "Password reset code sent to your email",
  "data": {
    "success": true,
    "message": "Password reset code sent to your email"
  }
}

Notes:

  • Always returns success to prevent email enumeration
  • Code sent via email (check inbox and spam)
  • Code expires in 1 hour
  • Rate limited to 1 request per 2 minutes
  • Maximum 5 requests per 24 hours

Try it out:


Step 2: Validate Reset Code (Optional)

Endpoint: POST /auth/validate-reset-code

This optional step allows you to verify the code before attempting to reset the password.

Headers:

Content-Type: application/json
x-api-key: your-api-key

Request Body:

{
  "email": "user@example.com",
  "resetCode": "123456"
}

Success Response:

{
  "success": true,
  "message": "Reset code is valid",
  "data": {
    "success": true,
    "message": "Reset code is valid",
    "userId": "60d5ec49f1b2c8b1f8e4e1a1"
  }
}

Error Response:

{
  "success": false,
  "message": "Invalid or expired reset code",
  "statusCode": 400
}

Step 3: Reset Password

Endpoint: POST /auth/reset-password

Headers:

Content-Type: application/json
x-api-key: your-api-key

Request Body:

{
  "email": "user@example.com",
  "resetCode": "123456",
  "newPassword": "NewSecure@Pass123"
}

Success Response:

{
  "success": true,
  "message": "Password has been reset successfully. Please sign in with your new password.",
  "data": {
    "success": true,
    "message": "Password has been reset successfully. Please sign in with your new password."
  }
}

Important:

  • All existing sessions are invalidated
  • User must sign in again with new password
  • Confirmation email is sent

Password Requirements

Passwords must meet these criteria:

  • Minimum 8 characters
  • At least one uppercase letter (A-Z)
  • At least one lowercase letter (a-z)
  • At least one number (0-9)
  • At least one special character (@$!%*?&#)

Valid examples: SecurePass@123, MyP@ssw0rd!, Strong#Pass1

Invalid examples: password (no uppercase, number, or special char); PASSWORD123 (no lowercase or special char); Pass@12 (too short, fewer than 8 characters)


Change Password (Authenticated Users)

Endpoint: POST /auth/change-password

For users who are already signed in and want to change their password.

Headers:

Content-Type: application/json
Authorization: Bearer <access_token>

Request Body:

{
  "currentPassword": "OldPassword@123",
  "newPassword": "NewSecure@Pass123"
}

Response:

{
  "success": true,
  "message": "Password changed successfully"
}

Notes:

  • Requires valid authentication token
  • Current password must be correct
  • New password must meet requirements
  • Confirmation email is sent

Error Codes

StatusMessageCause
400Invalid or expired reset codeCode is incorrect or has expired
401API key is requiredMissing x-api-key header
401Current password is incorrectWrong password (change password)
403Invalid API keyIncorrect x-api-key header
403Account is deactivatedUser account is disabled
429Please wait 2 minutes before requesting another reset codeRate limit exceeded
429Too many reset attempts. Please try again in 24 hoursMaximum attempts exceeded

Implementation Examples

React/JavaScript

// Development
const DEV_API_URL = 'https://api-gateway.dev.1houseglobalservices.com';
const DEV_API_KEY = process.env.REACT_APP_DEV_API_KEY;

// Production
const PROD_API_URL = 'https://api-gateway.prod.1houseglobalservices.com';
const PROD_API_KEY = process.env.REACT_APP_PROD_API_KEY;

// Use appropriate environment
const API_URL = process.env.NODE_ENV === 'production' ? PROD_API_URL : DEV_API_URL;
const API_KEY = process.env.NODE_ENV === 'production' ? PROD_API_KEY : DEV_API_KEY;

// 1. Request password reset
const requestReset = async (email) => {
  const response = await fetch(`${API_URL}/v1/auth/forgot-password`, {
    method: 'POST',
    headers: {
      'X-API-Key': API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ email })
  });
  
  const data = await response.json();
  if (data.success) {
    // Show code entry form
    return true;
  }
  return false;
};

// 2. Validate code (optional)
const validateCode = async (email, resetCode) => {
  const response = await fetch(`${API_URL}/v1/auth/forgot-password/validate`, {
    method: 'POST',
    headers: {
      'X-API-Key': API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ email, resetCode })
  });
  
  const data = await response.json();
  return data.success;
};

// 3. Reset password
const resetPassword = async (email, resetCode, newPassword) => {
  const response = await fetch(`${API_URL}/v1/auth/forgot-password/reset`, {
    method: 'POST',
    headers: {
      'X-API-Key': API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ email, resetCode, newPassword })
  });
  
  const data = await response.json();
  if (data.success) {
    // Redirect to sign in
    window.location.href = '/signin';
  }
  return data.success;
};

iOS (Swift)

class PasswordResetManager {
    // Development
    private let devBaseURL = "https://api-gateway.dev.1houseglobalservices.com"
    private let devAPIKey = Bundle.main.infoDictionary?["DEV_API_KEY"] as? String ?? ""
    
    // Production
    private let prodBaseURL = "https://api-gateway.prod.1houseglobalservices.com"
    private let prodAPIKey = Bundle.main.infoDictionary?["PROD_API_KEY"] as? String ?? ""
    
    // Use appropriate environment
    private var baseURL: String {
        return ProcessInfo.processInfo.environment["ENVIRONMENT"] == "production" ? prodBaseURL : devBaseURL
    }
    private var apiKey: String {
        return ProcessInfo.processInfo.environment["ENVIRONMENT"] == "production" ? prodAPIKey : devAPIKey
    }
    
    func requestPasswordReset(email: String, completion: @escaping (Bool) -> Void) {
        let url = URL(string: "\(baseURL)/v1/auth/forgot-password")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
        
        let body = ["email": email]
        request.httpBody = try? JSONSerialization.data(withJSONObject: body)
        
        URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data,
                  let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
                  let success = json["success"] as? Bool else {
                completion(false)
                return
            }
            completion(success)
        }.resume()
    }
    
    func resetPassword(email: String, code: String, newPassword: String, completion: @escaping (Bool) -> Void) {
        let url = URL(string: "\(baseURL)/v1/auth/forgot-password/reset")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.setValue(apiKey, forHTTPHeaderField: "X-API-Key")
        
        let body: [String: String] = [
            "email": email,
            "resetCode": code,
            "newPassword": newPassword
        ]
        request.httpBody = try? JSONSerialization.data(withJSONObject: body)
        
        URLSession.shared.dataTask(with: request) { data, response, error in
            guard let data = data,
                  let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
                  let success = json["success"] as? Bool else {
                completion(false)
                return
            }
            completion(success)
        }.resume()
    }
}

Android (Kotlin)

class PasswordResetManager(private val context: Context) {
    // Development
    private val devBaseUrl = "https://api-gateway.dev.1houseglobalservices.com"
    private val devApiKey = BuildConfig.DEV_API_KEY
    
    // Production
    private val prodBaseUrl = "https://api-gateway.prod.1houseglobalservices.com"
    private val prodApiKey = BuildConfig.PROD_API_KEY
    
    // Use appropriate environment
    private val baseUrl: String
        get() = if (BuildConfig.BUILD_TYPE == "release") prodBaseUrl else devBaseUrl
    private val apiKey: String
        get() = if (BuildConfig.BUILD_TYPE == "release") prodApiKey else devApiKey
    
    private val client = OkHttpClient()

    fun requestPasswordReset(email: String, callback: (Boolean) -> Unit) {
        val json = JSONObject().apply {
            put("email", email)
        }
        
        val body = RequestBody.create(
            "application/json".toMediaType(),
            json.toString()
        )
        
        val request = Request.Builder()
            .url("$baseUrl/v1/auth/forgot-password")
            .addHeader("X-API-Key", apiKey)
            .post(body)
            .build()
        
        client.newCall(request).enqueue(object : Callback {
            override fun onResponse(call: Call, response: Response) {
                val responseBody = response.body?.string()
                val jsonResponse = JSONObject(responseBody ?: "{}")
                callback(jsonResponse.getBoolean("success"))
            }
            
            override fun onFailure(call: Call, e: IOException) {
                callback(false)
            }
        })
    }
    
    fun resetPassword(email: String, code: String, newPassword: String, callback: (Boolean) -> Unit) {
        val json = JSONObject().apply {
            put("email", email)
            put("resetCode", code)
            put("newPassword", newPassword)
        }
        
        val body = RequestBody.create(
            "application/json".toMediaType(),
            json.toString()
        )
        
        val request = Request.Builder()
            .url("$baseUrl/v1/auth/forgot-password/reset")
            .addHeader("X-API-Key", apiKey)
            .post(body)
            .build()
        
        client.newCall(request).enqueue(object : Callback {
            override fun onResponse(call: Call, response: Response) {
                val responseBody = response.body?.string()
                val jsonResponse = JSONObject(responseBody ?: "{}")
                callback(jsonResponse.getBoolean("success"))
            }
            
            override fun onFailure(call: Call, e: IOException) {
                callback(false)
            }
        })
    }
}

UX Recommendations

1. Forgot Password Screen

  • Clear "Forgot Password?" link on sign-in page
  • Simple email input field
  • Informative success message
  • Link back to sign-in

2. Code Entry Screen

  • Large input field for 6-digit code
  • Auto-focus on page load
  • Numeric keyboard on mobile
  • "Resend code" option (respecting rate limits)
  • Clear error messages

3. New Password Screen

  • Password strength indicator
  • Show password requirements
  • Password visibility toggle
  • Confirm password field
  • Clear success message

4. Email Design

  • Users receive professional HTML email
  • 6-digit code prominently displayed
  • Reset link button for convenience
  • 1-hour expiration notice
  • Security warning

Testing

Test Flow

Environment-Specific Testing

When testing, make sure to use the correct environment URL and API key:

  • Development: https://api-gateway.dev.1houseglobalservices.com with your development API key
  • Production: https://api-gateway.prod.1houseglobalservices.com with your production API key
# Development - Set your development API key
export DEV_API_KEY="your-development-api-key"
export DEV_API_URL="https://api-gateway.dev.1houseglobalservices.com"

# Production - Set your production API key
export PROD_API_KEY="your-production-api-key"
export PROD_API_URL="https://api-gateway.prod.1houseglobalservices.com"

# Use appropriate environment (example uses development)
export API_KEY=$DEV_API_KEY
export API_URL=$DEV_API_URL

# 1. Request reset code
curl -X POST $API_URL/v1/auth/forgot-password \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $API_KEY" \
  -d '{"email":"test@example.com"}'

# 2. Check email for 6-digit code

# 3. Validate code (optional)
curl -X POST $API_URL/v1/auth/forgot-password/validate \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $API_KEY" \
  -d '{"email":"test@example.com","resetCode":"123456"}'

# 4. Reset password
curl -X POST $API_URL/v1/auth/forgot-password/reset \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $API_KEY" \
  -d '{
    "email":"test@example.com",
    "resetCode":"123456",
    "newPassword":"NewSecure@Pass123"
  }'

Email Templates

Users receive beautiful, branded emails:

Password Reset Email

  • Subject: "Reset Your Password - 1House Global"
  • Content: 6-digit code, reset link button, expiration notice
  • Design: Gradient header, clean layout, security warnings

Password Changed Email

  • Subject: "Password Changed Successfully - 1House Global"
  • Content: Confirmation message, security alert
  • Design: Green theme, clear alert box

Troubleshooting

"API key is required"

  • Add x-api-key header to your request
  • Contact administrator for API key

"Invalid or expired reset code"

  • Code may have expired (1 hour limit)
  • Verify email matches exactly
  • Check for typos in 6-digit code
  • Request a new code

"Please wait 2 minutes"

  • Rate limit protection
  • Wait 2 minutes before requesting again
  • This prevents abuse

"Too many reset attempts"

  • Maximum 5 attempts per 24 hours reached
  • Wait 24 hours or contact support
  • This is a security measure

Email not received

  • Check spam/junk folder
  • Verify email address is correct
  • Wait a few minutes (emails can be delayed)
  • Request a new code after 2 minutes

Best Practices

For Developers

  1. Store API key securely

    • Use environment variables
    • Never hardcode in source code
    • Keep separate keys for dev/prod
  2. Handle errors gracefully

    • Show user-friendly error messages
    • Don't expose technical details
    • Provide alternative support options
  3. Implement proper UX

    • Clear instructions
    • Progress indicators
    • Success confirmations
    • Easy navigation back to sign-in
  4. Security

    • Always use HTTPS
    • Validate input client-side
    • Show password strength
    • Confirm password field

For Users

  1. Check email inbox and spam
  2. Code expires in 1 hour - use it promptly
  3. Never share your reset code
  4. Contact support if issues persist


Support

If you encounter issues:

  1. Review error message carefully
  2. Check troubleshooting section above
  3. Verify API key is correct
  4. Test with the provided curl commands
  5. Contact platform support with error details