Morgbn / nuxt-csurf

Nuxt Cross-Site Request Forgery (CSRF) Prevention
https://nuxt-csurf.vercel.app
MIT License
77 stars 16 forks source link

How does it work? #4

Closed chrisnoden closed 1 year ago

chrisnoden commented 1 year ago

Apologies for such a blunt question, but I'm having problems getting this module to work with my Nuxt 3.1.1 project.

I have a form that POSTs the fields and all I get is a CSRF Token Mismatch error

Inspecting the POST request I can see 2 headers:

Cookie: sessionId=0a5868e1-1002-4572-9f9f-474f65530962; csrf=bc4655f5-220d-4512-a345-36c18ec7e358
csrf-token: undefined

I'm not creating either of these, so assume they're coming from the csurf module. The verifyCsrf() function in the middleware is failing at the first hurdle because the token is undefined.

I was using $fetch and have switched to useCsrfFetch to POST the data to my /server/api code. I've put useCsrf() in my app.vue and also tried adding it to the page with the form.... It's unclear from the minimal readme exactly how to use the composables, so I've just been trying all sorts.

chrisnoden commented 1 year ago

Follow-up:

I use the Brave browser and it is blocking the csrf-token somehow. Disabling the shields on the browser and it seems to work.

However, useCsrfFetch() is not a drop-in replacement for $fetch(). The changes to the behaviour are significant enough that I'll have to refactor every place I've got a POST request.

I tried this instead:

    const { csrf } = useCsrf();
    $fetch(`/api/login`, {
        method: 'POST',
        body: {
            email: emailAddress.value,
            password: password.value,
            remember: rememberMe.value,
        },
        headers: {
            'csrf-token': csrf,
        }
    })
        .then(({user, session}) => {... success code}
        .catch((error) => {
            if (/(CSRF Token Mismatch)/.test(error.message)) {
               // suggest user disables their browser shields/privacy extensions
            }
        })

But this still leaves the csrf value as undefined (whether the Brave shields are enabled or not). I wanted to be able to intercept the error to prompt the user they may need to disable their browser privacy extension. Trying to solve this with useCsrfFetch requires a lot more work because the promise behaves quite differently.

Why does the useCsrf() composable not work in this code?

chrisnoden commented 1 year ago

Further:

In addition to the approach above, where I obviously need to extract the value of the csrf token for the headers, I've added useCsrf() in my app.vue. I'm guessing this initialises the token from the server.

This approach seems to be working for me now.

github-actions[bot] commented 1 year ago

:tada: This issue has been resolved in version 1.1.0 :tada:

The release is available on:

Your semantic-release bot :package::rocket:

Morgbn commented 1 year ago

Hello Chris,

I just released a new version that adds the function $csrfFetch. I hope this will help to switch to request with csrf more easily

chrisnoden commented 1 year ago

That's great. Many thanks @Morgbn - I'll give it a try.

ankita2104 commented 9 months ago

Hello Chris,

I just released a new version that adds the function $csrfFetch. I hope this will help to switch to request with csrf more easily

Why does the $csrfFetch() composable not working in the latest version?

Morgbn commented 9 months ago

Why does the $csrfFetch() composable not working in the latest version?

Hello @ankita2104, please submit a new issue with a reproduction link