usebruno / bruno

Opensource IDE For Exploring and Testing Api's (lightweight alternative to postman/insomnia)
https://www.usebruno.com/
MIT License
27.71k stars 1.28k forks source link

[Bug] - Problem with Laravel Sanctum XSRF-TOKEN authentication #1493

Closed benjaminhaeberli closed 8 months ago

benjaminhaeberli commented 9 months ago

Hi guys ! First of all, thanks for this amazing tool that I truly want to use as a Postman alternative. The fact that this is versionable is amazing 👌

I wanted to use Bruno for a new Laravel API I'm working on, but I struggled a lot with scripting to automatically retrieve the XSRF-TOKEN that is generated by Laravel Sanctum (https://laravel.com/docs/10.x/sanctum#spa-authentication).

Here is the script I writed. In the console it looks fine, the token is correct, but something goes wrong when Bruno send the request because I don't get anything on my back-end side OR I get the token without the last "=" character :

const axios = require("axios");

const config = {
  withCredentials: true,
    headers: {
    "Accept" : "application/json",
    "Content-Type": "application/json",
        "Referer": "app.nanou.test",
    },
};

await axios.get(bru.getEnvVar('baseUrl') + '/sanctum/csrf-cookie', config).then(response => {
  const setCookieHeader = response.headers.get('set-cookie');

const xsrfTokenCookie = setCookieHeader.find(cookie => cookie.startsWith('XSRF-TOKEN='));
const xsrfToken = xsrfTokenCookie.split('=')[1].split(';')[0];
const xsrfDecodedToken = decodeURIComponent(xsrfToken);
req.setHeader('X-XSRF-TOKEN',xsrfToken);
});

The headers are these one Accept: application/json, Referer: app.nanou.test, Access-Control-Allow-Credentials: true. I then tried to replicate the same script in Postman with the same headers and it works, I don't know why. Is this a bug from Bruno or did I make something wrong ?

let csrfRequestUrl = pm.environment.get('url') + '/sanctum/csrf-cookie';
pm.sendRequest(csrfRequestUrl, function(err, res, {cookies}) {
    let xsrfCookie = cookies.one('XSRF-TOKEN');
    if (xsrfCookie) {
        let xsrfToken = decodeURIComponent(xsrfCookie['value']);
        pm.request.headers.upsert({
            key: 'x-xsrf-token',
            value: xsrfToken,
        });                
        pm.environment.set('XSRF-TOKEN', xsrfToken);
    }
});
LuccaRomanelli commented 9 months ago

Same here

benjaminhaeberli commented 9 months ago

I find a solution @LuccaRomanelli. I added two environment variables :

I added three collections headers :

Then I added a POST request to {{baseUrl}}/login with just email and password in the body.

And finally I created a separate GET request to {{baseUrl}}/sanctum/csrf-cookie with this Post Response script :

const setCookieHeader = res.headers.get('set-cookie')[0];

const xsrfTokenMatch  = setCookieHeader.match(/XSRF-TOKEN=([^;]+)/);

const xsrfToken = decodeURIComponent(xsrfTokenMatch[1]);

bru.setEnvVar('X-XSRF-TOKEN',xsrfToken);

Now it works 🥳 I just have to run the "CRSF" request manually once before run the other requests.

thomasaull commented 1 month ago

Small addition, in a recent project I needed to change the first line to:

const setCookieHeader = res.headers['set-cookie'][0];

to make it work. Tested with bruno v1.27.0