Improve BAD CSRF error message when making API calls with content-type application/json

API requests with the Content-Type as “application/json” often receive an unhelpful message like “BAD CSRF”, so we should improve the error messaging so that it provides more details as to why they are receiving this error message.

8 Likes

Hi Blake,

I’ve been sending JSON payloads to the API and up until recently, I’ve received a JSON response.

Whilst my calls to the API still seem to work correctly (i.e. a topic is created when I post to posts.json), the response now comes back as null (rather than the json I used to receive) and this breaks my response parsing.

In the Rails log I see

Started POST "/posts.json" for 82.44.224.199 at 2019-05-12 20:16:32 +0000
Processing by PostsController#create as JSON
  Parameters: {"title"=>"RT @love_se4: One of those hidden gems in the local community, you just have to try. Over 170 different gins. Proper mixologists who know h…", "raw"=>"https://twitter.com/se23_tweets/status/1127663613412630529", "category"=>49, "post"=>{"raw"=>"https://twitter.com/se23_tweets/status/1127663613412630529"}}
Can't verify CSRF token authenticity.
Completed 200 OK in 9ms (Views: 0.2ms | ActiveRecord: 0.0ms)

I’ve tried sending the API keys in the query string and in the HTTP headers. Seems they’re being accepted by the remote side.

I want to send data to Discourse in JSON form rather than form encoded. JSON worked in the past. Is there anything I can do to restore the functionality of my API code?

3 Likes

Can you share with me your actual ruby code to make this request? I’m unable to reproduce this locally. Here is the Postman json call I’m making and I’m always getting a response back:

image

Also I don’t think you need the extra post["raw"] parameter.

Parameters: {"title"=>"RT @love_se4: One of those hidden gems in the local community, you just have to try. Over 170 different gins. Proper mixologists who know h…", "raw"=>"https://twitter.com/se23_tweets/status/1127663613412630529", "category"=>49, "post"=>{"raw"=>"https://twitter.com/se23_tweets/status/1127663613412630529"}}

3 Likes

I’m unassigning myself from this for now, but would like to leave it open as a place to track any future “BAD CSRF” errors in case they continue to occur.

From digging into this I realized that most of the BAD CSRF errors came from before we switched to header based authentication via the API.

Pre-header based auth, if the json request was malformed in some way we couldn’t read the API_KEY out of the paremeters and so we couldn’t detect if the request was an actual API request on this line in the application controller:

unless is_api? || is_user_api?

and so we would just return:

  render plain: "[\"BAD CSRF\"]", status: 403

But now that API credentials are almost always in the HTTP Header of the request we can determine that the request is actually an API request with much better accuracy than before and so the “BAD CSRF” error shouldn’t show up as frequently anymore.

6 Likes

We were seeing this error after a recent Discourse upgrade (within the last few months). The application was not authenticating against the API via the HTTP headers, changed it to do so and now it works again.

1 Like