From 5c3fdc13548dbd7bc4bcb930fdcbd48a7bc176e7 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Thu, 15 May 2025 14:12:31 -0500 Subject: [PATCH] Enhance JWT authentication error handling and user redirection on token issues. --- dispatcharr/jwt_ws_auth.py | 19 +++++++++++++++---- frontend/src/App.jsx | 6 ++++++ frontend/src/api.js | 35 ++++++++++++++++++++++------------- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/dispatcharr/jwt_ws_auth.py b/dispatcharr/jwt_ws_auth.py index 3c7afeab..b478cd6f 100644 --- a/dispatcharr/jwt_ws_auth.py +++ b/dispatcharr/jwt_ws_auth.py @@ -6,7 +6,9 @@ from django.contrib.auth.models import AnonymousUser from django.contrib.auth import get_user_model from rest_framework_simplejwt.exceptions import InvalidToken, TokenError from rest_framework_simplejwt.authentication import JWTAuthentication +import logging +logger = logging.getLogger(__name__) User = get_user_model() @database_sync_to_async @@ -15,7 +17,11 @@ def get_user(validated_token): jwt_auth = JWTAuthentication() user = jwt_auth.get_user(validated_token) return user - except: + except User.DoesNotExist: + logger.warning(f"User from token does not exist. User ID: {validated_token.get('user_id', 'unknown')}") + return AnonymousUser() + except Exception as e: + logger.error(f"Error getting user from token: {str(e)}") return AnonymousUser() class JWTAuthMiddleware(BaseMiddleware): @@ -26,11 +32,16 @@ class JWTAuthMiddleware(BaseMiddleware): token = query_string.get("token", [None])[0] if token is not None: - validated_token = JWTAuthentication().get_validated_token(token) - scope["user"] = await get_user(validated_token) + try: + validated_token = JWTAuthentication().get_validated_token(token) + scope["user"] = await get_user(validated_token) + except (InvalidToken, TokenError) as e: + logger.warning(f"Invalid token: {str(e)}") + scope["user"] = AnonymousUser() else: scope["user"] = AnonymousUser() - except (InvalidToken, TokenError): + except Exception as e: + logger.error(f"Error in JWT authentication: {str(e)}") scope["user"] = AnonymousUser() return await super().__call__(scope, receive, send) diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 1c032ab3..7295d12e 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -57,6 +57,12 @@ const App = () => { } } catch (error) { console.error('Error checking superuser status:', error); + // If authentication error, redirect to login + if (error.status === 401) { + localStorage.removeItem('token'); + localStorage.removeItem('refreshToken'); + window.location.href = '/login'; + } } } checkSuperuser(); diff --git a/frontend/src/api.js b/frontend/src/api.js index 60b22634..7a378262 100644 --- a/frontend/src/api.js +++ b/frontend/src/api.js @@ -103,14 +103,13 @@ export default class API { static async fetchSuperUser() { try { - const response = await request( - `${host}/api/accounts/initialize-superuser/`, - { auth: false } - ); - - return response; - } catch (e) { - errorNotification('Failed to fetch superuser', e); + return await request(`${host}/api/accounts/initialize-superuser/`, { + auth: false, + method: 'GET', + }); + } catch (error) { + console.error('Error checking superuser status:', error); + throw error; } } @@ -150,11 +149,21 @@ export default class API { } static async refreshToken(refresh) { - return await request(`${host}/api/accounts/token/refresh/`, { - auth: false, - method: 'POST', - body: { refresh }, - }); + try { + return await request(`${host}/api/accounts/token/refresh/`, { + auth: false, + method: 'POST', + body: { refresh }, + }); + } catch (error) { + // If user does not exist or token is invalid, clear tokens + if (error.status === 401 || error.message?.includes('does not exist')) { + localStorage.removeItem('token'); + localStorage.removeItem('refreshToken'); + window.location.href = '/login'; // Redirect to login + } + throw error; + } } static async logout() {