{"record":{"id":"1a9c981e12d41e27","repo":"odoo/odoo","slug":"this-page-is-only-accessible-to-s-users","errorCode":null,"errorMessage":"This page is only accessible to %s users.","messagePattern":"This page is only accessible to (.+?) users\\.","errorType":"http","errorClass":"AccessError","httpStatus":403,"severity":"error","filePath":"addons/api_doc/controllers/api_doc.py","lineNumber":41,"sourceCode":"from odoo.http import content_disposition, request\nfrom odoo.modules.module_graph import ModuleGraph\nfrom odoo.service.model import get_public_method\nfrom odoo.tools import hmac, json_default, lazy_classproperty, py_to_js_locale\n\nlogger = logging.getLogger(__name__)\n\n\nclass DocController(http.Controller):\n    \"\"\"\n    A single page application that provides an OpenAPI-like interface\n    feeded by a reflection of the registry (fields and methods) in JSON\n    documents.\n    \"\"\"\n\n    @http.route(['/doc', '/doc/<model_name>', '/doc/index.html'], type='http', auth='user')\n    def doc_client(self, mod=None, **kwargs):\n        if not self.env.user.has_group('api_doc.group_allow_doc'):\n            raise AccessError(self.env._(\n                \"This page is only accessible to %s users.\",\n                self.env.ref('api_doc.group_allow_doc').sudo().name))\n        res = request.render('api_doc.docclient')\n        res.headers['X-Frame-Options'] = 'deny'\n        return res\n\n    @http.route('/doc-bearer/index.json', type='json2', auth='bearer')\n    def doc_bearer_index(self):\n        return self.doc_index()\n\n    @http.route('/doc/index.json', type='json2', auth='user')\n    def doc_index(self):\n        \"\"\"\n        Get a listing of all modules, models, methods and fields. But\n        only their technical name and translated \"human\" name.\n\n        It returns a json-serialized dictionnary with the following\n        structure:","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/odoo/odoo/blob/1e661df964b1b264c9cef3ab28430d4785be3fda/addons/api_doc/controllers/api_doc.py#L23-L59","documentation":"Access gate on the /doc SPA route (api_doc module): the doc client page is only for members of the 'api_doc.group_allow_doc' group. Users outside the group get AccessError naming the group. The route uses auth='user', so it fires for any authenticated but unauthorized user.","triggerScenarios":"Opening /doc, /doc/<model>, or /doc/index.html while the current env.user lacks group 'api_doc.group_allow_doc' (typically only a dedicated 'Documentation' technical group).","commonSituations":"Internal users without the doc group bookmarking /doc; sharing doc links in a team where the group was never assigned; testing on a DB where the group has no members.","solutions":["Add the user to the api_doc.group_allow_doc group (Settings > Users > Access Rights / technical groups)","Or remove/protect the /doc route at the reverse-proxy level if the doc module is installed but unused","Consider uninstalling api_doc on production databases where introspection docs are not needed"],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"if not env.user.has_group('api_doc.group_allow_doc'):\n    raise AccessError('Doc pages restricted')","typeGuard":"def can_view_docs(env) -> bool:\n    return env.user.has_group('api_doc.group_allow_doc')","tryCatchPattern":"try:\n    env['api_doc.controller'].doc_client()\nexcept AccessError:\n    # show login/insufficient-rights page\n    redirect('/')","preventionTips":["Grant the doc group only to developers/integrators","Hide /doc links from users without the group","Consider uninstalling api_doc on production"],"tags":["odoo","api-doc","access-control","http","authorization"],"backgroundTag":null,"analyzedSha":"1e661df964b1b264c9cef3ab28430d4785be3fda","analyzedAt":"2026-08-15T05:22:16.142Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}