Dolibarr/dolibarr · warning

If you access your server behind a proxy using url…

Error message

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${current_value} into setup).

What it means

This is not a standalone error but the trailing hint appended to the generic CSRF refusal (error 8): it explains that behind a proxy with URL rewriting the token parameter may be lost, and suggests checking header propagation, setting $dolibarr_nocsrfcheck=1 in conf.php, or changing MAIN_SECURITY_CSRF_WITH_TOKEN to 0 in setup. The current value of MAIN_SECURITY_CSRF_WITH_TOKEN is interpolated when set.

Solutions

  1. Fix proxy rewrite rules so the query string (including token) is preserved (e.g. proxy_pass with $uri/$args, keep original args)
  2. Propagate all HTTP headers (Host, X-Forwarded-*) to the backend
  3. If truly required, add $dolibarr_nocsrfcheck=1; to conf.php — understand this weakens security
  4. Or set MAIN_SECURITY_CSRF_WITH_TOKEN to 0 in Home > Setup > Other Setup

Example fix

# before (nginx)
rewrite ^/dolibarr/(.*)$ /index.php last;
# after
rewrite ^/dolibarr/(.*)$ /index.php?$args last;
Defensive patterns

Strategy: validation

Validate before calling

// Behind a proxy, verify the query string reaches PHP:
if (empty($_SERVER['QUERY_STRING']) && strpos($_SERVER['REQUEST_URI'], '?') !== false) { error_log('Proxy is stripping query string'); }

Prevention

When it happens

Trigger: CSRF refusal occurs while the site is served behind a reverse proxy doing URL rewriting that drops query strings, or the operator intends to relax the token check via conf.php/setup constants.

Common situations: Nginx/Apache reverse proxy rewrite rules stripping 'token='; misconfigured trusted-proxy header propagation; admins considering disabling CSRF token enforcement (security trade-off).

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at htdocs/main.inc.php:444

		((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')) {
			// If the page is not a page that disable the token renewal, we report a warning message to explain token has expired.

View on GitHub (pinned to 598aa4bdad)