3

I use django rest_framework_simplejwt package to generate JWT tokens and set them in browsable cookie with Httponly flag. At the Django side it work perfectly but at react side it does not work perfectly. I read many answers related to this question like this and this but they have not solved my problem yet. Please help me understand where I'm wrong.

DJANGO SIDE

views.py

from rest_framework_simplejwt.views import TokenObtainPairView
from django.conf import settings

from rest_framework import status
from rest_framework_simplejwt.exceptions import TokenError,\
    InvalidToken
from rest_framework.response import Response

class MyTokenObtainPairView(TokenObtainPairView):
    
    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)

        try:
            serializer.is_valid(raise_exception=True)
        except TokenError as e:
            raise InvalidToken(e.args[0])
           
          # set access token in browser with Httponly cookie.
        res = Response(serializer.validated_data, status=status.HTTP_200_OK)
        access_token = serializer.validated_data['access']
        res.set_cookie("access_token", access_token, max_age=settings.SIMPLE_JWT.get('ACCESS_TOKEN_LIFETIME').total_seconds(),samesite='Lax',secure=False, httponly=True)
        
        return res

authentication.py

from rest_framework_simplejwt.authentication import JWTAuthentication    
from django.conf import settings

class CookieHandlerJWTAuthentication(JWTAuthentication):
    def authenticate(self, request):
        # If cookie contains access token, put it inside authorization header
        access_token = request.COOKIES.get('access_token')
        if(access_token):
            request.META['HTTP_AUTHORIZATION'] = '{header_type} {access_token}'.format(
                header_type=settings.SIMPLE_JWT['AUTH_HEADER_TYPES'][0], access_token=access_token)

        return super().authenticate(request)

urls.py

from .views import MyTokenObtainPairView

urlpatterns = [
    ......
    path('auth/', include('djoser.urls')),
    # path('auth/', include('djoser.urls.jwt')),
    
    path('auth/api/token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
]

settings.py

CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
    'http://localhost:3000',
    'http://127.0.0.1:8000'
)

Work perfectly(Token set in cookie with Httponly.):

REACTJS SIDE

Login.js

axios.defaults.withCredentials = true
const Login = () => {

const [ivalue, setValue] = useState({});
const { state, dispatch } = useContext(Authcontext);
.......

const loginClick = (e) => {
    e.preventDefault();
    setLoader(true);

    axios.post('http://127.0.0.1:8000/auth/api/token/', {
        username: ivalue.username,
        password: ivalue.password,
    })
        .then((res) => {
            setValue({ password: "" });

            dispatch({
                type: LOGIN_SUCCESS,
            });

            setLoader(false);
 
            history.push("/my_profile");
        })
        .catch((err) => {
            setLoader(false);
            setOpen({ act: true, msg: "error" });

            dispatch({
                type: LOGIN_ERROR,
            });
            setError(err.response.data);
        });
};
.........
};

Myprofile.js

axios.defaults.withCredentials = true

const MyProfile = () => {

    const history = useHistory();
    const { state, dispatch } = useContext(Authcontext);

    useEffect(() => {
        const auth_check = () => {
                axios.get('http://127.0.0.1:8000/auth/users/me/')
                    .then((res) => {
                        dispatch({
                            type: AFTER_LOGIN,
                            payload: res.data
                        });
                    })
                    .catch((err) => {
                        history.push('/login')
                    });
                    };
        auth_check();
    }, []);
}
.......

JWT Response(cookie not set in browser).

Unauthorized Error

Jalal
  • 334
  • 1
  • 4
  • 16
Pradip Kachhadiya
  • 2,067
  • 10
  • 28

2 Answers2

0

I set backend and frontend under same IP. ex. my backend is

localhost:8000

and frontend is

localhost:3000

different ports same Ip.

This is not the scenario when it goes to production you can have any domain.

Pradip Kachhadiya
  • 2,067
  • 10
  • 28
0

You are getting a samesite=Lax value in your set-cookie header try using CSRF_COOKIE_SECURE = True, SESSION_COOKIE_SECURE = True, CSRF_COOKIE_SAMESITE = 'None', SESSION_COOKIE_SAMESITE = 'None' this will let browser to set cookies even from a different domain. and use withCredentials: true on your client side.