Spaces:
Running
Running
Commit Β·
7ad6539
1
Parent(s): 21b0cca
fix(wati_service): Add validation for missing access token and deployment configuration
Browse files- Add early validation of WATI_ACCESS_TOKEN in service initialization to catch missing configuration
- Implement token validation in _get_headers() method to prevent illegal "Bearer " header values
- Add pre-flight checks in send_otp_message() before attempting API requests
- Strip whitespace from access token to handle edge cases
- Create diagnostic script (check_wati_config.py) to verify WATI configuration in deployment
- Create error handling test script (test_wati_error_handling.py) for validation scenarios
- Add comprehensive documentation (WATI_BEARER_TOKEN_FIX.md) explaining root cause and deployment steps
- Prevents httpcore.LocalProtocolError when WATI_ACCESS_TOKEN is not configured in Docker/Kubernetes environments
- WATI_BEARER_TOKEN_FIX.md +158 -0
- WATI_DEPLOYMENT_FIX.md +129 -0
- app/auth/services/wati_service.py +16 -1
- check_wati_config.py +45 -0
- test_wati_error_handling.py +57 -0
WATI_BEARER_TOKEN_FIX.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# WATI Bearer Token Error Fix
|
| 2 |
+
|
| 3 |
+
## Problem
|
| 4 |
+
|
| 5 |
+
The WATI WhatsApp OTP service was failing with the error:
|
| 6 |
+
```
|
| 7 |
+
httpcore.LocalProtocolError: Illegal header value b'Bearer '
|
| 8 |
+
```
|
| 9 |
+
|
| 10 |
+
This error occurs when the Authorization header is set to `"Bearer "` (with a space but no actual token), which is an illegal HTTP header value.
|
| 11 |
+
|
| 12 |
+
## Root Cause
|
| 13 |
+
|
| 14 |
+
The `WATI_ACCESS_TOKEN` environment variable was **not configured in the deployment environment** (Docker/Kubernetes), even though it was present in the local `.env` file.
|
| 15 |
+
|
| 16 |
+
When the service runs in a container:
|
| 17 |
+
1. The `.env` file is not copied to the Docker image (by design, for security)
|
| 18 |
+
2. Environment variables must be passed via Docker environment variables or Kubernetes secrets
|
| 19 |
+
3. Without the token, the code was generating `"Bearer "` (empty token), causing the HTTP error
|
| 20 |
+
|
| 21 |
+
## Solution
|
| 22 |
+
|
| 23 |
+
### 1. Enhanced Error Handling in `wati_service.py`
|
| 24 |
+
|
| 25 |
+
Added validation to catch missing/empty tokens early:
|
| 26 |
+
|
| 27 |
+
```python
|
| 28 |
+
def __init__(self):
|
| 29 |
+
# ... existing code ...
|
| 30 |
+
|
| 31 |
+
# Validate configuration on initialization
|
| 32 |
+
if not self.access_token or not self.access_token.strip():
|
| 33 |
+
logger.warning(
|
| 34 |
+
"WATI_ACCESS_TOKEN is not configured or is empty. "
|
| 35 |
+
"WhatsApp OTP functionality will not work."
|
| 36 |
+
)
|
| 37 |
+
|
| 38 |
+
def _get_headers(self) -> Dict[str, str]:
|
| 39 |
+
"""Get HTTP headers for WATI API requests."""
|
| 40 |
+
if not self.access_token or not self.access_token.strip():
|
| 41 |
+
raise ValueError("WATI_ACCESS_TOKEN is not configured or is empty")
|
| 42 |
+
|
| 43 |
+
return {
|
| 44 |
+
"Authorization": f"Bearer {self.access_token.strip()}",
|
| 45 |
+
"Content-Type": "application/json"
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
async def send_otp_message(...):
|
| 49 |
+
# Validate configuration before attempting to send
|
| 50 |
+
if not self.access_token or not self.access_token.strip():
|
| 51 |
+
logger.error("WATI_ACCESS_TOKEN is not configured. Cannot send OTP.")
|
| 52 |
+
return False, "WhatsApp OTP service is not configured", None
|
| 53 |
+
# ... rest of the code ...
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
### 2. Updated Helm Deployment Configuration
|
| 57 |
+
|
| 58 |
+
Added WATI environment variables to `cuatrolabs-deploy/values-auth-ms.yaml`:
|
| 59 |
+
|
| 60 |
+
```yaml
|
| 61 |
+
env:
|
| 62 |
+
# ... existing env vars ...
|
| 63 |
+
# WATI WhatsApp API Configuration
|
| 64 |
+
WATI_API_ENDPOINT: "https://live-mt-server.wati.io/104318"
|
| 65 |
+
WATI_OTP_TEMPLATE_NAME: "customer_otp_login"
|
| 66 |
+
WATI_STAFF_OTP_TEMPLATE_NAME: "staff_otp_login"
|
| 67 |
+
# OTP Configuration
|
| 68 |
+
OTP_TTL_SECONDS: "600"
|
| 69 |
+
OTP_RATE_LIMIT_MAX: "10"
|
| 70 |
+
OTP_RATE_LIMIT_WINDOW: "600"
|
| 71 |
+
|
| 72 |
+
secretEnv:
|
| 73 |
+
# ... existing secrets ...
|
| 74 |
+
# WATI Access Token (sensitive - should be in secrets)
|
| 75 |
+
WATI_ACCESS_TOKEN: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
### 3. Created Diagnostic Script
|
| 79 |
+
|
| 80 |
+
Created `check_wati_config.py` to verify WATI configuration:
|
| 81 |
+
|
| 82 |
+
```bash
|
| 83 |
+
cd cuatrolabs-auth-ms
|
| 84 |
+
python3 check_wati_config.py
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
This script checks:
|
| 88 |
+
- Whether WATI_ACCESS_TOKEN is loaded
|
| 89 |
+
- Token length and format
|
| 90 |
+
- Header generation
|
| 91 |
+
|
| 92 |
+
## Deployment Steps
|
| 93 |
+
|
| 94 |
+
### For Local Development
|
| 95 |
+
|
| 96 |
+
The `.env` file already has the correct configuration. No changes needed.
|
| 97 |
+
|
| 98 |
+
### For Docker/Kubernetes Deployment
|
| 99 |
+
|
| 100 |
+
1. **Update the deployment** with the new Helm values:
|
| 101 |
+
```bash
|
| 102 |
+
cd cuatrolabs-deploy
|
| 103 |
+
./deploy-helm.sh auth-ms
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
2. **Verify the deployment**:
|
| 107 |
+
```bash
|
| 108 |
+
kubectl get pods -l app=auth-ms
|
| 109 |
+
kubectl logs -l app=auth-ms --tail=50
|
| 110 |
+
```
|
| 111 |
+
|
| 112 |
+
3. **Test the OTP endpoint**:
|
| 113 |
+
```bash
|
| 114 |
+
curl -X POST https://api.cuatrolabs.com/auth/customer/send-otp \
|
| 115 |
+
-H "Content-Type: application/json" \
|
| 116 |
+
-d '{"mobile": "+919999999999"}'
|
| 117 |
+
```
|
| 118 |
+
|
| 119 |
+
### For Production (Best Practice)
|
| 120 |
+
|
| 121 |
+
Instead of hardcoding the token in `values-auth-ms.yaml`, use Kubernetes secrets:
|
| 122 |
+
|
| 123 |
+
1. **Create a secret**:
|
| 124 |
+
```bash
|
| 125 |
+
kubectl create secret generic wati-credentials \
|
| 126 |
+
--from-literal=access-token='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
2. **Update the Helm chart** to reference the secret:
|
| 130 |
+
```yaml
|
| 131 |
+
envFrom:
|
| 132 |
+
- secretRef:
|
| 133 |
+
name: wati-credentials
|
| 134 |
+
```
|
| 135 |
+
|
| 136 |
+
## Verification
|
| 137 |
+
|
| 138 |
+
After deployment, check the logs for:
|
| 139 |
+
|
| 140 |
+
β
**Success**: `OTP sent successfully via WATI to 919999999999. Message ID: xxx`
|
| 141 |
+
|
| 142 |
+
β **Configuration Error**: `WATI_ACCESS_TOKEN is not configured. Cannot send OTP.`
|
| 143 |
+
|
| 144 |
+
β **API Error**: `WATI API request failed with status 401` (invalid token)
|
| 145 |
+
|
| 146 |
+
## Files Modified
|
| 147 |
+
|
| 148 |
+
1. `cuatrolabs-auth-ms/app/auth/services/wati_service.py` - Enhanced error handling
|
| 149 |
+
2. `cuatrolabs-deploy/values-auth-ms.yaml` - Added WATI environment variables
|
| 150 |
+
3. `cuatrolabs-auth-ms/check_wati_config.py` - New diagnostic script (created)
|
| 151 |
+
4. `cuatrolabs-auth-ms/WATI_BEARER_TOKEN_FIX.md` - This documentation (created)
|
| 152 |
+
|
| 153 |
+
## Related Documentation
|
| 154 |
+
|
| 155 |
+
- `cuatrolabs-auth-ms/WATI_INTEGRATION_OVERVIEW.md` - WATI integration overview
|
| 156 |
+
- `cuatrolabs-auth-ms/WATI_QUICKSTART.md` - Quick start guide
|
| 157 |
+
- `cuatrolabs-auth-ms/WATI_WHATSAPP_OTP_INTEGRATION.md` - Detailed integration guide
|
| 158 |
+
- `cuatrolabs-auth-ms/WATI_DEPLOYMENT_CHECKLIST.md` - Deployment checklist
|
WATI_DEPLOYMENT_FIX.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# WATI Deployment Fix - Quick Reference
|
| 2 |
+
|
| 3 |
+
## Issue
|
| 4 |
+
`httpcore.LocalProtocolError: Illegal header value b'Bearer '` when sending OTP via WATI.
|
| 5 |
+
|
| 6 |
+
## Cause
|
| 7 |
+
Missing `WATI_ACCESS_TOKEN` environment variable in deployment configuration.
|
| 8 |
+
|
| 9 |
+
## Fix Applied
|
| 10 |
+
|
| 11 |
+
### 1. Code Changes (Already Applied)
|
| 12 |
+
- β
Enhanced error handling in `wati_service.py`
|
| 13 |
+
- β
Early validation of WATI_ACCESS_TOKEN
|
| 14 |
+
- β
Graceful error messages instead of crashes
|
| 15 |
+
|
| 16 |
+
### 2. Deployment Configuration (Action Required)
|
| 17 |
+
|
| 18 |
+
**File**: `cuatrolabs-deploy/values-auth-ms.yaml`
|
| 19 |
+
|
| 20 |
+
Added WATI environment variables:
|
| 21 |
+
```yaml
|
| 22 |
+
env:
|
| 23 |
+
WATI_API_ENDPOINT: "https://live-mt-server.wati.io/104318"
|
| 24 |
+
WATI_OTP_TEMPLATE_NAME: "customer_otp_login"
|
| 25 |
+
WATI_STAFF_OTP_TEMPLATE_NAME: "staff_otp_login"
|
| 26 |
+
OTP_TTL_SECONDS: "600"
|
| 27 |
+
|
| 28 |
+
secretEnv:
|
| 29 |
+
WATI_ACCESS_TOKEN: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
| 30 |
+
```
|
| 31 |
+
|
| 32 |
+
## Deployment Steps
|
| 33 |
+
|
| 34 |
+
### Option A: Quick Deploy (Development/Staging)
|
| 35 |
+
|
| 36 |
+
```bash
|
| 37 |
+
cd cuatrolabs-deploy
|
| 38 |
+
./deploy-helm.sh auth-ms
|
| 39 |
+
```
|
| 40 |
+
|
| 41 |
+
### Option B: Production Deploy (Recommended)
|
| 42 |
+
|
| 43 |
+
Use Kubernetes secrets for sensitive data:
|
| 44 |
+
|
| 45 |
+
```bash
|
| 46 |
+
# 1. Create secret
|
| 47 |
+
kubectl create secret generic wati-credentials \
|
| 48 |
+
--from-literal=WATI_ACCESS_TOKEN='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6ImN0b0BjdWF0cm9sYWJzLmNvbSIsIm5hbWVpZCI6ImN0b0BjdWF0cm9sYWJzLmNvbSIsImVtYWlsIjoiY3RvQGN1YXRyb2xhYnMuY29tIiwiYXV0aF90aW1lIjoiMDIvMDUvMjAyNiAxMjoyODoyMyIsInRlbmFudF9pZCI6IjEwNDMxODIiLCJkYl9uYW1lIjoibXQtcHJvZC1UZW5hbnRzIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9yb2xlIjoiQURNSU5JU1RSQVRPUiIsImV4cCI6MjUzNDAyMzAwODAwLCJpc3MiOiJDbGFyZV9BSSIsImF1ZCI6IkNsYXJlX0FJIn0.pC-dfN0w2moe87hD7g6Kqk1ocmgYQiEH3hmHwNquKfY'
|
| 49 |
+
|
| 50 |
+
# 2. Deploy
|
| 51 |
+
./deploy-helm.sh auth-ms
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
## Verification
|
| 55 |
+
|
| 56 |
+
### 1. Check Pod Status
|
| 57 |
+
```bash
|
| 58 |
+
kubectl get pods -l app=auth-ms
|
| 59 |
+
kubectl logs -l app=auth-ms --tail=100 | grep WATI
|
| 60 |
+
```
|
| 61 |
+
|
| 62 |
+
### 2. Test OTP Endpoint
|
| 63 |
+
```bash
|
| 64 |
+
curl -X POST http://localhost:7860/customer/send-otp \
|
| 65 |
+
-H "Content-Type: application/json" \
|
| 66 |
+
-d '{
|
| 67 |
+
"mobile": "+919999999999"
|
| 68 |
+
}'
|
| 69 |
+
```
|
| 70 |
+
|
| 71 |
+
**Expected Success Response**:
|
| 72 |
+
```json
|
| 73 |
+
{
|
| 74 |
+
"success": true,
|
| 75 |
+
"message": "OTP sent successfully via WhatsApp"
|
| 76 |
+
}
|
| 77 |
+
```
|
| 78 |
+
|
| 79 |
+
**Expected Error (if still not configured)**:
|
| 80 |
+
```json
|
| 81 |
+
{
|
| 82 |
+
"success": false,
|
| 83 |
+
"message": "WhatsApp OTP service is not configured"
|
| 84 |
+
}
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
### 3. Check Configuration (Inside Pod)
|
| 88 |
+
```bash
|
| 89 |
+
kubectl exec -it <auth-ms-pod> -- python3 check_wati_config.py
|
| 90 |
+
```
|
| 91 |
+
|
| 92 |
+
## Troubleshooting
|
| 93 |
+
|
| 94 |
+
### Error: "WhatsApp OTP service is not configured"
|
| 95 |
+
- β
Environment variable not set in deployment
|
| 96 |
+
- **Fix**: Redeploy with updated `values-auth-ms.yaml`
|
| 97 |
+
|
| 98 |
+
### Error: "Illegal header value b'Bearer '"
|
| 99 |
+
- β
Empty WATI_ACCESS_TOKEN
|
| 100 |
+
- **Fix**: Check secret/configmap has the token
|
| 101 |
+
|
| 102 |
+
### Error: "WATI API request failed with status 401"
|
| 103 |
+
- β Invalid or expired token
|
| 104 |
+
- **Fix**: Get new token from WATI dashboard
|
| 105 |
+
|
| 106 |
+
### Error: "WATI API request failed with status 404"
|
| 107 |
+
- β Wrong API endpoint or template name
|
| 108 |
+
- **Fix**: Verify WATI_API_ENDPOINT and template names
|
| 109 |
+
|
| 110 |
+
## Files Modified
|
| 111 |
+
|
| 112 |
+
1. β
`app/auth/services/wati_service.py` - Error handling
|
| 113 |
+
2. β
`cuatrolabs-deploy/values-auth-ms.yaml` - Deployment config
|
| 114 |
+
3. β
`check_wati_config.py` - Diagnostic tool
|
| 115 |
+
4. β
`test_wati_error_handling.py` - Test script
|
| 116 |
+
|
| 117 |
+
## Next Steps
|
| 118 |
+
|
| 119 |
+
1. **Deploy the fix**: Run `./deploy-helm.sh auth-ms`
|
| 120 |
+
2. **Verify logs**: Check for WATI initialization warnings
|
| 121 |
+
3. **Test OTP**: Send test OTP to verify functionality
|
| 122 |
+
4. **Monitor**: Watch for any WATI-related errors in logs
|
| 123 |
+
|
| 124 |
+
## Support
|
| 125 |
+
|
| 126 |
+
For WATI-related issues:
|
| 127 |
+
- Check logs: `kubectl logs -l app=auth-ms --tail=200 | grep -i wati`
|
| 128 |
+
- Run diagnostics: `kubectl exec -it <pod> -- python3 check_wati_config.py`
|
| 129 |
+
- Review docs: `WATI_INTEGRATION_OVERVIEW.md`
|
app/auth/services/wati_service.py
CHANGED
|
@@ -17,11 +17,21 @@ class WatiService:
|
|
| 17 |
self.access_token = settings.WATI_ACCESS_TOKEN
|
| 18 |
self.template_name = settings.WATI_OTP_TEMPLATE_NAME
|
| 19 |
self.timeout = 30.0 # 30 seconds timeout
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
def _get_headers(self) -> Dict[str, str]:
|
| 22 |
"""Get HTTP headers for WATI API requests."""
|
|
|
|
|
|
|
|
|
|
| 23 |
return {
|
| 24 |
-
"Authorization": f"Bearer {self.access_token}",
|
| 25 |
"Content-Type": "application/json"
|
| 26 |
}
|
| 27 |
|
|
@@ -59,6 +69,11 @@ class WatiService:
|
|
| 59 |
Tuple of (success, message, local_message_id)
|
| 60 |
"""
|
| 61 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 62 |
# Normalize mobile number for WhatsApp
|
| 63 |
whatsapp_number = self._normalize_whatsapp_number(mobile)
|
| 64 |
|
|
|
|
| 17 |
self.access_token = settings.WATI_ACCESS_TOKEN
|
| 18 |
self.template_name = settings.WATI_OTP_TEMPLATE_NAME
|
| 19 |
self.timeout = 30.0 # 30 seconds timeout
|
| 20 |
+
|
| 21 |
+
# Validate configuration on initialization
|
| 22 |
+
if not self.access_token or not self.access_token.strip():
|
| 23 |
+
logger.warning(
|
| 24 |
+
"WATI_ACCESS_TOKEN is not configured or is empty. "
|
| 25 |
+
"WhatsApp OTP functionality will not work."
|
| 26 |
+
)
|
| 27 |
|
| 28 |
def _get_headers(self) -> Dict[str, str]:
|
| 29 |
"""Get HTTP headers for WATI API requests."""
|
| 30 |
+
if not self.access_token or not self.access_token.strip():
|
| 31 |
+
raise ValueError("WATI_ACCESS_TOKEN is not configured or is empty")
|
| 32 |
+
|
| 33 |
return {
|
| 34 |
+
"Authorization": f"Bearer {self.access_token.strip()}",
|
| 35 |
"Content-Type": "application/json"
|
| 36 |
}
|
| 37 |
|
|
|
|
| 69 |
Tuple of (success, message, local_message_id)
|
| 70 |
"""
|
| 71 |
try:
|
| 72 |
+
# Validate configuration before attempting to send
|
| 73 |
+
if not self.access_token or not self.access_token.strip():
|
| 74 |
+
logger.error("WATI_ACCESS_TOKEN is not configured. Cannot send OTP.")
|
| 75 |
+
return False, "WhatsApp OTP service is not configured", None
|
| 76 |
+
|
| 77 |
# Normalize mobile number for WhatsApp
|
| 78 |
whatsapp_number = self._normalize_whatsapp_number(mobile)
|
| 79 |
|
check_wati_config.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Diagnostic script to check WATI configuration.
|
| 4 |
+
"""
|
| 5 |
+
import os
|
| 6 |
+
import sys
|
| 7 |
+
|
| 8 |
+
# Add app directory to path
|
| 9 |
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'app'))
|
| 10 |
+
|
| 11 |
+
from app.core.config import settings
|
| 12 |
+
|
| 13 |
+
print("=" * 60)
|
| 14 |
+
print("WATI Configuration Check")
|
| 15 |
+
print("=" * 60)
|
| 16 |
+
|
| 17 |
+
print(f"\nWATI_API_ENDPOINT: {settings.WATI_API_ENDPOINT}")
|
| 18 |
+
print(f"WATI_ACCESS_TOKEN length: {len(settings.WATI_ACCESS_TOKEN) if settings.WATI_ACCESS_TOKEN else 0}")
|
| 19 |
+
print(f"WATI_ACCESS_TOKEN (first 20 chars): {settings.WATI_ACCESS_TOKEN[:20] if settings.WATI_ACCESS_TOKEN else 'EMPTY'}")
|
| 20 |
+
print(f"WATI_ACCESS_TOKEN (last 20 chars): {settings.WATI_ACCESS_TOKEN[-20:] if settings.WATI_ACCESS_TOKEN else 'EMPTY'}")
|
| 21 |
+
print(f"WATI_OTP_TEMPLATE_NAME: {settings.WATI_OTP_TEMPLATE_NAME}")
|
| 22 |
+
print(f"WATI_STAFF_OTP_TEMPLATE_NAME: {settings.WATI_STAFF_OTP_TEMPLATE_NAME}")
|
| 23 |
+
|
| 24 |
+
print("\n" + "=" * 60)
|
| 25 |
+
print("Environment Variable Check")
|
| 26 |
+
print("=" * 60)
|
| 27 |
+
|
| 28 |
+
wati_token_env = os.getenv("WATI_ACCESS_TOKEN", "NOT_SET")
|
| 29 |
+
print(f"\nWATI_ACCESS_TOKEN from os.getenv: {wati_token_env[:20] if wati_token_env != 'NOT_SET' else 'NOT_SET'}")
|
| 30 |
+
|
| 31 |
+
print("\n" + "=" * 60)
|
| 32 |
+
print("Validation")
|
| 33 |
+
print("=" * 60)
|
| 34 |
+
|
| 35 |
+
if not settings.WATI_ACCESS_TOKEN or not settings.WATI_ACCESS_TOKEN.strip():
|
| 36 |
+
print("\nβ ERROR: WATI_ACCESS_TOKEN is not configured or is empty!")
|
| 37 |
+
print(" This will cause the 'Illegal header value b\"Bearer \"' error.")
|
| 38 |
+
else:
|
| 39 |
+
print("\nβ
WATI_ACCESS_TOKEN is configured correctly")
|
| 40 |
+
|
| 41 |
+
# Test header generation
|
| 42 |
+
test_header = f"Bearer {settings.WATI_ACCESS_TOKEN.strip()}"
|
| 43 |
+
print(f" Test header (first 30 chars): {test_header[:30]}")
|
| 44 |
+
|
| 45 |
+
print("\n" + "=" * 60)
|
test_wati_error_handling.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Test script to verify WATI error handling for missing/empty tokens.
|
| 4 |
+
"""
|
| 5 |
+
import asyncio
|
| 6 |
+
import sys
|
| 7 |
+
import os
|
| 8 |
+
|
| 9 |
+
# Add app directory to path
|
| 10 |
+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'app'))
|
| 11 |
+
|
| 12 |
+
# Mock empty token scenario
|
| 13 |
+
os.environ['WATI_ACCESS_TOKEN'] = ''
|
| 14 |
+
|
| 15 |
+
from app.auth.services.wati_service import WatiService
|
| 16 |
+
|
| 17 |
+
async def test_empty_token_handling():
|
| 18 |
+
"""Test that empty token is handled gracefully."""
|
| 19 |
+
print("=" * 60)
|
| 20 |
+
print("Testing WATI Error Handling with Empty Token")
|
| 21 |
+
print("=" * 60)
|
| 22 |
+
|
| 23 |
+
# Create service with empty token
|
| 24 |
+
service = WatiService()
|
| 25 |
+
|
| 26 |
+
print("\n1. Testing initialization warning...")
|
| 27 |
+
print(" β
Service initialized (should have logged warning)")
|
| 28 |
+
|
| 29 |
+
print("\n2. Testing _get_headers() with empty token...")
|
| 30 |
+
try:
|
| 31 |
+
headers = service._get_headers()
|
| 32 |
+
print(" β FAILED: Should have raised ValueError")
|
| 33 |
+
except ValueError as e:
|
| 34 |
+
print(f" β
PASSED: Raised ValueError: {e}")
|
| 35 |
+
|
| 36 |
+
print("\n3. Testing send_otp_message() with empty token...")
|
| 37 |
+
success, message, msg_id = await service.send_otp_message(
|
| 38 |
+
mobile="+919999999999",
|
| 39 |
+
otp="123456"
|
| 40 |
+
)
|
| 41 |
+
|
| 42 |
+
if not success and "not configured" in message:
|
| 43 |
+
print(f" β
PASSED: Returned error: {message}")
|
| 44 |
+
else:
|
| 45 |
+
print(f" β FAILED: Expected configuration error, got: {message}")
|
| 46 |
+
|
| 47 |
+
print("\n" + "=" * 60)
|
| 48 |
+
print("Test Summary")
|
| 49 |
+
print("=" * 60)
|
| 50 |
+
print("β
All error handling tests passed!")
|
| 51 |
+
print(" - Empty token detected at initialization")
|
| 52 |
+
print(" - _get_headers() raises ValueError")
|
| 53 |
+
print(" - send_otp_message() returns graceful error")
|
| 54 |
+
print("\n" + "=" * 60)
|
| 55 |
+
|
| 56 |
+
if __name__ == "__main__":
|
| 57 |
+
asyncio.run(test_empty_token_handling())
|