Skip to content

CSRF token staleness causes all POST requests to fail after token rotation #3243

Description

@christianlupus

Extracted from #3227 by @eals2019:

Root cause

File: src/js/api-interface.js, line 6

import axios from '@nextcloud/axios';

const instance = axios.create();   // line 6 — ❌

@nextcloud/axios automatically subscribes the default axios instance to Nextcloud's csrf-token-update events, keeping the requesttoken header current across token rotations. However, axios.create() produces a new, independent instance that does not inherit those event subscriptions. The instance receives the correct CSRF token at page load but becomes stale if Nextcloud rotates the token during a long-running session, causing all subsequent POST requests (directory change, reindex, recipe save) to fail with a server-side CSRF validation error.

This can be confirmed in the server log (nextcloud.log):

{
  "method": "POST",
  "url": "/apps/cookbook/webapp/reindex",
  "message": "CSRF check failed"
}

Fix

Subscribe instance to CSRF token updates immediately after creation, mirroring what @nextcloud/axios does internally for its own instance:

import axios from '@nextcloud/axios';
import { onRequestTokenUpdate } from '@nextcloud/auth';  // ✅ add import

const instance = axios.create();

// Keep instance in sync with Nextcloud CSRF token rotations
onRequestTokenUpdate((token) => {           // ✅ add this block
    instance.defaults.headers.requesttoken = token;
});

Alternatively, avoid .create() entirely and use the @nextcloud/axios default export directly, since it already handles token rotation. All interceptors currently added to instance (request/response logging) would need to be moved to the default axios export in that case.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions