There are a number of answers here about how to send CSRF tokens along with AJAX requests, but I think my question is a little different. Please excuse the abstractness here:

In a headless application, I'd like to be able to log users in via AJAX, and keep a fresh CSRF token in the client-side application's state.

Is there a way to get a new token, once one has been consumed?

Imagine a case where a customer adds an item to their cart—that token is consumed, and a new one is issued on the next page load… but what if there isn't a new page load?

Am I even thinking about this the right way?

In looking at the UsersController, I noticed that the get-remaining-session-time action sends a csrfTokenValue. Any chance this is part of the answer?

1 Answer 1


A similar question was asked in the Craft Slack today, so I thought I'd transcribe the consensus:

Internally, CSRF tokens come from a call to Craft::$app->getRequest()->getCsrfToken(). This means that any controller (or template, for that matter—more often handled by the {{ csrfInput() }} shortcut method) can grab a CSRF token at will.

In the original post, I'd noted that the users/get-remaining-session-time action returns a token—that token comes from the above call, so it certainly sounds like a valid built-in method for grabbing tokens.

That said, it does have some potential side effects related to the session (aside from refreshing the CSRF token).

Ultimately—provided the time—it seems like the recommended method is to create a custom controller and call the method explicitly.

As far as the client-side handling… if your application has a means to consolidate AJAX calls, it'd be worth automating the refresh and inclusion of CSRF tokens as HTTP headers. For example, before a regular POST request is initiated, the client might first ensure it has a fresh CSRF token, then issue the request with the new token.

Hope this helps anyone else getting started with client-rendered applications!

Edit: As of Craft 3.1.13, you get a CSRF token in the JSON response when a user logs in (assuming the login occurs over Ajax)!

  • Worth noting—correct me if I'm wrong: the token isn't really “consumed”… it actually remains valid for the length of the session. You just happen to get a new one with each template-y request, because that's the expected behavior of the getCsrfToken method. So, with the 3.1.13 update, you can just immediately turn around and send this token to your application as many times as you like, without needing to refresh it. Cool! Commented Mar 5, 2019 at 23:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.