vimalloc / flask-jwt-extended

An open source Flask extension that provides JWT support (with batteries included)!
http://flask-jwt-extended.readthedocs.io/en/stable/
MIT License
1.56k stars 239 forks source link

Issue setting csrf_refresh_cookie #508

Closed nullwiz closed 1 year ago

nullwiz commented 1 year ago

Hello! First of all thanks for this amazing library. I am sure the dev has come across many times these kinds of questions. So I am sorry in advance! :)

I am finding that, the CSRF token , even after the Set-Cookie has been sent, is not being show at the JS level. The CSRF token does not have Http only.

See:

set-cookie: csrf_access_token=d1a63933-653d-4659-b397-fc29341a7231; Secure; Path=/; SameSite=None set-cookie: csrf_refresh_token=f8531601-b9b0-4b8f-bf23-1790249af6ab; Secure; Path=/; SameSite=None set-cookie: refresh_token_cookie=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTY4MTM4OTQxMSwianRpIjoiMGQ4Y2U0NjItZDVmZi00YmM5LWIzZjYtNDFmYTc5OTVlMzEzIiwidHlwZSI6InJlZnJlc2giLCJzdWIiOiI3YTY0N2EwNi03YjMzLTQwMjctODE2ZS1jY2RiMjUzMjg2YmUiLCJuYmYiOjE2ODEzODk0MTEsImNzcmYiOiJmODUzMTYwMS1iOWIwLTRiOGYtYmYyMy0xNzkwMjQ5YWY2YWIiLCJleHAiOjE2ODM5ODE0MTEsInJvbGUiOiJhZG1pbiIsImVtYWlsIjoiZGVmYXVsdGFkbWluQGFkbWluLmFzIiwiaWQiOiI3YTY0N2EwNi03YjMzLTQwMjctODE2ZS1jY2RiMjUzMjg2YmUifQ.cyMLI4Omztwmb6kvWC-qm8D9KSxkQGhP7j7o534QX4c; Secure; HttpOnly; Path=/; SameSite=None set-cookie: access_token_cookie=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTY4MTM4OTQxMSwianRpIjoiOTk4ZDNkYTctMWJjNC00YjkzLTllZmItMjU0NTljOGMyZDkxIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6IjdhNjQ3YTA2LTdiMzMtNDAyNy04MTZlLWNjZGIyNTMyODZiZSIsIm5iZiI6MTY4MTM4OTQxMSwiY3NyZiI6ImQxYTYzOTMzLTY1M2QtNDY1OS1iMzk3LWZjMjkzNDFhNzIzMSIsImV4cCI6MTY4MTM5MzAxMSwicm9sZSI6ImFkbWluIiwiZW1haWwiOiJkZWZhdWx0YWRtaW5AYWRtaW4uYXMiLCJpZCI6IjdhNjQ3YTA2LTdiMzMtNDAyNy04MTZlLWNjZGIyNTMyODZiZSJ9.lMwhZ9EtV0k0Eoxv6hqzxB8e_8w5HTt0hvhB5TDP8Qc; Secure; HttpOnly; Path=/; SameSite=None strict-transport-security: max-age=31556926; includeSubDomains x-content-type-options: nosniff x-frame-options: SAMEORIGIN x-xss-protection: 1; mode=block

If I go to the cookies tab, it's just not there. The frontend can, however, send the rest of the secure httponly cookies.

I have to come up with a different implementation in the frontend/backend in order to bypass and ask for a refresh token to the backend, which I know it is a security risk and shouldn't be done.

My frontend uses axios, after loggin in:


export const login = async (email, password) => {
  const response = await axios.post(
    '/login',
    {
      email,
      password,
    },
    {
      baseURL: API_BASE_URL,
      withCredentials: true,
    }
  )

  if (response.status === 200) {
    axios.defaults.headers.common['X-CSRF-TOKEN'] =
      Cookies.get('csrf_access_token')
  }
  return response
}

The next request interceptor is used to other operations (you see how I bypassed the csrf by calling getCsrfToken()


axiosInstance.interceptors.request.use(
  async (config) => {
    // Set cookies
    let token_cookie = Cookies.get('csrf_access_token')
    const token_expiration = localStorage.getItem('csrf_token_expiration')

    if (
      !token_cookie ||
      (token_expiration && new Date() > new Date(token_expiration))
    ) {
      token_cookie = await getCsrfToken()
      // Store the new token expiration time
      const new_expiration_time = new Date()
      new_expiration_time.setMinutes(new_expiration_time.getMinutes() + 5)
      localStorage.setItem('csrf_token_expiration', new_expiration_time)
    }

    config.headers['X-CSRF-TOKEN'] = token_cookie
    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

I know this might be a chrome issue. I tried on chrome, mobile, firefox, safari. They all have the same issue: the cookie is not set.

strikeitbroke commented 1 year ago

did you set the JWT_TOKEN_LOCATION to cookies? I'm currently using the cookies to store tokens, and I am able to get csrf in the frontend (shows up in the cookies section under storage in firefox).

vimalloc commented 1 year ago

Odd, the CSRF cookie should be showing up. If you make a request on the command line do you see the Set-Cookie being sent in there?

A couple other things to check. Do you have JWT_COOKIE_CSRF_PROTECT set to True, and JWT_CSRF_IN_COOKIES set to True? Those should be the default values, but if those aren't set then that might explain why you are not seeing the csrf cookies.

Sorry for the delay in getting back to you here, things have been absolutely hectic on my end recently 😅