Is this djoser implementation secure?
This question may be too broad for StackOverflow, but I'm not sure where else to go for help.
I wrote a simple authentication system in Django with Djoser and its JWT implementation, using jQuery on the frontend. I really don't know what I'm doing though, and I'm about 99% sure I did it wrong and it's totally insecure.
First, when a user submits the login form, I send a POST request to retrieve a refresh token and an access token. The refresh token is stored as a cookie, and the access token is stored in sessionStorage:
// Post the form
$.post("/auth/jwt/create/", $(this).serialize())
// Success: store tokens & redirect
.done(function(data) {
// Logged in: set redirect path & store tokens
if (data.refresh !== "undefined" && data.access !== "undefined") {
Cookies.set("refresh_token", data.refresh, { expires: 30, secure: true, sameSite: "strict" });
sessionStorage.setItem("access_token", data.access);
}
})
I have another simple script that runs every time a page is loaded. There, I verify the access token, attempt a refresh if it's invalid, fetch user data using the access token, then post that user data to the backend to login. This script also logs the user out if on the logout page:
// Log in or out
function auth(data) {
$.post("/auth/", {
"user": data,
"csrfmiddlewaretoken": $("meta[name='csrf-token']").attr("content"),
});
}
// Remove tokens & log out
function logout() {
Cookies.remove("refresh_token");
sessionStorage.removeItem("access_token");
auth("");
}
// Authorize: get user data & log in
function authorize() {
$.ajax({
url: "/auth/users/me/",
headers: { "Authorization": "JWT "+sessionStorage.getItem("access_token") },
})
// Success: log in
.done(function(data) { auth(JSON.stringify(data)); })
// Fail: log out
.fail(function() { logout(); });
}
// Verify access token & authorize
function verify() {
$.post("/auth/jwt/verify/", { "token": sessionStorage.getItem("access_token") })
// Success: authorize
.done(function() { authorize(); })
// Fail: refresh access token
.fail(function() {
$.post("/auth/jwt/refresh/", { "refresh": Cookies.get("refresh_token") })
// Success: store new access token & authorize
.done(function(data) {
sessionStorage.setItem("access_token", data.access);
authorize();
})
// Fail: log out
.fail(function() { logout(); });
});
}
// Log out page
if (window.location.pathname == "/logout/") {
logout();
}
// Attempt login
else verify();
Finally, on the backend I log the user in or out with Django's native login
and logout
:
def auth(request):
if not request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' or not request.method=="POST":
return HttpResponseNotAllowed(["POST"])
user_post = request.POST.get("user")
user = None
if user_post != "":
user_post = json.loads(user_post)
if "id" in user_post and "username" in user_post and "email" in user_post:
user = User.objects.filter(id=user_post["id"], username=user_post["username"], email=user_post["email"]).first()
if user == None:
logout(request)
return HttpResponse("User logged out.")
else:
login(request, user)
return HttpResponse("User logged in.")
What I'm most worried about is the part where a simple POST request can log a user in with only its id, username and email. Although I'm going to keep the id hidden from the public, if a hacker does obtain it somehow (or just guesses it), they could easily bypass the need for a password or any tokens.