Search code examples
laravelnext.jscsrf

How to get Laravel CSRF value in NEXTJS


I have a Next JS frontend and Laravel 9 as backend. Created APIs and tested them on the postman. All of the API's working fine without any issues.

The Problem

So I have created a Nextjs file with a form and posted data using Axios. I am getting Error: Request failed with status code 419.

Tried

There are multiple answers available on StackOverflow for similar questions. I followed the answers but nothing worked for the problem.

  1. Changed VerifyCsrfToken.php code to disable the csrf protection. (i want to keep the csrf)

  2. Tried adding the csrf cookie using the headers option in Axios. (Axios POST to Laravel API results in 419 error)

  3. Generated key using (PHP artisan key: generate)

  4. Added Session domain

  5. added route in the web middleware

Route::group(['middleware' => ['api']], function () {

    // our routes

});

What's working ?

  1. Allowing all domains in VerifyCsrfToken.php is working.

I want to get csrf token

`const csrf = () => axios.get('/sanctum/csrf-cookie')'

i am getting empty value for csrf token / csrf cookie. and found no accepted answer to the request failed with status code 419.

Does anyone know what I am doing wrong?


Solution

  • As per the documentation of laravel :

    Do these 3 changes in Laravel

    1. Update the cors policy (config/cors.php)

    From : 'supports_credentials' => false,

    To: 'supports_credentials' => true,

    1. Add the line in (resources/js/bootstrap.js)

    axios.defaults.withCredentials = true;

    1. Add backend and frontend url in .env file in laravel
    APP_URL=http://localhost:8000
    FRONTEND_URL=http://localhost:3000
    

    Now do the following cahnges in NEXT JS app.

    1. Add .env.local file at the root and add the following code. NEXT_PUBLIC_BACKEND_URL=http://localhost:8000'

    2. Install axios using npm i axios

    3. Import CSRF Token using AXIOS before posting the data using axios then post form data using axios.

    Here is the sample code to send or get data

    import React, { useEffect, useState } from 'react';
    import axios from 'axios';
    
    //optional toastify library
    import { ToastContainer, toast } from 'react-toastify';
    import 'react-toastify/dist/ReactToastify.css';
    
    export default function index({data}) {
    
    //console.log(data); 
    
      //setting the state (getting form data into veriable)
      const [title, setTitle] = useState('')
      const [desc, setDesc] = useState('')
    
      
      // preventing default and showing the data in console
      const formSubmit = async (e) => {
      e.preventDefault();
      console.log(title ,desc);
    
          // setting csrf token
           await axios.get('http://localhost:8000/sanctum/csrf-cookie').then(getcsrvf => {
                    
              //console.log(getcsrvf);
                
                     // posting the data using axios / creating the data.
                      axios.post('http://localhost:8000/api/post', {title,desc})
                      .then(function (response) {
                        //alert(response.data.message);
                        
                       toast(response.data.message);
                        
                        console.log(response);
                      })
                      .catch(function (error) {
                        //console.log(error);
                      });
              });
    } 
    
    
      return (
    
    // bootstrap installed
    
    <div className=' pt-5'>
    <div className='container'>
    
    //basic jsx form
    
    <form onSubmit={formSubmit}> 
    
     <div className='mb-2'> 
    
    {/* onChange={(e)=>{setName(e.target.value)}} */}
    
    <input type="text" onChange={(e) => {setTitle(e.target.value)}} value={title} className="form-control mb-2 py-2" placeholder="title" name="title" id='title' />
    
    </div>  
    
    <div className='mb-2'>
    <input type="text" onChange={(e) => {setDesc(e.target.value)}} value={desc} className="form-control mb-2 py-2" placeholder="desc" name="desc" id='desc' />
    </div>  
    
    
    <div className='mb-2'>
    <button className='btn btn-primary'>Submit</button>
    </div>  
    </form> 
    
    </div>
    
    
    <hr/>
    //looping the post data
    
    {data.post.map((post, i)=>{
      return (
        <div className='container' key={i}>
          <h3>{post.title}</h3>
          <p>{post.desc}</p>
          <hr/>
        </div>
      )
    })}
    
    
    <ToastContainer position="top-center" pauseOnHover="false"/>
    
    </div>
      )
    }
    
    // Getting the records // reading the data
    
    export async function getServerSideProps() {
     
    const res = await fetch("http://localhost:8000/api/post")
    const data = await res.json()
    
    return{
      props: {
        data
      }
    }
    }
    
    

    Note : Pleae change http://localhost:8000 as your laravle url and http://localhost:3000 as per your frontend url.

    The above solution worked for me.