← Back to blog

The definitive guide to access rights in Odoo

How Odoo access rights really work, from the screen you click to the database behind it: groups, the new Odoo 19 privileges, record rules, field access, User Roles and API or AI access. Every field name is verified against a live Odoo 19.

Someone on your team opens Odoo and gets 'Access Denied'. Or they cannot find a menu that a colleague uses every day. It feels like a bug, but it almost never is. It is Odoo's permission system doing exactly what it was told.

The catch is that the screen you use to hand out access hides most of what is really going on. You pick a value from a dropdown, and Odoo quietly rewrites a web of groups, rules and filters underneath. Once you can see that web, access rights stop being guesswork. This guide walks the whole path, from the screen you click to the tables behind it, for standard Odoo, the new privilege model in Odoo 19, the optional User Roles add-on, and API and AI access. Every id and field name below is checked against a live Odoo 19 database, so nothing here is invented.

Odoo Access Rights Schema.excalidraw

The short version

  • Odoo checks four layers, in order: groups, then access rights, then record rules, then field access. One 'no' stops the action.
  • The user screen only ever sets one thing: which groups the user is in. Everything else hangs off those groups.
  • The per-app dropdowns are 'privileges', a new model in Odoo 19. A privilege is just the dropdown. The real permissions live on the groups inside it.
  • User Roles (reusable roles) is an optional add-on, not standard Odoo.
  • An API key or AI login runs as a user, so it obeys the exact same four layers.

The four layers

For every single action, read a record, edit it, delete it, Odoo runs four checks in order. If any check says no, the action stops and the user sees an error.

  1. Groups (res.groups): which groups is this user in? This is the only thing you set on the user screen.
  2. Access rights (ir.model.access): may those groups touch this type of record at all? Read, write, create, delete.
  3. Record rules (ir.rule): which specific records inside that type? A filter, for example 'only your own orders'.
  4. Field access (the groups attribute on a field): which fields on the record are visible or editable?

One rule ties the whole thing together and trips up almost everyone: permissions only add up. You cannot take a right away by giving someone an extra group. If a user can see too much, remove a group, never add a restricting one.

The screen you actually use

Open a user under Settings, Users, and go to the Access Rights tab. You will see a Role choice at the top, then grey headers like Sales and Accounting, each with a dropdown.

Odoo user form, Access Rights tab, with the Sales dropdown open showing No, User Own Documents Only, User All Documents and Administrator

Here is the part that clears up most of the confusion. Everything on this screen does one thing: it decides which groups the user belongs to. The Role choice, every dropdown, every checkbox further down, they all write to a single place, the user's list of groups. None of them is a separate setting with its own column in the database.

So this screen is layer 1, and only layer 1. Layers 2, 3 and 4 are never shown here. They come attached to the groups you pick, and they were set up long ago by Odoo and by each app. You only find them if you turn on developer mode and open the technical settings.

What 'Role: User / Administrator' really does

The Role choice is the user's base type. In the database it is the field res.users.role, a plain dropdown with two options, User and Administrator, and it stores nothing of its own (Odoo computes it on the fly). Picking a value just adds the user to one base group: User adds the group Role / User, Administrator adds the group Role / Administrator.

The word Administrator is misleading, so be precise about it. It means 'may open Settings and configure the apps'. It does not mean 'manager of every app'. Whether someone can see all sales orders or every project is decided lower down, in the per-app dropdowns. In our test database, the Administrator base group quietly pulls in a bundle of technical groups and is wired to 127 access-right records for configuration models. None of those touch business data like orders or invoices.

Privileges: the per-app dropdowns (new in Odoo 19)

Each grey section holds one or more dropdowns, like Sales or Project. In Odoo 19, one of those dropdowns is a privilege, stored in a new model, res.groups.privilege.

The Odoo Privileges list, grouped by category, with Sales expanded to show its three groups

Read a privilege as a question with a fixed list of answers. Take Sales:

The Sales privilege form showing Sequence, Category, Placeholder and the Groups tab with the three ranked groups

  • The name is 'Sales', the label next to the dropdown.
  • The category points to the grey header, stored as ir.module.category.
  • The groups are the options inside: User: Own Documents Only, User: All Documents, Administrator.
  • The placeholder is the empty option, usually 'No'.

So the screen has three levels, not two. The grey header is a category. Under it sit one or more privileges (the dropdowns). Inside each privilege sit the groups (the options). Category contains privileges, a privilege contains groups.

Why is Sales a single dropdown instead of three checkboxes? Because the options are ranked and mutually exclusive. Administrator already includes All Documents, which already includes Own Documents. You are picking a level on a ladder, not ticking independent boxes.

What you pick is a group, not the privilege

This answers a question that trips up a lot of people: if the dropdown is a privilege, why is the privilege not linked to the user?

Because the thing you actually choose is one option, and every option is a group. Only the group is stored on the user. The privilege is just the packaging. If Odoo saved 'this user has the Sales privilege', it would not know whether that meant Own, All or Administrator, and the privilege carries no permissions of its own anyway. So the user links to the specific group (the answer), never to the privilege (the question).

Inside a group: the hub of the system

A group is where everything meets. On its own it grants nothing. It is an anchor that the real rules point at. Open a group in developer mode (Settings, Users and Companies, Groups) and the tabs tell the story.

Access rights: what the group may do

The Access Rights tab lists one row per type of record, with four checkboxes: read, write, create, delete. This is layer 2.

If a group has no row that grants at least read on a model, its members cannot open that model at all. This is the most common cause of 'Access Denied' for a new user: they are simply missing the group that carries the access.

Inherited: implied, implying and disjoint

The Inherited tab is where the ranking and the exclusivity live. It has three lists, and all three point back at other groups.

A group, Inherited tab, showing Implied Groups Role User, Implying Groups Sales User All Documents, and empty Disjoint Groups

  • Implied Groups are the groups this one hands out for free. Give someone this group and they get all the implied ones too. This is what makes Administrator pull in a bundle, and what makes a dropdown a ladder where higher includes lower.
  • Implying Groups are the reverse view: the groups that include this one. It is the same link read the other way. For Own Documents, the implying group is All Documents, because All sits above Own.
  • Disjoint Groups are the groups you cannot hold at the same time. When Odoo sees a set of ranked, disjoint groups, it shows them as one dropdown rather than separate checkboxes. That is why Sales is a single selector.

Record rules: which records

The Record Rules tab narrows access from 'this whole model' down to specific rows, using a domain filter. This is layer 3.

A group, Record Rules tab, with rules like Personal Orders and their domains

For the Own Documents salesperson, the rules read like [('salesman_id', '=', user.id)], which means 'only records where you are the salesperson'. Their manager sits in a group with a wider rule and sees everything.

The same thing, seen from the model

You can read layers 2 and 3 from the other end too, starting at the record type instead of the group. In developer mode, open a model under Settings, Technical, Models, for example Contact (res.partner).

Access rights per model

The Access Rights tab on the model shows the same rows, now grouped by the group they belong to. This view answers 'who can edit a contact?' rather than 'what can this group do?'

Field access: which fields

The Fields tab is layer 4. Every field can be limited to certain groups, so it is hidden or read-only for everyone else.

The Contact model, Fields tab, listing its fields

This is how Odoo keeps a cost price or a salary field out of sight for most people while a manager still sees it. Same record, a few lines blacked out.

Record rules: global versus group

The Record Rules tab on the model shows a difference that matters a lot.

The Contact model, Record Rules tab, a global company rule plus a portal rule attached to groups

  • A global rule has no group attached. It applies to everyone and cannot be loosened by any other rule. The classic example is the multi-company rule, [('company_id', 'in', company_ids + [False])], which keeps each company's records apart no matter how senior you are.
  • A group rule is attached to one or more groups and widens what those groups can reach, but only within the global boundary.

In plain terms, global rules draw the outer fence that nobody climbs, and group rules hand out access inside it. In logic terms, global rules stack with AND, group rules combine with OR.

For developers: why the dropdown is not a database column

If you go looking for a sales or project column on res.users, you will not find one. The Role choice and every per-app dropdown are reified fields. They have no column. When the form loads, Odoo works out the current value by checking which groups the user is in, and when you save, it writes the right group into the user's group list.

  • role is a hand-written selection field (module base, not stored).
  • The per-app dropdowns are generated at runtime, named like sel_groups_<ids>, and a standalone checkbox is in_group_<id>. Neither is registered in ir.model.fields, which is why searching for them there comes up empty.
  • The only thing actually stored is the many-to-many res.users.groups_id, physically the table res_groups_users_rel(uid, gid).

So the mental model is short: the widgets on the user screen are a friendly front end over one list of groups. The power of each group lives elsewhere, in ir.model.access, ir.rule, the field groups attribute, and the group's own implied groups.

User Roles: the optional add-on

Standard Odoo makes you set access per person. For three people that is fine. For thirty, with turnover, it drifts, and nobody remembers why someone has what.

The OCA add-on base_user_role fixes that. You define a role once as a bundle of groups, then assign the role to people. Change the role, and everyone with it updates at once. You can switch a role on or off by date, which is handy for temporary access.

Two things to be clear about. First, this is not standard Odoo. The role list only exists if you install the module, and it should not be confused with the simple User / Administrator choice, which is standard. Second, under the hood a role bundles its groups through an implied_ids field, and people are linked to roles through a small join record, res.users.role.line, which can carry a from and to date. It is the same implied-groups idea, reused one level up.

Access rights, API keys and AI

This is where it pays off for anyone connecting Odoo to an API or an AI assistant.

An API key grants no permissions of its own. It only says 'I am this user'. A call made with the key runs as that user and goes through the exact same four layers. Want to know what a key is allowed to do? Look at the groups of the user behind it, exactly as you would for a person.

The key lives in res.users.apikeys. Each key belongs to one user (user_id), has a scope and an expiration_date, and its secret is stored hashed, so you can never read it back after creating it. A governance add-on can attach a limited role to a key so it does less than the full user, something standard Odoo cannot do. The practical takeaway: to control what the assistant may do, adjust the user's groups or role in Odoo, the same way you would onboard a careful new colleague.

When to use what

  • A small, stable team: the standard user screen is enough.
  • Several people in the same job, a growing team, or audit and compliance needs: use User Roles so roles are reusable and easy to review.
  • Giving an AI or API access: pair a scoped role with a limited API key, and keep the underlying user tight.

FAQ

What is the difference between a group and a role in Odoo?
A group is the built-in unit that actually carries permissions. A role in the everyday sense is either the simple User / Administrator base type, or, if you install the OCA add-on, a reusable bundle of groups you can hand to many users.

Access rights versus record rules?
Access rights decide what you can do to a whole type of record (read, write, create, delete). Record rules decide which specific records you can do it to, using a filter.

What is a privilege in Odoo 19?
It is one per-app dropdown on the user form, a named set of ranked options. It organizes the screen, it does not grant anything by itself. The permissions sit on the groups inside it.

Can I remove a permission by adding a group?
No. Permissions only add up. To reduce access, remove a group, do not add one.

Do I need the OCA User Roles module?
Only if managing access per person has become a chore, or you need reusable, auditable roles. Small teams are fine without it.

How do access rights affect an AI or MCP connection?
The connection logs in as a user through an API key and obeys the same four layers. Fix access by adjusting that user's groups or role.

Reference: which field controls what

What you see Model Field What it controls
Whole Access Rights tab res.users groups_id (m2m to res.groups) which groups the user is in
Role: User / Administrator res.users role (selection, not stored) base group User or Administrator
Per-app dropdown res.users sel_groups_<ids> (runtime) membership in that app group
Extra Rights checkbox res.users in_group_<id> (runtime) one group on or off
Grey header and grouping res.groups privilege_id to res.groups.privilege (has category_id to ir.module.category) screen layout (Odoo 19)
Ranking in a dropdown res.groups implied_ids which groups come along
What a group may do ir.model.access group_id, model_id, perm_read/write/create/unlink CRUD per model
Which records ir.rule groups, model_id, domain_force, global row filter
Which fields ir.model.fields groups field visible or editable
The protected thing ir.model model (for example project.task) target of the rights
An API key res.users.apikeys user_id, scope, expiration_date authenticates as a user