"unexpected token at 'BAD CSRF'" when updating email


(Roberto_Pezzali) #1

I have this error when I try to update a user email through api.

client.update_email(“pippopippo”, "batman@example.com")
DiscourseApi::Error: 399: unexpected token at ‘‘BAD CSRF’]’

Any solution to update a user email? I must implement app -> discourse one way user sync and I can create a user but I cannot update a user email.


(Kane York) #2

Do you have either the master or that user’s API key?


(Roberto_Pezzali) #3

I’m using the api key generated in the admin panel with my admin user. I read in the documents that there is a secret master key but I cannot find it.

Where I get the master key?


(Kane York) #4

The master key is the one generated in the rightmost tab of the /admin panel.

The per-user API keys are the ones generated on each user’s page inside the Users tab of the admin panel.


(Roberto_Pezzali) #5

Ok, I’m using the master key.

I can create a new user with that key but I cannot create a post or update a users.


(Roberto_Pezzali) #6

@riking have yougot some hint?

I try again with master api key on a new fresh install.
When I try to update email of a user same result:

DiscourseApi::Error: 399: unexpected token at ''BAD CSRF']'

:frowning:


(Phil Nelson) #7

I’m getting the error when trying to invite a new user via the API, as well. Have tried using both the master API key and an admin user (same user that is ‘making’ the request) API key.


(Roberto_Pezzali) #8

For me also when I create a post…


(David Liaw) #9

My best guess is that you’re not passing back a csrf token back to the server (or passing an incorrect token). This is pretty much what caused me to spend sleepless nights trying to figure it out…
But you can obtain this from /session/csrf.json and pass it back in the headers as ‘X-CSRF-TOKEN’. If you watch your network activity (chrome dev tools, wireshark, etc) you’ll see that this is what is done by the discourse web app.
I don’t know how you guys are using the API, but hopefully this helps a bit.

Edit: I found that if the above doesn’t work, you can try passing it in the params as ‘authenticity_token’.
Also, the call to get the csrf token is usually done at login/register and passed back every time after that (rather than calling to /csrf.json everytime…)


(Roberto_Pezzali) #10

Of course I’m using api.

"DiscourseApi::Error: 399: unexpected token at ''BAD CSRF']'"

(Clifford Duke) #11

Any idea what the lifespan of the token is?


(David Liaw) #12

@codinghorror What is the correct way to access the API? Using an API key or just using the csrf token, or is it either? I’m a little confused since the web app uses the csrf token but the API examples use the API key system.


(Sam Saffron) #13

csrf is skipped for api calls. provided you specify api key / user


(David Liaw) #14

Ah that makes sense now. But going by that, why does the ‘bad csrf’ occur as per the basis of this thread?


(Clifford Duke) #15

Does the API key have to be tied to that particular user or can it be an admin’s API key? I ask because I received a BAD_CSRF message even after specifying a user and supplying an admin API key


(Roberto_Pezzali) #16

Sam, something is not working as expected because we are using API master key and some api call are working (mail update, user create, user activate) and some not (bad csrf), for example the create post give me that result.


(Sam Saffron) #17

sounds like we need to review the code, api key should always bypass csrf


(Roberto_Pezzali) #18

@sam have you looked ad this? We can’t bypass csrf using master key! We try every setup but every post/put call return bad csrf.

Tu be more precise in not possible to update email address using api call and is not possible to update user attributes.


(Clifford Duke) #19

I don’t think it has been fixed yet, but in the meantime grab the csrf token at /session/csrf.json so like https://meta.discourse.org/session/csrf.json


(Sam Saffron) #20

Copied verbatim from: update API to handle CSRF token by spaghetticode · Pull Request #20 · discourse/discourse_api · GitHub

I just debugged through this issue and can confirm the api gem has become a bit of a mess.

Initially when I wrote it all requests (GET,PUT,POST) passed along api_key and api_username.

100 refactors later, we are no longer doing this, so it needs to be done explicitly, people are forgetting (naturally) and the API is messing up.

Actions needed

  1. api gem MUST always pass api_key and api_username to EVERY (get,put,post) it makes, this must be fixed asap
  2. examples are mostly bust, the examples folder needs to be fixed with WORKING examples
  3. a huge oversight is that now there is no posts.rb, so no clean way for creating posts and the like, this must be added asap. Cause this is a mess on about 10 levels:
client.post("/posts",
  category: "Boing Boing",
  skip_validations: true,
  auto_track: false,
  title: "Concert Master: A new way to choose",
  raw: "This is the raw markdown for my post",
  api_key: client.api_key,
  api_username: client.api_username
)

CSRF thing is a red herring, CSRF bypassing for API works fine, I just confirmed it.

Regarding complaints about update_email being a mess, the reason is twofold.

  1. See item number 1) in my list above
  2. The API endpoint is misunderstood, it will only trigger the email change process, it does not actually change any emails until users confirm.

So, if people really want to change emails via API a new endpoint needs to be added to Discourse. But keep in mind, even admins are required to validate emails in the current system, this would be a departure from it. (and probably a legit use case in API use)