Resolve common authentication errors and debug integration issues with LendFoundry APIs
title: "Authentication Troubleshooting"
slug: "authentication-troubleshooting"
excerpt: "Resolve common authentication errors and debug integration issues with LendFoundry APIs"
category: "API Reference"
hidden: false
order: 3
Authentication Troubleshooting
Quick Fixes for Common IssuesThis guide helps you diagnose and resolve authentication errors quickly. Most issues stem from using the wrong authentication method for each system.
Error Quick Reference
%%{init: {'theme': 'base', 'themeVariables': {'background': '#ffffff', 'mainBkg': '#ffffff', 'clusterBkg': '#f9fafb', 'clusterBorder': '#2563eb', 'primaryColor': '#2563eb', 'primaryTextColor': '#ffffff', 'titleColor': '#000000', 'lineColor': '#374151'}, 'flowchart': {'padding': 25, 'nodeSpacing': 45, 'rankSpacing': 60}}}%%
flowchart TB
subgraph DIAG[🔍 Authentication Error Diagnosis]
A[❌ 401 Error] --> B{Which System?}
B -->|LOS| C{Bearer Prefix?}
B -->|LMS| D{Token Expired?}
C -->|Yes| E[❌ Remove Bearer]
C -->|No| F[🔑 Check API Key]
D -->|Yes| G[🔄 Refresh Token]
D -->|No| H[🔑 Check Format]
end
style A fill:#dc2626,stroke:#b91c1c,color:#fff
style B fill:#6b7280,stroke:#4b5563,color:#fff
style C fill:#6b7280,stroke:#4b5563,color:#fff
style D fill:#6b7280,stroke:#4b5563,color:#fff
style E fill:#059669,stroke:#047857,color:#fff
style F fill:#d97706,stroke:#b45309,color:#fff
style G fill:#059669,stroke:#047857,color:#fff
style H fill:#d97706,stroke:#b45309,color:#fff
| HTTP Status | Error Code | System | Common Cause | Solution |
|---|---|---|---|---|
401 | UNAUTHORIZED | Both | Invalid/missing credentials | Verify credentials |
401 | TOKEN_EXPIRED | LMS | JWT token expired | Refresh token |
403 | FORBIDDEN | Both | Insufficient permissions | Contact support |
429 | RATE_LIMIT_EXCEEDED | Both | Too many requests | Implement backoff |
Application Submission APIs (LOS) Issues
Error: 401 Unauthorized
Symptoms:
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or missing API key"
}
}Diagnostic Checklist:
1. Check for Bearer Prefix (Most Common Issue)
# ❌ WRONG - Has "Bearer" prefix
Authorization: Bearer abc123def456
# ✅ CORRECT - No prefix
Authorization: abc123def4562. Verify API Key Format
import os
api_key = os.getenv('LENDFOUNDRY_LOS_API_KEY')
# Check for common issues
if api_key is None:
print("❌ API key not set in environment")
elif api_key.startswith('Bearer '):
print("❌ API key contains 'Bearer ' prefix - remove it")
elif ' ' in api_key:
print("❌ API key contains spaces - check for copy/paste errors")
elif len(api_key) < 10:
print("⚠️ API key seems too short - verify correct key")
else:
print("✅ API key format looks correct")3. Verify Environment
| Environment | Base URL |
|---|---|
| Demo/Sandbox | https://loc.demo.kendra.lendfoundry.com/v1/darbaan |
| Production | Contact support for production URL |
ImportantDemo API keys do not work in production, and vice versa.
4. Test Authentication
curl -v -X POST "https://loc.demo.kendra.lendfoundry.com/v1/darbaan/back-office/rest/api/list-applications" \
-H "Authorization: your-api-key-here" \
-H "Content-Type: application/json" \
-d '{"page": 1, "size": 1}'Expected: 200 OK or 401 Unauthorized with clear error message
Error: 403 Forbidden
Symptoms:
{
"error": {
"code": "FORBIDDEN",
"message": "Insufficient permissions",
"details": "Your API key does not have permission to access this resource"
}
}Causes:
- API key doesn't have required permissions for the endpoint
- Using sandbox credentials with production endpoint
- Organization role restrictions
Solution:
- Contact [email protected] to verify permissions
- Confirm you're using the correct environment credentials
- Check if your organization has access to the requested endpoint
Active Loan Servicing APIs (LMS) Issues
Error: 401 Unauthorized - Token Expired
Symptoms:
{
"error": {
"code": "TOKEN_EXPIRED",
"message": "JWT token has expired",
"details": "Token expired at 2025-12-15T10:30:00Z. Request a new token."
}
}Cause: JWT tokens expire after 1 hour (3600 seconds)
Solution: Implement automatic token refresh with buffer time:
from datetime import datetime, timedelta
import requests
import os
class TokenManager:
"""Manage JWT tokens with automatic refresh."""
def __init__(self):
self.client_id = os.getenv('LENDFOUNDRY_LMS_CLIENT_ID')
self.client_secret = os.getenv('LENDFOUNDRY_LMS_CLIENT_SECRET')
self.base_url = "https://api.demo.lms.lendfoundry.com"
self.token = None
self.expires_at = None
def get_valid_token(self):
"""Get valid token, refreshing if needed."""
# Refresh 5 minutes before expiry
if self.token and self.expires_at:
if datetime.now() < self.expires_at - timedelta(minutes=5):
return self.token
return self._refresh_token()
def _refresh_token(self):
"""Request new token from OAuth endpoint."""
response = requests.post(
f"{self.base_url}/oauth/token",
data={
"grant_type": "client_credentials",
"client_id": self.client_id,
"client_secret": self.client_secret
}
)
response.raise_for_status()
data = response.json()
self.token = data["access_token"]
self.expires_at = datetime.now() + timedelta(seconds=data.get("expires_in", 3600))
return self.token
# Usage - always use get_valid_token() before requests
token_manager = TokenManager()
token = token_manager.get_valid_token()Error: 401 Unauthorized - Invalid Token Format
Symptoms:
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid token format",
"details": "Bearer token is malformed"
}
}Common Mistakes:
| ❌ Wrong | Issue |
|---|---|
Authorization: eyJhbG... | Missing Bearer prefix |
Authorization: Bearer eyJhbG... | Double space after Bearer |
Authorization: bearer eyJhbG... | Lowercase bearer |
Authorization: Bearer abc123 | Using API key instead of JWT |
Correct Format:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...Validation Code:
def validate_token_format(token):
"""Validate JWT token format."""
import jwt
# Check if it looks like a JWT (3 parts separated by dots)
parts = token.split('.')
if len(parts) != 3:
print("❌ Invalid JWT format - should have 3 parts")
return False
# Decode without verification to check structure
try:
decoded = jwt.decode(token, options={"verify_signature": False})
print(f"✅ Valid JWT structure")
print(f" Expires: {datetime.fromtimestamp(decoded.get('exp', 0))}")
return True
except Exception as e:
print(f"❌ Invalid JWT: {e}")
return FalseError: 401 Unauthorized - Invalid Client Credentials
Symptoms:
{
"error": {
"code": "INVALID_CLIENT",
"message": "Invalid client_id or client_secret"
}
}Diagnostic Checklist:
- ✅ Verify
client_idis correct (copy-paste, don't type) - ✅ Verify
client_secretis correct - ✅ Check for leading/trailing whitespace
- ✅ Confirm credentials are for correct environment
- ✅ Check if credentials have been regenerated
import os
client_id = os.getenv('LENDFOUNDRY_LMS_CLIENT_ID')
client_secret = os.getenv('LENDFOUNDRY_LMS_CLIENT_SECRET')
# Remove any accidental whitespace
client_id = client_id.strip() if client_id else None
client_secret = client_secret.strip() if client_secret else None
# Validate
if not client_id:
print("❌ CLIENT_ID not set")
elif not client_secret:
print("❌ CLIENT_SECRET not set")
else:
print(f"✅ Credentials loaded")
print(f" Client ID length: {len(client_id)}")
print(f" Client Secret length: {len(client_secret)}")Common Integration Mistakes
Mistake 1: Using Wrong Authentication Method
Symptom: 401 errors when switching between LOS and LMS
%%{init: {'theme': 'base', 'themeVariables': {'background': '#ffffff', 'mainBkg': '#ffffff', 'clusterBkg': '#f9fafb', 'clusterBorder': '#2563eb', 'primaryColor': '#2563eb', 'primaryTextColor': '#ffffff', 'titleColor': '#000000', 'lineColor': '#374151'}, 'flowchart': {'padding': 25, 'nodeSpacing': 45, 'rankSpacing': 60}}}%%
flowchart LR
subgraph WRONG[❌ Common Mistake]
A1[LOS API Key] --> B1[LMS Endpoint]
B1 --> C1[401 Error]
end
subgraph RIGHT[✅ Correct Approach]
A2[LOS API Key] --> B2[LOS Endpoint]
A3[LMS JWT] --> B3[LMS Endpoint]
B2 --> C2[200 OK]
B3 --> C3[200 OK]
end
style A1 fill:#dc2626,stroke:#b91c1c,color:#fff
style B1 fill:#dc2626,stroke:#b91c1c,color:#fff
style C1 fill:#dc2626,stroke:#b91c1c,color:#fff
style A2 fill:#059669,stroke:#047857,color:#fff
style A3 fill:#059669,stroke:#047857,color:#fff
style B2 fill:#059669,stroke:#047857,color:#fff
style B3 fill:#059669,stroke:#047857,color:#fff
style C2 fill:#059669,stroke:#047857,color:#fff
style C3 fill:#059669,stroke:#047857,color:#fff
Solution: Create separate clients for each system:
class LendFoundryClient:
"""Unified client for LOS and LMS with correct authentication."""
def __init__(self, los_api_key, lms_client_id, lms_client_secret):
self.los_api_key = los_api_key
self.lms_token_manager = TokenManager(lms_client_id, lms_client_secret)
def call_los(self, endpoint, data):
"""Call Application Submission API (LOS)."""
headers = {
"Authorization": self.los_api_key, # No Bearer prefix
"Content-Type": "application/json"
}
return requests.post(
f"https://loc.demo.kendra.lendfoundry.com/v1/darbaan{endpoint}",
json=data,
headers=headers
)
def call_lms(self, endpoint, method="GET", data=None):
"""Call Active Loan Servicing API (LMS)."""
token = self.lms_token_manager.get_valid_token()
headers = {
"Authorization": f"Bearer {token}", # Bearer prefix required
"Content-Type": "application/json"
}
return requests.request(
method,
f"https://api.demo.lms.lendfoundry.com/v1{endpoint}",
json=data,
headers=headers
)Mistake 2: Not Handling Token Expiration
Symptom: Works initially, then starts failing after 1 hour
Solution: Implement middleware that always ensures valid token:
class LMSApiClient:
"""LMS API client with automatic token refresh."""
def __init__(self, client_id, client_secret):
self.token_manager = TokenManager(client_id, client_secret)
def request(self, method, endpoint, **kwargs):
"""Make request with automatic token refresh."""
token = self.token_manager.get_valid_token()
headers = kwargs.pop('headers', {})
headers['Authorization'] = f'Bearer {token}'
headers['Content-Type'] = 'application/json'
response = requests.request(
method,
f"https://api.demo.lms.lendfoundry.com/v1{endpoint}",
headers=headers,
**kwargs
)
# If token expired mid-request, refresh and retry once
if response.status_code == 401:
error_data = response.json()
if error_data.get('error', {}).get('code') == 'TOKEN_EXPIRED':
token = self.token_manager._refresh_token()
headers['Authorization'] = f'Bearer {token}'
response = requests.request(
method,
f"https://api.demo.lms.lendfoundry.com/v1{endpoint}",
headers=headers,
**kwargs
)
return responseMistake 3: Hardcoding Credentials
Risk: Credentials in version control, security exposure
# ❌ NEVER DO THIS
API_KEY = "abc123def456" # Hardcoded credentials
# ✅ USE ENVIRONMENT VARIABLES
import os
API_KEY = os.getenv('LENDFOUNDRY_LOS_API_KEY')
# ✅ OR USE SECRETS MANAGER
import boto3
def get_secret(secret_name):
client = boto3.client('secretsmanager')
response = client.get_secret_value(SecretId=secret_name)
return response['SecretString']
API_KEY = get_secret('lendfoundry/los-api-key')Debugging Tips
Enable Request Logging
import logging
import requests
from http.client import HTTPConnection
# Enable debug logging
logging.basicConfig(level=logging.DEBUG)
HTTPConnection.debuglevel = 1
# Now requests will show full HTTP details
response = requests.post(url, headers=headers, json=data)Decode JWT Token for Debugging
import jwt
from datetime import datetime
def debug_jwt_token(token):
"""Decode and display JWT token information."""
try:
# Decode without verification (for debugging only)
decoded = jwt.decode(token, options={"verify_signature": False})
print("=== JWT Token Debug ===")
print(f"Subject: {decoded.get('sub', 'N/A')}")
print(f"Issued At: {datetime.fromtimestamp(decoded.get('iat', 0))}")
print(f"Expires At: {datetime.fromtimestamp(decoded.get('exp', 0))}")
now = datetime.now()
exp = datetime.fromtimestamp(decoded.get('exp', 0))
if now > exp:
print(f"⚠️ TOKEN EXPIRED {now - exp} ago")
else:
print(f"✅ Token valid for {exp - now}")
return decoded
except Exception as e:
print(f"❌ Failed to decode token: {e}")
return None
# Usage
debug_jwt_token(your_jwt_token)cURL Verbose Mode
curl -v -X POST "https://loc.demo.kendra.lendfoundry.com/v1/darbaan/back-office/rest/api/list-applications" \
-H "Authorization: your-api-key" \
-H "Content-Type: application/json" \
-d '{"page": 1, "size": 1}'The -v flag shows:
- Request headers sent
- Response headers received
- Connection details
- SSL/TLS information
Getting Help
Before Contacting Support
- ✅ Review this troubleshooting guide
- ✅ Verify credentials are correct (copy-paste, no typos)
- ✅ Test with cURL to isolate code issues
- ✅ Check error response body for details
- ✅ Confirm using correct environment (sandbox vs production)
When Contacting Support
Provide:
| Information | Example |
|---|---|
| Error message | Full JSON response |
| HTTP status code | 401, 403, etc. |
| Endpoint | /back-office/rest/api/list-applications |
| Environment | Sandbox / Production |
| System | LOS or LMS |
| Code snippet | Sanitized (no credentials!) |
Contact:
- Email: [email protected]
- Subject: "Authentication Issue - [LOS/LMS] - [Brief Description]"
Next Steps
| Resource | Description |
|---|---|
| Authentication | Authentication setup guide |
| API Integration Flow | Complete integration workflow |
| Error Codes | Full error code reference |
Issue Resolved?Head to the API Integration Flow to continue your integration.
