API Key Authentication Failures
When using Odoo API keys for external integrations, you encounter:
Authentication failed: Invalid API key.
xmlrpc.client.Fault: Access Denied
HTTP 401: Unauthorized — The API key provided is not valid.
jsonrpc error: {"message": "Session expired"}
AccessError: API key does not have sufficient permissions.Understanding Odoo API Keys
Odoo API keys (introduced in Odoo 14+) replace passwords for API authentication. They are:
- Generated per user in Settings > Users > API Keys
- Used in place of the user's password in XML-RPC and JSON-RPC calls
- Scoped to the user's permissions — no additional access beyond the user's groups
- Revocable without changing the user's login password
Fix 1: Generate a Valid API Key
# Step 1: Log in to Odoo as the user needing API access
# Step 2: Go to Settings (gear icon) > My Profile > Account Security tab
# Step 3: Click "New API Key"
# Step 4: Enter a description (e.g., "Integration with App X")
# Step 5: COPY THE KEY IMMEDIATELY — it's shown only once!
# The key looks like: 3f5a8b2c-1234-5678-90ab-cdef12345678
# IMPORTANT:
# - The key is shown only once during creation
# - If lost, delete and create a new one
# - Store securely (environment variables, not in code)Fix 2: Using API Key with XML-RPC
import xmlrpc.client
url = 'https://odoo.example.com'
db = 'mydb'
username = 'admin' # User's login email
api_key = '3f5a8b2c-1234-5678-90ab-cdef12345678' # NOT the password
# Authenticate with API key instead of password
common = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/common')
uid = common.authenticate(db, username, api_key, {})
if not uid:
print("Authentication failed - check username and API key")
else:
# Use API key (not password) for all subsequent calls
models = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/object')
partners = models.execute_kw(
db, uid, api_key, # API key goes here, not password
'res.partner', 'search_read',
[[]], {'fields': ['name', 'email'], 'limit': 5}
)
print(partners)Fix 3: API Key with JSON-RPC
# Authenticate via JSON-RPC:
fetch('https://odoo.example.com/web/session/authenticate', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
jsonrpc: '2.0',
params: {
db: 'mydb',
login: 'admin',
password: 'YOUR_API_KEY', // API key as password
}
})
});
// Save the session cookie for subsequent requests
// The session remains valid until it expiresFix 4: Common Authentication Errors
# Error: Access Denied
# Causes:
# 1. Wrong database name
# 2. Wrong username (must be the login, usually email)
# 3. API key was revoked or deleted
# 4. User account is deactivated
# 5. Two-factor authentication is enabled but not handled
# Debug checklist:
# 1. Verify database name:
sudo -u postgres psql -l | grep mydb
# 2. Verify user exists and is active:
sudo -u postgres psql -d mydb -c "
SELECT ru.login, ru.active, rp.name
FROM res_users ru
JOIN res_partner rp ON ru.partner_id = rp.id
WHERE ru.login = 'admin';
"
# 3. Verify API key exists:
sudo -u postgres psql -d mydb -c "
SELECT ak.name, ak.scope, ak.user_id, ru.login
FROM auth_api_key ak
JOIN res_users ru ON ak.user_id = ru.id
WHERE ru.login = 'admin';
"
# Note: the actual key value is hashed and cannot be retrievedFix 5: Two-Factor Authentication (2FA) Blocking
# If the user has 2FA enabled:
# API key authentication bypasses 2FA (by design)
# But some custom 2FA modules may block API keys
# If 2FA is blocking API access:
# Option 1: Create a dedicated service user without 2FA
# Option 2: Use API keys (should bypass standard 2FA)
# Option 3: Check custom security modules that may intercept authFix 6: API Key Scope and Permissions
# API keys inherit the user's permissions
# The key cannot do more than the user can do via the UI
# If getting AccessError:
# The user doesn't have permission for the requested operation
# Fix: Check user groups:
# Settings > Users > select user
# Verify the user has the appropriate groups:
# - Sales / User for sale.order access
# - Accounting / Invoicing for account.move access
# - Inventory / User for stock.picking access
# Create a dedicated API user with appropriate permissions:
# Settings > Users > Create
# Name: "API Integration User"
# Groups: only the specific groups needed
# Generate API key for this dedicated userFix 7: Rate Limiting and IP Restrictions
# If authentication fails intermittently:
# Odoo may have rate limiting or IP-based blocking
# Check for failed login lockout:
sudo -u postgres psql -d mydb -c "
SELECT login, COUNT(*) as attempts
FROM res_users_log
WHERE create_date > NOW() - INTERVAL '1 hour'
GROUP BY login;
"
# If using a reverse proxy, ensure X-Real-IP is forwarded
# So Odoo sees the correct client IP for rate limiting
# Check odoo.conf for any custom auth restrictionsPrevention
DeployMonkey manages API key lifecycle, including generation, rotation, and permission auditing. The AI agent validates API authentication configurations and detects failed authentication patterns proactively.