How do I properly implement DRF TokenAuthentication without the request object returning an anonymous user when I try to log in?
according to the docs, when authenticated, the TokenAuthentication
object provides the request.user
which is the Django user instance and the request.auth
which is the token instance. But even after authentication, request.user
returns anonymouse user.
What could I be doing wrong?
Client request:
//function to get token
export default function axiosConfig() {
// request header
const headers = {
"Content-Type": "application/json"
}
// Get token from local storage. Token is stored when user registers.
const token = localStorage.getItem("token");
if (token) headers["Authorisation"] = `Token ${token}`;
return headers;
}
Redux action
import axiosConfig from "../../utils/axiosConfig";
const config = axiosConfig
export const login = (email, password) => (dispatch, getState) => {
const body = { email, password };
// Change to absoulte path when deploying to production
axios
.post("http://localhost:8000/api/auth/login", body, config())
.then((res) => {
dispatch({
type: SIGN_IN_SUCCESFUL,
payload: res.data,
});
console.log(res);
})
.catch((err) => {
dispatch({
type: SIGN_IN_FAIL,
payload: err.response,
});
console.log(err.response.data, err.response.status);
});
};
url:
from django.urls import path
from authentication.views import RegisterationView
from authentication.views import LoginView
from authentication.views import LogoutView
urlpatterns = [
path("auth/register", RegisterationView.as_view()),
path("auth/login", LoginView.as_view()),
path("auth/logout/<int:id>", LogoutView.as_view()),
]
Serializer:
The LoginResponseSerializer
is used to provide response data to the client
class LoginSerializer(serializers.Serializer):
"""Login serializer"""
username = serializers.CharField()
password = serializers.CharField(required=True)
class LoginResponseSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = [
"id",
"username",
"first_name",
"last_name",
"email",
"is_active",
"is_staff",
]
read_only_fields = ["id", "is_active", "is_staff"]
View:
class LoginView(APIView):
"""Login View"""
permision_classs = [permissions.AllowAny]
def post(self, request):
serializer = LoginSerializer(data=request.data)
if serializer.is_valid():
print(serializer.data) # Data is present
user = authenticate(request, **serializer.data) # Valid credentials. User object is returned.
response_serializer = LoginResponseSerializer(user)
if user is not None and login(request, user):
print(request.user) # User is anonymous
token, created_token = Token.objects.get_or_create(user_id=user.id)
if isinstance(created_token, Token):
token = created_token
return Response(
{
"user": response_serializer.data,
"status": {
"message": "user authenticated",
"code": status.HTTP_200_OK,
},
"token": token.key,
}
)
raise serializers.ValidationError(
"Invalid Username or Password. Please try again"
)
return Response(
{"error": serializer.errors, "status": status.HTTP_403_FORBIDDEN}
)
Since you are using Token authentication, your users will be authenticated with the token in the header, for each request.
Django login()
is useful in case of SessionAuthentication. Where user is stored in the session object in django, identified by the session cookie.
In your view, you don't have to call the login method. Just return the token
and whatever extra information you want. And make sure you are sending this token
in every request to authenticate this user.
EDIT:
And the clarification about the request.user
in the documentation of DRF, is about accessing the authenticated user in the other view where you provide token in headers.