feat: implement JWT authentication and token management in frontend and backend

This commit is contained in:
Siddhant Rai
2025-03-14 17:07:15 +05:30
parent fe02bf9347
commit 7fd377bdbe
17 changed files with 453 additions and 178 deletions

View File

@@ -2,28 +2,34 @@ import { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import { NavLink, useNavigate } from 'react-router-dom';
import conversationService from './api/services/conversationService';
import userService from './api/services/userService';
import Add from './assets/add.svg';
import openNewChat from './assets/openNewChat.svg';
import Hamburger from './assets/hamburger.svg';
import DocsGPT3 from './assets/cute_docsgpt3.svg';
import Discord from './assets/discord.svg';
import Expand from './assets/expand.svg';
import Github from './assets/github.svg';
import Hamburger from './assets/hamburger.svg';
import openNewChat from './assets/openNewChat.svg';
import SettingGear from './assets/settingGear.svg';
import SpinnerDark from './assets/spinner-dark.svg';
import Spinner from './assets/spinner.svg';
import Twitter from './assets/TwitterX.svg';
import UploadIcon from './assets/upload.svg';
import Help from './components/Help';
import SourceDropdown from './components/SourceDropdown';
import {
handleAbort,
selectQueries,
setConversation,
updateConversationId,
handleAbort,
} from './conversation/conversationSlice';
import ConversationTile from './conversation/ConversationTile';
import { useDarkTheme, useMediaQuery } from './hooks';
import useDefaultDocument from './hooks/useDefaultDocument';
import DeleteConvModal from './modals/DeleteConvModal';
import JWTModal from './modals/JWTModal';
import { ActiveState, Doc } from './models/misc';
import { getConversations, getDocs } from './preferences/preferenceApi';
import {
@@ -31,20 +37,17 @@ import {
selectConversationId,
selectConversations,
selectModalStateDeleteConv,
selectPaginatedDocuments,
selectSelectedDocs,
selectSourceDocs,
selectPaginatedDocuments,
selectToken,
setConversations,
setModalStateDeleteConv,
setPaginatedDocuments,
setSelectedDocs,
setSourceDocs,
setPaginatedDocuments,
} from './preferences/preferenceSlice';
import Spinner from './assets/spinner.svg';
import SpinnerDark from './assets/spinner-dark.svg';
import { selectQueries } from './conversation/conversationSlice';
import Upload from './upload/Upload';
import Help from './components/Help';
interface NavigationProps {
navOpen: boolean;
@@ -53,6 +56,7 @@ interface NavigationProps {
export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
const dispatch = useDispatch();
const token = useSelector(selectToken);
const queries = useSelector(selectQueries);
const docs = useSelector(selectSourceDocs);
const selectedDocs = useSelector(selectSelectedDocs);
@@ -70,6 +74,8 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
const [uploadModalState, setUploadModalState] =
useState<ActiveState>('INACTIVE');
const [authKeyModalState, setAuthKeyModalState] =
useState<ActiveState>('INACTIVE');
const navRef = useRef(null);
@@ -86,7 +92,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
async function fetchConversations() {
dispatch(setConversations({ ...conversations, loading: true }));
return await getConversations()
return await getConversations(token)
.then((fetchedConversations) => {
dispatch(setConversations(fetchedConversations));
})
@@ -99,7 +105,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
const handleDeleteAllConversations = () => {
setIsDeletingConversation(true);
conversationService
.deleteAll()
.deleteAll(token)
.then(() => {
fetchConversations();
})
@@ -109,7 +115,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
const handleDeleteConversation = (id: string) => {
setIsDeletingConversation(true);
conversationService
.delete(id, {})
.delete(id, {}, token)
.then(() => {
fetchConversations();
resetConversation();
@@ -119,9 +125,9 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
const handleDeleteClick = (doc: Doc) => {
userService
.deletePath(doc.id ?? '')
.deletePath(doc.id ?? '', token)
.then(() => {
return getDocs();
return getDocs(token);
})
.then((updatedDocs) => {
dispatch(setSourceDocs(updatedDocs));
@@ -145,7 +151,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
const handleConversationClick = (index: string) => {
conversationService
.getConversation(index)
.getConversation(index, token)
.then((response) => response.json())
.then((data) => {
navigate('/');
@@ -177,7 +183,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
id: string;
}) {
await conversationService
.update(updatedConversation)
.update(updatedConversation, token)
.then((response) => response.json())
.then((data) => {
if (data) {
@@ -197,6 +203,14 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
useEffect(() => {
setNavOpen(!isMobile);
}, [isMobile]);
useEffect(() => {
const authToken = localStorage.getItem('authToken');
if (!authToken) {
setAuthKeyModalState('ACTIVE');
}
}, []);
useDefaultDocument();
return (
@@ -470,6 +484,10 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) {
close={() => setUploadModalState('INACTIVE')}
></Upload>
)}
<JWTModal
modalState={authKeyModalState}
setModalState={setAuthKeyModalState}
/>
</>
);
}