Ruby on Rails CSRF Protection with React.js & Webpacker

Zayne Abraham
2 min readAug 24, 2019

--

An idea for handling CSRF tokens in your Rails app when using webpacker and React.

Edit: Read the github thread the code in this post was based on for a better/up to date answer on this topic.

Rails has built in CSRF protection by default, so when you first try to make a post request from the react portion of your app, initially your request will fail and you’ll probably see a message like this in your console:

Can't verify CSRF token authenticity.
Completed 422 Unprocessable Entity
ActionController::InvalidAuthenticityToken

The Quick & Dirty Solution

The easier but potentially more reckless fix you may want to do is to simply disable CSRF protection in your rails controller, which can be done like so:

skip_before_action :verify_authenticity_token

Doing this will ‘fix’ the issue mentioned above, but in doing so, you are now opening your app up to potentially accept illegitimate requests.

There may be times where it makes sense to do this, but there also may be times where it does more harm than good.

Another way

Let’s assume you have a component in your React code that looks something like this:

import React, { Component } from 'react'
import axios from 'axios'
class App extends Component {
handleSubmit = (e) => {
e.preventDefault()
axios.post(url, {params: 'bla'})
.then(resp => console.log(resp))
.catch(error => console.log(error))
}

render(){
return(
<form onSubmit={this.handleSubmit}>
<button type="submit">Click Me</button>
</form>
)
}
}
export default App

Using axios, we can update this code to account for a CSRF token by modifying axios’s default headers:

import React, { Component } from 'react'
import axios from 'axios'
class App extends Component {
handleSubmit = (e) => {
e.preventDefault()
const token =
document.querySelector('[name=csrf-token]').content

axios.defaults.headers.common['X-CSRF-TOKEN'] = token
axios.post(url, {params: 'bla'})
.then(resp => console.log(resp))
.catch(error => console.log(error))
}

render(){
return(
<form onSubmit={this.handleSubmit}>
<button type="submit">Click Me</button>
</form>
)
}
}
export default App

Adding that to your code should resolve the CSRF issue and allow you to now make post requests from your React code to your Rails controllers.

Conclusion

The above example is specific to a rails app using webpacker, and uses axios for the solution — if you are using a different approach, your mileage may vary with this.

--

--

Zayne Abraham

Read more posts I’m working on about startups, coding, ruby, rails and more here: https://zayne.io