The Problem
Your customer logs into the Odoo portal and sees "Access Denied" or "403 Forbidden" when trying to view their sales orders, invoices, or support tickets. Or they can see some documents but not others. Portal access issues frustrate customers and generate support tickets.
Error Messages
# On the portal page:
Access Denied
Sorry, you are not allowed to access this document.
403 Forbidden
# In Odoo logs:
odoo.exceptions.AccessError: You are not allowed to access 'Sales Order' (sale.order) records.
psycopg2.errors.InsufficientPrivilege: permission denied for relation sale_order
AccessError: The requested operation cannot be completed due to security restrictions.Common Causes and Fixes
1. User Not in Portal Group
The most basic cause — the user is not a portal user. They might be an internal user who was changed, or the portal access was never granted.
Fix: Go to Settings > Users > find the user. Under "User Type", select "Portal". Or grant portal access from the contact form: Contacts > find the partner > Action menu > Grant Portal Access.
2. Document Not Linked to Partner
Portal record rules filter documents by the partner (customer). If the order or invoice is not linked to the portal user's partner, they cannot see it.
Fix: Check that the document has the correct partner set:
- Sales Orders:
partner_idmust match the portal user's partner - Invoices:
partner_idmust match - Support tickets:
partner_idmust match
# Check in Odoo shell:
user = env['res.users'].browse(portal_user_id)
partner = user.partner_id
orders = env['sale.order'].sudo().search([('partner_id', '=', partner.id)])
print(f"Partner {partner.name} has {len(orders)} orders")3. Record Rules Blocking Access
Custom record rules or modified default rules can accidentally block portal users.
Debug:
# Check portal record rules:
SELECT name, model_id, domain_force, active
FROM ir_rule
WHERE name LIKE '%portal%'
ORDER BY model_id;Fix: Go to Settings > Technical > Security > Record Rules. Search for "portal" and check:
- Rules are active
- Domain filters are correct
- Rules apply to the "Portal" group
Common issue: a custom rule with a domain like [('user_id','=',user.id)] instead of [('partner_id','=',user.commercial_partner_id.id)]. Portal users may not be the user_id on records.
4. Commercial Partner vs Contact Partner
Odoo uses commercial_partner_id for portal access — this is the top-level company, not individual contacts. If a contact logs in but the invoice is on the parent company, access depends on the record rule using commercial_partner_id.
Fix: Ensure record rules use commercial_partner_id:
# Correct portal rule domain:
[('partner_id', 'child_of', user.commercial_partner_id.id)]
# This allows contacts of a company to see the company's documents5. Access Token Expired or Missing
Some portal documents are shared via access tokens in the URL. If the token is invalid or missing, access fails even for legitimate portal users.
Fix: Regenerate the portal URL:
# In Odoo shell:
order = env['sale.order'].browse(order_id)
order._portal_ensure_token()
url = order.get_portal_url()
print(url) # Send this URL to the customer6. Multi-Company Access Issues
In multi-company setups, portal users may be linked to a partner in Company A but trying to access documents from Company B.
Fix: Check that the partner's company matches the document's company. If the partner should access cross-company documents, ensure the record rules handle this case.
7. Website Module Conflicts
The website module adds its own layer of access control. A portal user might have backend access but not website portal access.
Fix:
- Verify the user has the
base.group_portalgroup - Check website-specific record rules (search for "website" in record rules)
- Ensure the website's portal pages are published and accessible
8. Custom Module Breaking Portal
A custom module that inherits a portal-accessible model and adds a new field with restrictive access can break portal views.
Fix: Check your custom module's security:
ir.model.access.csv— ensure portal group has read access- Record rules — ensure they do not accidentally exclude portal users
- View inheritance — ensure portal views are not broken by your changes
Testing Portal Access
- Create a test portal user
- Grant them portal access from the contact form
- Create a sales order for their partner
- Log in as the portal user (use a private/incognito window)
- Navigate to My Account > Sales Orders
- If it fails, check Odoo logs for the specific AccessError
Quick Fix Checklist
- User is in the Portal group
- Document's partner_id matches the user's partner
- Record rules use commercial_partner_id with child_of
- Access token is present (portal_ensure_token called)
- ir.model.access.csv grants read to portal group
- No custom record rules blocking portal users