最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

auth cookie not sent from browser to django backend - Stack Overflow

programmeradmin3浏览0评论

I have a Django backend that uses allauth and simplejwt (both provided by dj-rest-auth) for authentication. When I make API requests using an API client (Bruno), my auth cookies containing JWT tokens are passed, and the server responds. But, I can't achieve the same thing in JS from the browser.

The authentication cookies are received, but not passed in subsequent requests:

minimal front-end JS:

(async () => {
    console.log("logging in...")

    const loginResponse = await fetch('http://127.0.0.1:8000/api/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            username: 'test',
            password: 'securepassword123'
        })
    })
    const loginData = await loginResponse.json();
    // response contains `set-cookie` headers
    // vv prints JSON containing "access", "refresh", "username", etc.
    console.log(loginData)

    if (!loginResponse.ok) {
        console.log('login failed :(')
        return
    }

    console.log("getting user info...")

    const userResponse = await fetch('http://127.0.0.1:8000/api/user', {
        credentials: 'include'
    });
    const userData = await userResponse.json();
    // vv prints `{detail: 'Authentication credentials were not provided.'}`
    console.log(userData)
    if (!userResponse.ok) {
        console.log("user data fetch failed :(")
    }
})();

I've already set up CORS, allow-credentials, etc. in Django:

# dj-rest-auth settings ---------------------------------
# src: /@michal.drozdze/django-rest-apis-with-jwt-authentication-using-dj-rest-auth-781a536dfb49
SITE_ID = 1
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'dj_rest_auth.jwt_auth.JWTCookieAuthentication',
    )
}

# djangorestframework-simplejwt
SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(hours=1),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1),
}

# dj-rest-auth
REST_AUTH = {
    "USE_JWT": True,
    "JWT_AUTH_COOKIE": "_auth",  # Name of access token cookie
    "JWT_AUTH_REFRESH_COOKIE": "_refresh", # Name of refresh token cookie
    "JWT_AUTH_HTTPONLY": False,  # Makes sure refresh token is sent
}

# cors ---------------------------------
# src: /
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_HEADERS = (
    *default_headers,
)
CORS_ALLOW_CREDENTIALS = True
SESSION_COOKIE_SAMESITE = 'None'

minimal reproducible example:

  • install django
  • follow this tutorial to set up dj-rest-auth
  • create a user
  • run the attached script in your front end (e.g. a script tag in html)

I have a Django backend that uses allauth and simplejwt (both provided by dj-rest-auth) for authentication. When I make API requests using an API client (Bruno), my auth cookies containing JWT tokens are passed, and the server responds. But, I can't achieve the same thing in JS from the browser.

The authentication cookies are received, but not passed in subsequent requests:

minimal front-end JS:

(async () => {
    console.log("logging in...")

    const loginResponse = await fetch('http://127.0.0.1:8000/api/login', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            username: 'test',
            password: 'securepassword123'
        })
    })
    const loginData = await loginResponse.json();
    // response contains `set-cookie` headers
    // vv prints JSON containing "access", "refresh", "username", etc.
    console.log(loginData)

    if (!loginResponse.ok) {
        console.log('login failed :(')
        return
    }

    console.log("getting user info...")

    const userResponse = await fetch('http://127.0.0.1:8000/api/user', {
        credentials: 'include'
    });
    const userData = await userResponse.json();
    // vv prints `{detail: 'Authentication credentials were not provided.'}`
    console.log(userData)
    if (!userResponse.ok) {
        console.log("user data fetch failed :(")
    }
})();

I've already set up CORS, allow-credentials, etc. in Django:

# dj-rest-auth settings ---------------------------------
# src: https://medium.com/@michal.drozdze/django-rest-apis-with-jwt-authentication-using-dj-rest-auth-781a536dfb49
SITE_ID = 1
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'dj_rest_auth.jwt_auth.JWTCookieAuthentication',
    )
}

# djangorestframework-simplejwt
SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(hours=1),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1),
}

# dj-rest-auth
REST_AUTH = {
    "USE_JWT": True,
    "JWT_AUTH_COOKIE": "_auth",  # Name of access token cookie
    "JWT_AUTH_REFRESH_COOKIE": "_refresh", # Name of refresh token cookie
    "JWT_AUTH_HTTPONLY": False,  # Makes sure refresh token is sent
}

# cors ---------------------------------
# src: https://pypi.org/project/django-cors-headers/
CORS_ALLOW_ALL_ORIGINS = True
CORS_ALLOW_HEADERS = (
    *default_headers,
)
CORS_ALLOW_CREDENTIALS = True
SESSION_COOKIE_SAMESITE = 'None'

minimal reproducible example:

  • install django
  • follow this tutorial to set up dj-rest-auth
  • create a user
  • run the attached script in your front end (e.g. a script tag in html)
Share Improve this question edited Jan 19 at 17:27 Ashkan Arabi asked Jan 19 at 9:38 Ashkan ArabiAshkan Arabi 1192 silver badges9 bronze badges 1
  • Okay the issue was that my browser wasn't saving my cookie. I had to modify my login request on the front end to fix it. See this answer. I'll answer this question once I confirm everything works. – Ashkan Arabi Commented Jan 26 at 20:59
Add a comment  | 

1 Answer 1

Reset to default 0

Turns out that my main issue was that the cookies sent by the login endpint were not being saved in my browser. I should have checked that first to make this question clearer. To fix that, I had to modify the /api/login request I was making on the front end to also have credentials: 'include'. This is because by default, when dealing with cross-origin api calls, received cookies are not saved. See this answer.

My fixed simple front-end script looks like this:

(async () => {
    console.log("logging in...")

    const loginResponse = await fetch('http://127.0.0.1:8000/api/login', {
        credentials: 'include', // <------------------------ NEW
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            username: 'test',
            password: 'securepassword123'
        })
    })
    const loginData = await loginResponse.json();
    console.log(loginData)

    if (!loginResponse.ok) {
        console.log('login failed :(')
        return
    }

    console.log("getting user info...")

    const userResponse = await fetch('http://127.0.0.1:8000/api/user', {
        credentials: 'include'
    });
    const userData = await userResponse.json();
    console.log(userData)
    if (!userResponse.ok) {
        console.log("user data fetch failed :(")
    }
})();
发布评论

评论列表(0)

  1. 暂无评论