Wednesday, March 15, 2023

Enable CSRF protection

 To implement the suggested design to protect your Rails API from CSRF attacks, follow these steps:


Enable CSRF protection in the application_controller.rb file:

class ApplicationController < ActionController::API

  protect_from_forgery with: :exception

end


Implement an endpoint in the Rails API to generate and return the CSRF token:

First, create a new controller:


# app/controllers/csrf_controller.rb

class CsrfController < ApplicationController

  skip_before_action :verify_authenticity_token


  def token

    render json: { csrf_token: form_authenticity_token }

  end

end


Next, add a route for the new endpoint in config/routes.rb:


Rails.application.routes.draw do

  # Add this line for the new CSRF token endpoint

  get 'csrf/token', to: 'csrf#token'


  # Other routes...

end


Update your React application to fetch the CSRF token when it loads and include the token in the request headers:

First, fetch the CSRF token when the React application loads and store it in the application state or a context. For example, if you are using React Hooks:


// App.js

import React, { useState, useEffect } from 'react';


function App() {

  const [csrfToken, setCsrfToken] = useState(null);


  useEffect(() => {

    async function fetchCsrfToken() {

      const response = await fetch('/csrf/token');

      const data = await response.json();

      setCsrfToken(data.csrf_token);

    }


    fetchCsrfToken();

  }, []);


  return (

    <div className="App">

      {/* Your application components */}

    </div>

  );

}


export default App;



Next, include the fetched CSRF token in the request headers when making API calls from the React application. If you are using fetch:


async function makeApiRequest(url, method = 'GET', body = null) {

  const headers = new Headers();

  headers.append('Content-Type', 'application/json');

  headers.append('X-CSRF-Token', csrfToken); // Add the CSRF token to the headers


  const requestOptions = {

    method: method,

    headers: headers,

    credentials: 'include',

  };


  if (body) {

    requestOptions.body = JSON.stringify(body);

  }


  const response = await fetch(url, requestOptions);

  return response.json();

}


This implementation ensures that the Rails API is protected from CSRF attacks while maintaining compatibility with the React frontend. Remember to regularly assess and monitor the application's security, especially as new features and endpoints are added.