ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken): While POSTing a JSON arugments to a Rails Controller

I am using a React/Redux frontend with a rails server running the backend. I have a button that onClick will send trigger an action that consists of two dispatches and a fetch, one dispatch before and one after. The fetch finds the server properly but I am given a 422 Error, meaning there is some issue on the Rails side of things after the request is accepted. The error is as you see in the title, ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken). However, I have the params set up to require a player object and permit the proper attributes.
The action with the fetch (which I know works) looks like this

export default function completeAttributeSelection(playerObj){
    const playerPOST = ({
        method: "POST",
        headers: {
            "Content-Type": "application/json",
            "Accept": "application/json"
        body: JSON.stringify({
            atk: playerObj.atk,
            sAtk: playerObj.sAtk,
            def: playerObj.def,
            sDef: playerObj.sDef,
            spd: playerObj.spd,
            hp: playerObj.hp,
    return (dispatch) => {
        dispatch({type: "LOADING"})
        console.log("Domain: " + DOMAIN())
        fetch((DOMAIN() + "/players/update_or_create"), playerPOST)
            .then(resp => resp.json())
            .then(json => {
                dispatch({type: "ATTRIBUTE_UPDATE_COMPLETE", payload: json})

And this is the controller that handles the request:

class PlayersController < ApplicationController

    def update_or_create
        puts ("Update or Create hit")
        @player = Player.create_or_find_by(name: player_params[:name])
        puts (player_params)
        @player.update(class: player_params[:class], lvl: player_params[:level], atk: player_params[:atk], sAtk: player_params[:sAtk], def: player_params[:def], sDef: player_params[:sDef], spd: player_params[:spd], hp: player_params[:hp])
        render json{@player}

    def player_params
        params.require(:player).permit(:name, :inv_hash, :lvl, :name, :class, :atk, :def, :sAtk, :sDef, :spd, :hp, :move_distance)

Since I am not using any secrets, keys, or anything like has_secure_password I am struggling to see what exactly is getting caught up by this.
The entirety of the prompts I get from the Rails Terminal (before the long jumbled error) is as follows…

Processing by PlayersController#update_or_create as JSON
  Parameters: {"atk"=>6, "sAtk"=>6, "def"=>5, "sDef"=>9, "spd"=>10, "hp"=>85, "name"=>"test01", "player"=>{"name"=>"test01", "atk"=>6, "def"=>5, "sAtk"=>6, "sDef"=>9, "spd"=>10, "hp"=>85}}
HTTP Origin header (http://localhost:3000) didn't match request.base_url (http://localhost:3006)
Completed 422 Unprocessable Entity in 0ms (ActiveRecord: 0.3ms | Allocations: 394)

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

>Solution :

The short answer to get this to work is adding protect_from_forgery with: :null_session to your controller.

class PlayersController < ApplicationController
  protect_from_forgery with: :null_session

  # ...

The longer answer deals with CSRF and the so called authenticity token. This is a good source it seems

Cross-Site Request Forgery is a serious vulnerability that stems from
the trust that web applications place on the session identification
cookies that are being passed between browser and server. For a more
detailed explanation of CSRF, I suggest looking at the OWASP guide on
Cross-Site Request Forgery.

Rails includes a built-in mechanism for preventing CSRF,
protect_from_forgery, which is included by default in the
application_controller.rb controller when generating new applications.
This protect_from_forgery method leverages magic to ensure that your
application is protected from hackers!

Leave a Reply