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: _auth and _refresh cookies received on login api call no cookies are sent with with "user" info request, thus, no authentication happens

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)
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. Commented Jan 26 at 20:59

1 Answer 1

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 :(")
    }
})();
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.