Authentication¶
Complete guide to authenticating with the JDX Odoo REST API.
Authentication Methods¶
| Method | Use Case | Token Lifetime |
|---|---|---|
| OAuth2 | External integrations | 1 hour (configurable) |
| API Key | Server-to-server | No expiry |
| Session | PWA / Web browser | Session-based |
OAuth2 Authentication¶
Step 1: Get Access Token¶
curl -X POST "https://{your-erp-domain}/restapi/1.0/common/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
Response:
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600
}
Step 2: Use Access Token¶
curl -X GET "https://{your-erp-domain}/restapi/1.0/object/res.partner" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
JWT Token Format¶
Request JWT format by adding token_format=jwt:
curl -X POST "https://{your-erp-domain}/restapi/1.0/common/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "token_format=jwt"
JWT payload contains:
API Key Authentication¶
Setup in Odoo¶
- Go to Settings → Users & Companies → Users
- Select the API user
- Go to Preferences tab
- Under API Keys, click New API Key
- Enter a description and click Generate Key
- Copy the key (shown only once)
Security
Store API keys securely. Never commit to git or expose in client-side code.
Using API Key¶
Header method (recommended):
curl -X GET "https://{your-erp-domain}/restapi/1.0/object/res.partner" \
-H "X-API-Key: YOUR_API_KEY"
Bearer token method:
curl -X GET "https://{your-erp-domain}/restapi/1.0/object/res.partner" \
-H "Authorization: Bearer YOUR_API_KEY"
Session Authentication¶
Used by the PWA and web interface.
Login¶
curl -X POST "https://{your-erp-domain}/web/session/authenticate" \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{
"jsonrpc": "2.0",
"method": "call",
"params": {
"db": "odoo_production",
"login": "username",
"password": "password"
}
}'
Response:
{
"jsonrpc": "2.0",
"result": {
"uid": 2,
"session_id": "abc123...",
"username": "admin",
"company_id": 1
}
}
Using Session Cookie¶
curl -X GET "https://{your-erp-domain}/web/dataset/call_kw" \
-H "Content-Type: application/json" \
-b cookies.txt \
-d '{
"jsonrpc": "2.0",
"method": "call",
"params": {
"model": "res.partner",
"method": "search_read",
"args": [[["is_company", "=", true]]],
"kwargs": {"fields": ["name", "email"], "limit": 10}
}
}'
Code Examples¶
Python¶
import requests
# OAuth2
def get_oauth_token(base_url, client_id, client_secret):
response = requests.post(
f"{base_url}/restapi/1.0/common/oauth2/token",
data={
"grant_type": "client_credentials",
"client_id": client_id,
"client_secret": client_secret
}
)
return response.json()["access_token"]
# API Key
def get_partners(base_url, api_key):
response = requests.get(
f"{base_url}/restapi/1.0/object/res.partner",
headers={"X-API-Key": api_key},
params={
"domain": "[('is_company','=',True)]",
"fields": "['name','email','phone']",
"limit": 50
}
)
return response.json()
# Usage
base_url = "https://your-erp-domain.com"
api_key = "your_api_key"
partners = get_partners(base_url, api_key)
JavaScript (Node.js)¶
const axios = require('axios');
// OAuth2
async function getOAuthToken(baseUrl, clientId, clientSecret) {
const response = await axios.post(
`${baseUrl}/restapi/1.0/common/oauth2/token`,
new URLSearchParams({
grant_type: 'client_credentials',
client_id: clientId,
client_secret: clientSecret
})
);
return response.data.access_token;
}
// API Key
async function getPartners(baseUrl, apiKey) {
const response = await axios.get(
`${baseUrl}/restapi/1.0/object/res.partner`,
{
headers: { 'X-API-Key': apiKey },
params: {
domain: "[('is_company','=',True)]",
fields: "['name','email','phone']",
limit: 50
}
}
);
return response.data;
}
JavaScript (Browser/PWA)¶
// Session-based authentication
async function login(database, username, password) {
const response = await fetch('/web/session/authenticate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
jsonrpc: '2.0',
method: 'call',
params: { db: database, login: username, password: password }
})
});
return response.json();
}
// Make authenticated request
async function getPartners() {
const response = await fetch('/web/dataset/call_kw', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({
jsonrpc: '2.0',
method: 'call',
params: {
model: 'res.partner',
method: 'search_read',
args: [[['is_company', '=', true]]],
kwargs: { fields: ['name', 'email'], limit: 10 }
}
})
});
return response.json();
}
Token Refresh¶
OAuth2 tokens expire. Refresh before expiry:
curl -X POST "https://{your-erp-domain}/restapi/1.0/common/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=refresh_token" \
-d "refresh_token=YOUR_REFRESH_TOKEN" \
-d "client_id=YOUR_CLIENT_ID" \
-d "client_secret=YOUR_CLIENT_SECRET"
Error Responses¶
| Status | Error | Description |
|---|---|---|
| 401 | invalid_client |
Wrong client_id or client_secret |
| 401 | invalid_token |
Token expired or invalid |
| 401 | invalid_api_key |
API key not found or revoked |
| 403 | access_denied |
User lacks permission |
Error response format:
Security Best Practices¶
- Use HTTPS - Never send credentials over HTTP
- Store keys securely - Use environment variables, not code
- Rotate API keys - Regenerate periodically
- Limit permissions - Create dedicated API users with minimal access
- Monitor usage - Check logs for unusual API activity
Next Steps¶
- OpenAPI Spec - Full API specification
- API Overview - Endpoint summary