{"record":{"id":"ee204b57a5b0eddf","repo":"Dolibarr/dolibarr","slug":"access-to-a-page-that-needs-a-token-constant-csrfcheck-with","errorCode":null,"errorMessage":"Access to a page that needs a token (constant CSRFCHECK_WITH_TOKEN is defined) is refused by CSRF protection in main.inc.php. Token not provided.","messagePattern":"Access to a page that needs a token \\(constant CSRFCHECK_WITH_TOKEN is defined\\) is refused by CSRF protection in main\\.inc\\.php\\. Token not provided\\.","errorType":"http","errorClass":null,"httpStatus":403,"severity":"error","filePath":"htdocs/main.inc.php","lineNumber":440,"sourceCode":"\tif (\n\t\t(!empty($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'POST') ||\n\t\t$sensitiveget ||\n\t\tGETPOSTISSET('massaction') ||\n\t\t((GETPOSTISSET('actionlogin') || GETPOSTISSET('action')) && defined('CSRFCHECK_WITH_TOKEN'))\n\t) {\n\t\t// If token is not provided or empty, error (we are in case it is mandatory)\n\t\tif (!GETPOST('token', 'alpha') || GETPOST('token', 'alpha') == 'notrequired') {\n\t\t\ttop_httphead();\n\t\t\tif (GETPOSTINT('uploadform')) {\n\t\t\t\tdol_syslog(\"--- Access to \".(empty($_SERVER[\"REQUEST_METHOD\"]) ? '' : $_SERVER[\"REQUEST_METHOD\"].' ').$_SERVER[\"PHP_SELF\"].\" refused. File size too large or not provided.\");\n\t\t\t\t$langs->loadLangs(array(\"errors\", \"install\"));\n\t\t\t\tprint $langs->trans(\"ErrorFileSizeTooLarge\").' ';\n\t\t\t\tprint $langs->trans(\"ErrorGoBackAndCorrectParameters\");\n\t\t\t} else {\n\t\t\t\thttp_response_code(403);\n\t\t\t\tif (defined('CSRFCHECK_WITH_TOKEN')) {\n\t\t\t\t\tdol_syslog(\"--- Access to \".(empty($_SERVER[\"REQUEST_METHOD\"]) ? '' : $_SERVER[\"REQUEST_METHOD\"].' ').$_SERVER[\"PHP_SELF\"].\" refused by CSRF protection (CSRFCHECK_WITH_TOKEN protection) in main.inc.php. Token not provided.\", LOG_WARNING);\n\t\t\t\t\tprint \"Access to a page that needs a token (constant CSRFCHECK_WITH_TOKEN is defined) is refused by CSRF protection in main.inc.php. Token not provided.\\n\";\n\t\t\t\t} else {\n\t\t\t\t\tdol_syslog(\"--- Access to \".(empty($_SERVER[\"REQUEST_METHOD\"]) ? '' : $_SERVER[\"REQUEST_METHOD\"].' ').$_SERVER[\"PHP_SELF\"].\" refused by CSRF protection (POST method or GET with a sensible value for 'action' parameter) in main.inc.php. Token not provided.\", LOG_WARNING);\n\t\t\t\t\tprint \"Access to this page this way (POST method or GET with a sensible value for 'action' parameter) is refused by CSRF protection in main.inc.php. Token not provided.\\n\";\n\t\t\t\t\tprint \"If you access your server behind a proxy using url rewriting and the parameter is provided by caller, you might check that all HTTP header are propagated (or add the line \\$dolibarr_nocsrfcheck=1 into your conf.php file or MAIN_SECURITY_CSRF_WITH_TOKEN to 0\";\n\t\t\t\t\tif (getDolGlobalString('MAIN_SECURITY_CSRF_WITH_TOKEN')) {\n\t\t\t\t\t\tprint \" instead of \" . getDolGlobalString('MAIN_SECURITY_CSRF_WITH_TOKEN');\n\t\t\t\t\t}\n\t\t\t\t\tprint \" into setup).\\n\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tdie;\n\t\t}\n\t}\n\n\t$sessiontokenforthisurl = (empty($_SESSION['token']) ? '' : $_SESSION['token']);\n\t// TODO Get the sessiontokenforthisurl into an array of session token (one array per base URL so we can use the CSRF per page and we keep ability for several tabs per url in a browser)\n\tif (GETPOSTISSET('token') && GETPOST('token') != 'notrequired' && GETPOST('token', 'alpha') != $sessiontokenforthisurl) {\n\t\tdol_syslog(\"--- Access to \".(empty($_SERVER[\"REQUEST_METHOD\"]) ? '' : $_SERVER[\"REQUEST_METHOD\"].' ').$_SERVER[\"PHP_SELF\"].\" refused by CSRF protection (invalid token), so we disable POST and some GET parameters - referrer=\".(empty($_SERVER['HTTP_REFERER']) ? '' : $_SERVER['HTTP_REFERER']).\", action=\".GETPOST('action', 'aZ09').\", _GET|POST['token']=\".GETPOST('token', 'alpha'), LOG_WARNING);","sourceCodeStart":422,"sourceCodeEnd":458,"githubUrl":"https://github.com/Dolibarr/dolibarr/blob/598aa4bdada683d17ca04b1842548821ff0eb6c6/htdocs/main.inc.php#L422-L458","documentation":"Dolibarr's CSRF protection refuses requests without a valid token. This variant fires when the target page declares CSRFCHECK_WITH_TOKEN, meaning it unconditionally demands a token; since none was supplied, access is refused with HTTP 403.","triggerScenarios":"GET/POST to a page whose code has define('CSRFCHECK_WITH_TOKEN', 1) (or called via GETPOST check with the constant) without the 'token' URL/POST parameter or with an invalid/absent session token.","commonSituations":"Building links to action pages by hand instead of via dolBuildUrl/Form helpers; token lost when copying a URL into an email/bookmark (token bound to session and expired); proxies or HTML sanitizers stripping the token parameter; custom module pages missing newToken().","solutions":["Generate links/forms with the token: use $form->showFormConfirm, newToken() or append '?token='.newToken() to the URL","Re-open the page from within the Dolibarr UI so a fresh session token is issued","If a page wrongly declares CSRFCHECK_WITH_TOKEN, remove that define from your custom page","Check that proxies don't strip query parameters"],"exampleFix":"// before\nheader('Location: ./card.php?action=confirm&id=15');\n// after\nheader('Location: ./card.php?action=confirm&id=15&token='.newToken());","handlingStrategy":"fallback","validationCode":"if (empty($_REQUEST['token'])) { die('CSRF token missing: regenerate the link via the UI'); }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never hand-craft URLs to token-protected pages; use newToken()/form helpers","Tokens are session-bound: re-open pages from the UI after re-login","For programmatic access, prefer the REST API with an API token","Check bookmarks/emails don't carry stale tokens"],"tags":["csrf","dolibarr","security","token"],"backgroundTag":"authentication-required","analyzedSha":"598aa4bdada683d17ca04b1842548821ff0eb6c6","analyzedAt":"2026-09-14T11:12:15.309Z","contentChangedAt":"2026-09-14T11:12:15.309Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}