Dolibarr/dolibarr · error

Access to this page this way (POST method or GET with a…

Error message

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.

What it means

The generic CSRF refusal in main.inc.php: a state-changing request (POST, or GET with a meaningful 'action' parameter) arrived without a token on a page that did not declare CSRFCHECK_WITH_TOKEN. Dolibarr returns 403 to prevent cross-site request forgery.

Solutions

  1. Include the token: POST field or GET 'token' parameter from newToken() matching the current session
  2. Use Dolibarr's REST API (api token) for programmatic access instead of form endpoints
  3. Ensure the user session is active and stable (same Dolibarr instance) when the form is submitted
  4. As a last resort, tune MAIN_SECURITY_CSRF_WITH_TOKEN (not recommended) or set $dolibarr_nocsrfcheck in conf.php for trusted contexts

Example fix

// before
curl -d 'action=update&id=15' https://doli.example.com/htdocs/societe/card.php
// after
curl -d 'action=update&id=15&token='$TOKEN https://doli.example.com/htdocs/societe/card.php
Defensive patterns

Strategy: fallback

Validate before calling

if (($_SERVER['REQUEST_METHOD']==='POST' || isset($_GET['action'])) && empty($_REQUEST['token'])) { die('Token required before calling Dolibarr'); }

Prevention

When it happens

Trigger: POST to any main.inc.php-protected page without token parameter; GET request with action=add/confirm/update etc. and no token; external form or curl script posting into Dolibarr endpoints.

Common situations: REST/curl scripts posting to page endpoints instead of the REST API; embedding Dolibarr forms in third-party sites; session regenerated (login) making the old token invalid; load-balanced setup with mismatched sessions.

Related errors


AI-assisted analysis of Dolibarr/dolibarr@598aa4bdad (2026-09-14). Data as JSON: /api/errors/cbf3e272652c95e3. Report an issue: GitHub.

Appendix: source

Thrown at htdocs/main.inc.php:443

		GETPOSTISSET('massaction') ||
		((GETPOSTISSET('actionlogin') || GETPOSTISSET('action')) && defined('CSRFCHECK_WITH_TOKEN'))
	) {
		// If token is not provided or empty, error (we are in case it is mandatory)
		if (!GETPOST('token', 'alpha') || GETPOST('token', 'alpha') == 'notrequired') {
			top_httphead();
			if (GETPOSTINT('uploadform')) {
				dol_syslog("--- Access to ".(empty($_SERVER["REQUEST_METHOD"]) ? '' : $_SERVER["REQUEST_METHOD"].' ').$_SERVER["PHP_SELF"]." refused. File size too large or not provided.");
				$langs->loadLangs(array("errors", "install"));
				print $langs->trans("ErrorFileSizeTooLarge").' ';
				print $langs->trans("ErrorGoBackAndCorrectParameters");
			} else {
				http_response_code(403);
				if (defined('CSRFCHECK_WITH_TOKEN')) {
					dol_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);
					print "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";
				} else {
					dol_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);
					print "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";
					print "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";
					if (getDolGlobalString('MAIN_SECURITY_CSRF_WITH_TOKEN')) {
						print " instead of " . getDolGlobalString('MAIN_SECURITY_CSRF_WITH_TOKEN');
					}
					print " into setup).\n";
				}
			}
			die;
		}
	}

	$sessiontokenforthisurl = (empty($_SESSION['token']) ? '' : $_SESSION['token']);
	// 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)
	if (GETPOSTISSET('token') && GETPOST('token') != 'notrequired' && GETPOST('token', 'alpha') != $sessiontokenforthisurl) {
		dol_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);
		//dol_syslog("_SESSION['token']=".$sessiontokenforthisurl, LOG_DEBUG);
		// Do not output anything on standard output because this create problems when using the BACK button on browsers. So we just set a message into session.
		if (!defined('NOTOKENRENEWAL')) {

View on GitHub (pinned to 598aa4bdad)