cuatrolabs-auth-ms / STAFF_WATI_OTP_INTEGRATION.md
MukeshKapoor25's picture
chore(config): Update WATI customer OTP template name
a22c439

Staff WhatsApp OTP Integration - Complete Guide

Overview

Staff authentication now uses WATI WhatsApp API to send OTP codes via WhatsApp messages, providing a secure and convenient login method for staff/employee users.

Date: February 5, 2026
Integration: WATI WhatsApp Business API
Authentication Type: Mobile OTP via WhatsApp


Features

Staff OTP Authentication

  • βœ… WhatsApp OTP delivery via WATI API
  • βœ… Random 6-digit OTP generation
  • βœ… 5-minute OTP expiration
  • βœ… Maximum 3 verification attempts
  • βœ… One-time use enforcement
  • βœ… Staff role validation (excludes admin users)
  • βœ… Active user status verification
  • βœ… Message delivery tracking

Security Features

  • βœ… Separate OTP collection for staff (staff_otps)
  • βœ… User existence verification before sending OTP
  • βœ… Role-based access control (staff only, not admin)
  • βœ… Account status validation
  • βœ… JWT token generation with merchant context
  • βœ… Comprehensive audit logging

Architecture

Components

  1. StaffAuthService (app/auth/services/staff_auth_service.py)

    • Orchestrates staff OTP flow
    • Validates staff user eligibility
    • Integrates with WatiService
    • Manages OTP storage and verification
  2. WatiService (app/auth/services/wati_service.py)

    • Handles WATI API communication
    • Supports multiple templates (customer & staff)
    • Tracks message delivery
  3. Staff Router (app/auth/controllers/staff_router.py)

    • /staff/send-otp - Send OTP endpoint
    • /staff/login/mobile-otp - Verify OTP and login
  4. Configuration (app/core/config.py)

    • WATI_STAFF_OTP_TEMPLATE_NAME - Staff template name

Setup Instructions

1. Create Staff WhatsApp Template in WATI

Template Name: staff_otp_login

Template Content:

Your staff login OTP is: {{otp_code}}

This code will expire in {{expiry_time}} minutes.

Do not share this code with anyone.

Required Elements:

  • Category: AUTHENTICATION
  • OTP placeholder: {{otp_code}}
  • Expiry time placeholder: {{expiry_time}}
  • Security disclaimer
  • Button: "Copy Code" or "One-Tap Autofill"

Submit for WhatsApp approval (24-48 hours)

2. Environment Configuration

Already configured in .env:

WATI_API_ENDPOINT=https://live-mt-server.wati.io/104318
WATI_ACCESS_TOKEN=eyJhbGci...
WATI_STAFF_OTP_TEMPLATE_NAME=staff_otp_login

3. Database Collection

A new MongoDB collection staff_otps is automatically created with the following schema:

{
  phone: "+919999999999",           // Normalized phone number
  user_id: "uuid",                  // Staff user ID
  username: "staff@example.com",    // Staff username
  otp: "123456",                    // 6-digit code
  created_at: ISODate("..."),       // Creation timestamp
  expires_at: ISODate("..."),       // Expiration (5 min)
  attempts: 0,                      // Verification attempts
  verified: false,                  // Verification status
  wati_message_id: "abc-123-..."   // WATI tracking ID
}

API Endpoints

POST /staff/send-otp

Send OTP to staff mobile number via WhatsApp.

Request:

{
  "phone": "+919999999999"
}

Response (Success):

{
  "success": true,
  "message": "OTP sent successfully via WhatsApp",
  "expires_in": 300
}

Response (Error - User Not Found):

{
  "detail": "Staff user not found for this phone number"
}

Status: 404

Response (Error - Admin User):

{
  "detail": "Admin login not allowed via staff OTP"
}

Status: 403

Response (Error - Inactive User):

{
  "detail": "User account is inactive"
}

Status: 403

POST /staff/login/mobile-otp

Verify OTP and authenticate staff user.

Request:

{
  "phone": "+919999999999",
  "otp": "123456"
}

Response (Success):

{
  "access_token": "eyJhbGci...",
  "token_type": "bearer",
  "expires_in": 28800,
  "user_info": {
    "user_id": "uuid",
    "username": "staff@example.com",
    "email": "staff@example.com",
    "full_name": "Staff Name",
    "role": "staff",
    "merchant_id": "merchant-uuid",
    "merchant_type": "retail",
    "phone": "+919999999999",
    "status": "active",
    "permissions": []
  }
}

Response (Error - Invalid OTP):

{
  "detail": "Invalid OTP"
}

Status: 401

Response (Error - Expired OTP):

{
  "detail": "OTP has expired"
}

Status: 401

Response (Error - Too Many Attempts):

{
  "detail": "Too many attempts. Please request a new OTP"
}

Status: 401


Authentication Flow

Send OTP Flow

1. Staff requests OTP β†’ POST /staff/send-otp
   ↓
2. Verify staff user exists with phone number
   ↓
3. Validate user is staff role (not admin)
   ↓
4. Check user status is active
   ↓
5. Generate random 6-digit OTP
   ↓
6. Send OTP via WATI WhatsApp API
   ↓
7. Store OTP in staff_otps collection
   ↓
8. Return success response

Verify OTP Flow

1. Staff submits OTP β†’ POST /staff/login/mobile-otp
   ↓
2. Retrieve OTP from staff_otps collection
   ↓
3. Validate OTP (expiry, attempts, correctness)
   ↓
4. Verify user is still active and staff role
   ↓
5. Update last login timestamp
   ↓
6. Generate JWT token with merchant context
   ↓
7. Return authentication response

Differences from Customer OTP

Feature Customer OTP Staff OTP
Collection customer_otps staff_otps
Template cust_otp staff_otp_login
User Validation Find or create customer Must exist as staff user
Role Check N/A Must be staff (not admin)
Status Check N/A Must be active
Endpoints /customer/auth/* /staff/*
User Creation Auto-creates new customers No auto-creation

Testing

Quick Test

cd cuatrolabs-auth-ms
python test_staff_wati_otp.py

Test Options:

  1. Full staff OTP flow (send + verify)
  2. Direct WATI service test
  3. API endpoints test

Manual API Testing

# Send OTP to staff
curl -X POST http://localhost:8001/staff/send-otp \
  -H "Content-Type: application/json" \
  -d '{"phone": "+919999999999"}'

# Verify OTP and login
curl -X POST http://localhost:8001/staff/login/mobile-otp \
  -H "Content-Type: application/json" \
  -d '{"phone": "+919999999999", "otp": "123456"}'

Prerequisites for Testing

  1. Staff user must exist in system_users collection
  2. User must have phone number set
  3. User role must be staff/employee (not admin)
  4. User status must be "active"
  5. Phone number must be WhatsApp-enabled

Security Considerations

Staff-Specific Security

  1. User Existence: OTP only sent to existing staff users
  2. Role Validation: Admins cannot use staff OTP login
  3. Status Check: Only active users can receive OTP
  4. Separate Storage: Staff OTPs stored separately from customer OTPs
  5. Audit Trail: All attempts logged with user context

General Security

  1. Random OTP: Cryptographically secure random generation
  2. Expiration: 5-minute timeout
  3. Attempt Limiting: Maximum 3 attempts
  4. One-Time Use: OTPs marked as verified after use
  5. Secure Delivery: WhatsApp end-to-end encryption
  6. Message Tracking: WATI message IDs for audit

Error Handling

Common Errors

Error Cause Solution
Staff user not found Phone not in system_users Add staff user with phone
Admin login not allowed User has admin role Use regular admin login
User account is inactive Status not "active" Activate user account
Invalid OTP Wrong code entered Request new OTP
OTP has expired >5 minutes passed Request new OTP
Too many attempts >3 failed attempts Request new OTP

Troubleshooting

  1. OTP Not Received

    • Verify staff user exists: Check system_users collection
    • Verify phone number is correct
    • Check user role is staff (not admin)
    • Verify user status is active
    • Check WATI template is approved
    • Review application logs
  2. Verification Fails

    • Check OTP not expired (5 minutes)
    • Verify attempts not exceeded (max 3)
    • Confirm OTP not already used
    • Check phone number format

Logging

Log Levels

INFO:

Staff OTP sent successfully via WATI to +919999999999 for user staff@example.com
Staff OTP verified successfully for +919999999999, user: staff@example.com
Staff user logged in via mobile OTP: staff@example.com

WARNING:

Staff OTP request for non-existent phone: +919999999999
Admin user admin@example.com attempted staff OTP login
Inactive staff user attempted OTP: staff@example.com, status: inactive
Staff OTP verification failed - incorrect OTP for +919999999999

ERROR:

Failed to send staff OTP via WATI to +919999999999: Invalid WhatsApp number
Error sending staff OTP to +919999999999: [error details]

Monitoring

Metrics to Track

  • Staff OTP send success rate
  • Staff OTP verification success rate
  • Failed login attempts by reason
  • Average OTP delivery time
  • WATI API response times
  • Admin users attempting staff login

Alerts

  • Staff OTP send failure rate >5%
  • High number of invalid OTP attempts
  • Admin users using staff endpoints
  • WATI API errors

Deployment Checklist

  • Code implementation complete
  • Configuration added to .env
  • Test script created
  • Documentation created
  • WATI staff template created
  • WATI staff template approved
  • Test with real staff users
  • Production deployment
  • Monitoring setup

Next Steps

  1. Create WATI Template

    • Log into WATI dashboard
    • Create authentication template: staff_otp_login
    • Submit for WhatsApp approval
  2. Test with Staff Users

    • Run python test_staff_wati_otp.py
    • Test with multiple staff accounts
    • Verify error scenarios
  3. Deploy to Production

    • Ensure template is approved
    • Deploy updated code
    • Monitor logs
    • Track success rates

Support

Resources

Troubleshooting

  1. Check logs: cuatrolabs-auth-ms/logs/
  2. Run test script: python test_staff_wati_otp.py
  3. Verify staff user exists and is active
  4. Check WATI dashboard for message status

Status: βœ… READY FOR TESTING

Next Step: Create and approve WATI staff authentication template.