nextcloud/server · error · Sabre\DAV\Exception\NotAuthenticated
CSRF check not passed.
Error message
CSRF check not passed.
What it means
Raised in Sabre\Auth::auth() for DAV requests that rely on the browser session: passesCSRFCheck() failed and requiresCSRFCheck() is true, and the method is not POST (POST instead takes the forcedLogout path and re-checks credentials). The server sets 401 and throws NotAuthenticated. In practice: a cookie-authenticated DAV request (PROPFIND, GET, PUT, ...) reached the server without a valid request token.
Source
Thrown at apps/dav/lib/Connector/Sabre/Auth.php:178
return true;
}
/**
* @return array{bool, string}
* @throws NotAuthenticated
*/
private function auth(RequestInterface $request, ResponseInterface $response): array {
$forcedLogout = false;
if (!$this->request->passesCSRFCheck()
&& $this->requiresCSRFCheck()) {
// In case of a fail with POST we need to recheck the credentials
if ($this->request->getMethod() === 'POST') {
$forcedLogout = true;
} else {
$response->setStatus(Http::STATUS_UNAUTHORIZED);
throw new \Sabre\DAV\Exception\NotAuthenticated('CSRF check not passed.');
}
}
if ($forcedLogout) {
$this->userSession->logout();
} else {
if ($this->twoFactorManager->needsSecondFactor($this->userSession->getUser())) {
throw new \Sabre\DAV\Exception\NotAuthenticated('2FA challenge not passed.');
}
if (
//Fix for broken webdav clients
($this->userSession->isLoggedIn() && is_null($this->session->get(self::DAV_AUTHENTICATED)))
//Well behaved clients that only send the cookie are allowed
|| ($this->userSession->isLoggedIn() && $this->session->get(self::DAV_AUTHENTICATED) === $this->userSession->getUser()->getUID() && empty($request->getHeader('Authorization')))
|| \OC_User::handleApacheAuth()
) {
$user = $this->userSession->getUser()->getUID();
$this->currentUser = $user;View on GitHub (pinned to ecdeb153ff)
Solutions
- Send the CSRF token: header 'X-Request-Token' (or 'requesttoken' form/query parameter) using the token embedded in the page (oc_requesttoken / data-requesttoken)
- Prefer app-password basic auth for scripted/daemon access — it bypasses CSRF and 2FA entirely
- For POST requests the code force-logs-out and retries credential checks; ensure your client re-authenticates rather than looping
- Regenerate the page/session if the token is stale (log out and back in)
Example fix
# before (cookie only -> CSRF check not passed) curl -b nc_cookies.txt -X PROPFIND https://cloud.example/remote.php/dav/files/alice/ -H 'Depth: 0' # after (app password: no session, no CSRF involved) curl -u alice:xxxx-xxxx-xxxx-xxxx -X PROPFIND https://cloud.example/remote.php/dav/files/alice/ -H 'Depth: 0'
Defensive patterns
Strategy: validation
Validate before calling
// JS: every cookie-authenticated DAV call must carry the request token
const token = document.querySelector('[data-requesttoken]')?.dataset.requesttoken ?? oc_requesttoken;
await fetch('/remote.php/dav/files/alice/test.txt', {
method: 'PUT',
headers: {
'X-Request-Token': token,
'Content-Type': 'text/plain',
},
body: data,
}); Try / catch
try {
await davPut(url, body);
} catch (e) {
if (e.status === 401 && /CSRF check not passed/.test(e.body ?? '')) {
// cookie session without valid request token: refresh token from the page or switch to app-password auth
await refreshRequestTokenAndRetryOnce();
} else {
throw e;
}
} Prevention
- Attach X-Request-Token (or requesttoken parameter) to every cookie-based DAV request
- Use app passwords + basic auth for scripts, daemons, and CLI — CSRF does not apply
- Read the token fresh from the current page payload; tokens from cached pages may be stale
- Keep auth method consistent per client: either full session+token or full basic auth
When it happens
Trigger: JS or curl calling remote.php/dav/... with only the session cookie, no X-Request-Token header / requesttoken parameter, and no Authorization header — e.g. a fetch() missing the requesttoken header, or a copied curl command reused after the token expired with the session still alive.
Common situations: Custom front-end code calling DAV endpoints and forgetting the request token; long-lived sessions whose requesttoken was rendered into an old page; tools that mix cookie auth with WebDAV semantics; requests proxied through middleware stripping custom headers.
Related errors
- Cannot authenticate over ajax calls
- Cannot authenticate over ajax calls
- $class: $msg
- NoValidCredentials
- Too many calendars created
AI-assisted analysis of nextcloud/server@ecdeb153ff (2026-08-17).
Data as JSON: /api/errors/07e16ecbfbe8032d.
Report an issue: GitHub.