"BAD CSRF" when executing PUT using API, curl, and PHP

AI-generated summary

The discussion revolves around resolving a “BAD CSRF” error when executing a PUT request using the API, curl, and PHP. hjalali initially shared their code, which was causing the error. simon suggested moving the Api-Key and Api-Username values to the request header, providing a link to a relevant topic.

Following this advice, hjalali was able to resolve the issue and shared their updated code. They also provided an additional example for updating a “user_field”.

Later, brospars inquired about when the Api-Key and Api-Username in the request header became mandatory, as their existing tool had stopped working. blake explained that support for non-HTTP header based authentication was dropped on April 6th, 2020, and provided a link to the relevant deprecation warning.

I have a very simple function that “should” work but it is not for some reason. Can someone help me understand what we are doing wrong.

We keep getting the “BAD CSRF” error.

public function changeName()
{
  $url = 'https://www.website.com/{username}.json';
  $data = ['name'=>'James', 'api_key'=>DISCOURSE_API, 'api_username'=>'system'];

  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
  curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type:multipart/form-data'));
  curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($data));

  echo $response = curl_exec($ch);

  if (!$response)
  {
      return false;
  }

}

By the way I already tried moving the api_key and api_username to the URL above as GET but no difference.

You need to put the Api-Key and Api-Username values in the request header. There’s a curl example near the end of this topic that could be helpful: Sync DiscourseConnect user data with the sync_sso route.

Thanks a lot! That did the trick.

For anyone else with the same problem:

$url = 'https://www.website.com/{username}.json';
$data = ['name'=>'George'];
$api_key = CUSTOM_DISCOURSE_API;

$headers = array("Content-Type: multipart/form-data;","Api-Key: $api_key","Api-Username: system",);


$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers );
curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($data));

$result = curl_exec( $ch );

if ( curl_errno( $ch ) !== 0 ) {
   // Handle error, call curl_close( $ch ) and return.
}

curl_close( $ch );

$discourse_user = json_decode( $result );

Just to add to that, if someone needs to update a “user_field” replace the $data with this:

$data = ['user_fields' => ['1' => 'Something']];

The number “1” being the first user_field I created (as they are assigned by number not name).

Since when it’s mandatory ?
Didn’t find it in the changelog. I made a tool 2-3 years ago to create categories in batch that worked perfectly fine and now I get this error…

Sorry about any issues this caused, we did do a slow roll out of this change and notified people the best we could, but its hard to catch every deprecation use.