Odoo LDAP & OAuth Authentication and the API
How Odoo LDAP and OAuth authentication change API access — why SSO login backends break password-based calls, and why API keys are the transport-independent fix for integrations.
ODXProxy Team · Jul 12, 2026 · 8 min read

Once an Odoo deployment grows past a handful of users, someone wires the login to a central identity provider — LDAP/Active Directory or an OAuth/OpenID provider like Google, Microsoft Entra, or Okta. It's the right move for humans. But it quietly changes the rules for your integrations, and teams usually discover this when a script that authenticated fine last week starts failing with an access error. This guide explains what Odoo LDAP and OAuth authentication actually do to programmatic access, why they break password-based API calls, and why API keys are the correct, login-backend-independent fix that keeps your integrations running.
What LDAP and OAuth change about login
Both are alternative authentication backends: instead of Odoo checking a password stored in its own
res.users table, it delegates the identity check somewhere else.
- LDAP (the
auth_ldapmodule) points Odoo at an LDAP/Active Directory server. When a user logs in, Odoo binds to the directory to verify the credentials. Users can be auto-created on first login, and their password lives in the directory, not in Odoo. - OAuth / OpenID Connect (the
auth_oauthmodule) replaces the password prompt with a "Sign in with Google/Microsoft/…" redirect. Odoo never sees a password at all — it trusts a token the provider issues after the user authenticates there.
In both cases the human web login now runs through an external system. That's exactly what you want for people. The problem is what it does to machines.
Why SSO breaks password-based API access
Historically, some integrations authenticated to Odoo by sending a username and password — the classic
common/authenticate call. The instant an SSO backend is in play, that stops being viable:
- With OAuth, there is often no Odoo-local password to send. The user's real credential lives at Google/Microsoft and is exchanged through an interactive browser redirect a script can't perform.
- With LDAP, a password may exist in the directory, but putting a user's directory password into an integration is a security anti-pattern — it's the same credential that unlocks email, VPN, and everything else, and it rotates on the directory's schedule, breaking your job whenever it changes.
So the pattern that "used to work" — a service account with a password baked into a script — is precisely the thing SSO is designed to eliminate. Trying to preserve it means either weakening the SSO setup or storing a high-value human credential in your automation. Neither is acceptable.
Why API keys are the correct fix
Odoo's API keys (Odoo 14 and later) sit beside the login backend rather than inside it. An API key is a per-user secret, generated in Odoo, that replaces the password for API calls only. Crucially, it is validated by Odoo itself against its own key store — it does not round-trip to LDAP or the OAuth provider. That's what makes it the right tool:
- It works no matter which login backend a human uses. LDAP, OAuth, plain password, 2FA on top — none of it touches the key path.
- It's scoped to one user and revocable independently. Delete the key in Odoo and the integration is cut off, with zero impact on the person's SSO login.
- It decouples your automation from the directory. Rotating a user's LDAP/OAuth credential doesn't break the key; rotating the key doesn't touch their SSO.
So the clean architecture is: humans authenticate through LDAP/OAuth (plus a second factor); machines authenticate with API keys. The two never collide. (The same reasoning applies to two-factor auth — see Odoo 2FA and the API — because 2FA is another thing that lives on the interactive login path and an API key sidesteps.)
Generating a key for an SSO-backed instance
Even when your instance authenticates humans through LDAP or OAuth, API keys are generated the same way, on the user the integration will act as:
- Log in to the Odoo web client as that user (through whatever SSO the instance uses).
- Open your avatar → My Profile → Account Security.
- Under API Keys, click New API Key, name it (e.g.
nightly-sync), and copy the value — you see it once.
You'll also need the user's numeric user id (uid): with developer mode on, open the user record and
read the id from the URL (.../web#id=2&model=res.users).
A practical note for pure-OAuth setups: an SSO user may have no usable Odoo password, which can make it awkward to reach the profile screen to create the key. Two common paths are to have an administrator generate a key on the service user's behalf, or to provision a dedicated local integration user (outside the OAuth flow) specifically for automation. Either way, the goal is the same — a key'd service identity, never a human's SSO credential in a script.
Making the call — identical regardless of login backend
Once you hold an API key, the call is exactly the same as on any other Odoo instance; the login backend
is invisible to it. Through ODXProxy — a reverse proxy in front of one or more Odoo instances — the
request goes to POST /api/odoo/execute, authenticated at the gateway with the x-api-key header and at
Odoo with the user's API key inside the body:
curl -X POST https://your-proxy.example.com/api/odoo/execute \
-H "Content-Type: application/json" \
-H "x-api-key: $ODX_PROXY_KEY" \
-d '{
"id": "sso-call-1",
"action": "search_read",
"model_id": "res.users",
"params": [[["id", "=", 2]]],
"keyword": { "fields": ["name", "login"], "limit": 1 },
"odoo_instance": {
"url": "https://erp.example.com",
"db": "prod",
"user_id": 2,
"api_key": "<the Odoo user API key>"
}
}'There are two different secrets in that request, and conflating them is the most common source of a
mysterious 401:
x-api-key— the proxy's key, an HTTP header that authenticates your app to the gateway.odoo_instance.api_key— the Odoo user's API key, sent in the body to authenticate the ERP call. This is the credential that stands in for the password the SSO backend no longer gives you.
On success you get HTTP 200 and a JSON-RPC envelope with the data in result:
{
"jsonrpc": "2.0",
"id": "sso-call-1",
"result": [
{ "id": 2, "name": "Integration Bot", "login": "svc-integration" }
]
}Reading the failure when auth is wrong
When a call won't authenticate, the layer of the failure tells you where to look. Odoo speaks JSON-RPC 2.0
(not REST), and a rejected ERP call often still returns HTTP 200, so check in order:
- HTTP
401, code-32000— the proxyx-api-keyis missing or wrong. Nothing to do with LDAP, OAuth, or Odoo; fix the gateway header. - HTTP
200with anerrorobject — Odoo itself rejected the call. An invalid, revoked, or wrong-user API key shows up here:
{
"jsonrpc": "2.0",
"id": "sso-call-1",
"error": {
"code": 200,
"message": "Access Denied",
"data": { "name": "odoo.exceptions.AccessDenied" }
}
}An AccessDenied on a key'd call almost always means the key is wrong, revoked, or belongs to a different
user than the user_id you sent — not that LDAP or OAuth is blocking you. API keys don't consult the
SSO backend at all, so if you're using a key correctly the login provider is simply out of the picture. If
you're still seeing a password/redirect-style rejection, some caller is falling back to a password-login
path; switch it to the key.
error.code of 200 here is Odoo's own server-side code, not the HTTP status. Always check the HTTP status first, then check the body's error field even on a 200. The full two-layer model is in Odoo API error handling.A checklist for API access on an SSO instance
- Let LDAP/OAuth own human login — that's what it's for; don't fight it.
- Never put a directory or OAuth credential in a script. Those are human, high-value, and rotate on someone else's schedule.
- Give every integration a dedicated key'd service user with least-privilege access.
- Generate an API key for that user (admin can do it on their behalf if the account has no local password).
- Store keys in a secrets manager; they're shown once and inherit the owner's full permissions.
- Rotate keys on a schedule and immediately if one leaks — deleting the key in Odoo revokes it at once, independent of the SSO account.
- Keep the two keys straight — the proxy
x-api-keyand the Odoo user'sapi_keyare different secrets.
ODXProxy is early (v0.1.0), so treat anything beyond its nine shipped actions as roadmap. The API-key auth flow described here, though, is stable across recent Odoo releases and independent of whichever login backend a deployment uses.
Where to go next
- Start with the fundamentals in how to authenticate to the Odoo API.
- See the closely related case in Odoo two-factor authentication and the API.
- Verify connectivity before credentials with the Odoo API connection quickstart.
- Read the full request/response contract in the API reference, or let the Python SDK wrap the envelope and error checks for you.