<p>According to <a href="https://craftcms.com/support/csrf-protection" rel="nofollow">https://craftcms.com/support/csrf-protection</a> CSRF does require POST requests</p>

<blockquote>
  <p>With CSRF protection enabled, all of your site’s visitors will get a “CRAFT_CSRF_TOKEN” cookie set on their browser, and all POST requests must be accompanied by a POST parameter with a matching name and value (the CSRF Token).</p>
</blockquote>

<p>On top of that, you'll need to (manually) enable it in your config:</p>

<blockquote>
  <p>You will need to enable it to take advantage of it. You can do that by setting the <a href="https://craftcms.com/docs/config-settings#enableCsrfProtection" rel="nofollow">enableCsrfProtection</a> config setting in your craft/config/general.php file.</p>
</blockquote>

CC BY-SA 3.0
2016-02-04T09:28:00.620Z
Thanks – I missed that part in the docs! Oh well, I'll try to find a workaround and post it as an additional answer, in case anyone else needs CSRF protection for GET requests.
Mats Mikkel Rummelhoff
CC BY-SA 3.0
2016-02-04T09:19:59.893Z
2016-02-04T09:19:59.893Z
chris
<p><a href="https://craftcms.stackexchange.com/users/4588/chris">Chris</a> is quite <a href="https://craftcms.stackexchange.com/a/13561/1098">correct</a> – CSRF does not work with GET requests (see <a href="https://craftcms.stackexchange.com/a/4554/1098">this answer by Brad Bell</a> for an explanation). I'm posting my workaround as an additional answer in case anyone else ever needs to have CSRF validation for GET requests working.</p>

<p>To get around the issue, I set up a custom config key in <code>/config/general.php</code> called <code>tokenGetParam</code>. This is because you can't use the native <code>tokenParam</code> config setting for GET requests – Craft's CSRF validation will hijack the request and throw a 404 exception as soon as it sees the token in the URL, if it's a GET request. Obviously, the <code>tokenGetParam</code> setting needs to have a different value than <code>tokenParam</code>, as well – I went with <code>"t"</code>. A custom config value isn't really necessary – you can just hard code along the way – but it's helpful to have if you ever need to change it in a pinch.</p>

<p><em>Of course, not being able to use the native <code>tokenParam</code> config value also means that you can't use the various built-in methods for dealing with CSRF tokens, e.g. <code>$this-&gt;requireToken()</code> for the Controller or <code>UrlHelper::getUrlWithToken()</code>, etc.</em></p>

<p>In my case, my needs were very simple. I simply needed to include a valid CSRF token in a GET variable <code>tokenGetParam</code> (i.e. <code>"t"</code>) in the callback URL to the external API, so that whenever the external API calls that URL after authenticating stuff on their end, I'd be able to accept or reject the request based on the contents of the <code>"t"</code> query parameter.</p>

<p>Here's how I generate the callback URL before calling the external webservice:</p>

<pre><code>$callbackUrl = UrlHelper::getSiteUrl('actions/myplugin/mycontroller/authCallback').'?'.craft()-&gt;config-&gt;get('tokenGetParam').'='.craft()-&gt;request-&gt;getCsrfToken();
</code></pre>

<p>When the <code>actionAuthCallback</code> is called, I validate the token like this:</p>

<pre><code>$requestToken = craft()-&gt;request-&gt;getQuery(craft()-&gt;config-&gt;get('tokenGetParam'));
if ($requestToken !== craft()-&gt;request-&gt;getCsrfToken()) {
    // Token is not valid
    throw new HttpException(400);
}
</code></pre>

<p>Works.</p>

CC BY-SA 3.0
2016-02-04T15:30:07.493Z
2016-02-04T15:30:07.493Z
2017-04-13T12:51:00.303Z
Mats Mikkel Rummelhoff
<p>I've got a controller action which will work as the callback URL for OAUTH authentication with an external, third-party API. After authenticating, the external API will issue a GET request to my callback URL, which means I need to allow anonymous access for the action method. However, I'd like to use CSRF protection for it.</p>

<p>I've set <code>enableCsrfProtection</code> to <code>true</code> in my config/general.php file, and the <code>tokenParam</code> setting is <code>token</code>. I've also added <code>protected $allowAnonymous = array('actionAuthCallback');</code> to my Controller.</p>

<p>Here's how I create the callback URL:</p>

<pre><code>$callbackUrl = UrlHelper::getUrlWithToken(UrlHelper::getSiteUrl('actions/myplugin/mycontroller/authCallback'), craft()-&gt;request-&gt;getCsrfToken());
</code></pre>

<p>The resulting URL looks like this:  </p>

<pre><code>https://mysite.com/actions/myplugin/mycontroller/authCallback?token=2423552353djfsjfdsfjsdfsdfrandomrandomawesome
</code></pre>

<p>I've validated that the correct action method fires, so all good so far.</p>

<p>Here's the important bits for the action:</p>

<pre><code>public function actionAuthCallback()
{
    $this-&gt;requireToken();
    ...
    $this-&gt;returnJson(array(
        'success' =&gt; true,
    ));
}
</code></pre>

<p>If I call the action URL <em>without</em> the <code>token</code> query parameter, stuff works as expected – Craft throws a 400, as it should.</p>

<p>However, if I do include the <code>token</code> parameter in the URL, Craft throws a <strong>404</strong>. What's even more confusing, this happens even if I leave out the <code>$this-&gt;requireToken();</code> call in the <code>actionAuthCallBack()</code> method – as soon as Craft sees the <code>token</code> query parameter in the URL, the 404 exception is thrown.</p>

<p><em>What am I doing wrong? Does CSRF protection require POST requests?</em></p>

<plugin-development><controller><csrf>
Does CSRF protection for controller actions require POST?
# Does CSRF protection for controller actions require POST?

(Asked by: username_0 on 2016-02-04)

I've got a controller action which will work as the callback URL for OAUTH authentication with an external, third-party API. After authenticating, the external API will issue a GET request to my callback URL, which means I need to allow anonymous access for the action method. However, I'd like to use CSRF protection for it.
I've set enableCsrfProtection to true in my config/general.php file, and the tokenParam setting is token. I've also added protected $allowAnonymous = array('actionAuthCallback'); to my Controller.
Here's how I create the callback URL:
$callbackUrl = UrlHelper::getUrlWithToken(UrlHelper::getSiteUrl('actions/myplugin/mycontroller/authCallback'), craft()->request->getCsrfToken());

The resulting URL looks like this:  
https://mysite.com/actions/myplugin/mycontroller/authCallback?token=2423552353djfsjfdsfjsdfsdfrandomrandomawesome

I've validated that the correct action method fires, so all good so far.
Here's the important bits for the action:
public function actionAuthCallback()
{
    $this->requireToken();
    ...
    $this->returnJson(array(
        'success' => true,
    ));
}

If I call the action URL without the token query parameter, stuff works as expected – Craft throws a 400, as it should.
However, if I do include the token parameter in the URL, Craft throws a 404. What's even more confusing, this happens even if I leave out the $this->requireToken(); call in the actionAuthCallBack() method – as soon as Craft sees the token query parameter in the URL, the 404 exception is thrown.
What am I doing wrong? Does CSRF protection require POST requests?

**Tags:** plugin-development, controller, csrf


---

## 2 answers

### Answer by username_1 on 2016-02-04. Score: 2 | Accepted answer

According to <https://craftcms.com/support/csrf-protection> CSRF does require POST requests

> With CSRF protection enabled, all of your site’s visitors will get a “CRAFT\_CSRF\_TOKEN” cookie set on their browser, and all POST requests must be accompanied by a POST parameter with a matching name and value (the CSRF Token).

On top of that, you'll need to (manually) enable it in your config:

> You will need to enable it to take advantage of it. You can do that by setting the [enableCsrfProtection](https://craftcms.com/docs/config-settings#enableCsrfProtection) config setting in your craft/config/general.php file.

> **Comments:**
> **username_0**: Thanks – I missed that part in the docs! Oh well, I'll try to find a workaround and post it as an additional answer, in case anyone else needs CSRF protection for GET requests.  

---

### Answer by username_0 on 2016-02-04. Score: 2

Chris is quite correct – CSRF does not work with GET requests (see this answer by Brad Bell for an explanation). I'm posting my workaround as an additional answer in case anyone else ever needs to have CSRF validation for GET requests working.
To get around the issue, I set up a custom config key in /config/general.php called tokenGetParam. This is because you can't use the native tokenParam config setting for GET requests – Craft's CSRF validation will hijack the request and throw a 404 exception as soon as it sees the token in the URL, if it's a GET request. Obviously, the tokenGetParam setting needs to have a different value than tokenParam, as well – I went with "t". A custom config value isn't really necessary – you can just hard code along the way – but it's helpful to have if you ever need to change it in a pinch.
Of course, not being able to use the native tokenParam config value also means that you can't use the various built-in methods for dealing with CSRF tokens, e.g. $this->requireToken() for the Controller or UrlHelper::getUrlWithToken(), etc.
In my case, my needs were very simple. I simply needed to include a valid CSRF token in a GET variable tokenGetParam (i.e. "t") in the callback URL to the external API, so that whenever the external API calls that URL after authenticating stuff on their end, I'd be able to accept or reject the request based on the contents of the "t" query parameter.
Here's how I generate the callback URL before calling the external webservice:
$callbackUrl = UrlHelper::getSiteUrl('actions/myplugin/mycontroller/authCallback').'?'.craft()->config->get('tokenGetParam').'='.craft()->request->getCsrfToken();

When the actionAuthCallback is called, I validate the token like this:
$requestToken = craft()->request->getQuery(craft()->config->get('tokenGetParam'));
if ($requestToken !== craft()->request->getCsrfToken()) {
    // Token is not valid
    throw new HttpException(400);
}

Works.


---

