Tangible Bytes

A Web Developer’s Blog

How to make Axios JS use Cookies and XSRF Token

I am working on an application that needs to be able to login to a Laravel instance via API.

In my usual workflow all the session management and XSRF protection has been automagical but I needed to be able to build a test case - and all the docs seemed to assume it would “Just Work™”

It took me a while to figure out what was going on and how to make it work.

The Default Scenario

https://axios-http.com/docs/req_config

  // `withCredentials` indicates whether or not cross-site Access-Control requests
  // should be made using credentials
  withCredentials: false, // default

If you are operating in a browser to a secure (https) site this should be all you need.

Testing Outside a Browser

If you are not in a browser you have to use a client that adds a cookie jar and make your requests with this instead of using axios directly.

This will retain cookies from previous responses and add the to future requests.

Test Server Does Not Have https

My test environment is running without https, while this is becoming increasingly problematic for JavaSCript development I can workaround it in this case.

The cookie behaviour still works - but for the XSRF protection to work I need the XSRF-TOKEN cookie value added to the request as an X-XSRF-TOKEN header (this acts as proof that the request comes from the same client).

Sending this header in plain text is insecure - so axios doesn’t automatically do it.

But for test purposes in a dev environment I am manually adding this header

Resulting Code

import axios from 'axios';
import { wrapper } from 'axios-cookiejar-support';
import { CookieJar } from 'tough-cookie';


// in a browser cookies are managed for us
// in this test script we need to setup a cookiejar 
const jar = new CookieJar();
const client = wrapper(axios.create({ jar }));


const host = 'http://localhost'

try {
    let options = { method: 'GET', url: host + '/sanctum/csrf-cookie', withCredentials: true };
    let crsfReq = await client.request(options);
    let now = new Date().valueOf();
    options = {
        method: 'POST',
        url: host + '/api/auth/signup',
        data: {
            firstname: 'foo',
            lastname: 'bar',
            email: `${now}@example.com`,
            password: now,

        },
        withCredentials: true
    };


    // I think that in a secure browser context axios does this bit for you
    const cookie = (crsfReq.headers['set-cookie'])
        .find(cookie => cookie.includes('XSRF-TOKEN'))
        ?.match(new RegExp(`^${'XSRF-TOKEN'}=(.+?);`))
        ?.[1];
    options.headers = { 'X-XSRF-TOKEN': decodeURIComponent(cookie) }
    


    const { data } = await client.request(options);
    console.log(data);



} catch (error) {
    console.error(error);
}

Install the pre-requisites with

npm install axios tough-cookie axios-cookiejar-support

Summary

I think it most cases this will happen fairly transparently, but I hope this helps anyone else who needs to make this work outside of a browser context.