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

@@ -15,7 +15,10 @@ import Spinner from '../assets/spinner.svg';
import RetryIcon from '../components/RetryIcon';
import { useDarkTheme, useMediaQuery } from '../hooks';
import { ShareConversationModal } from '../modals/ShareConversationModal';
import { selectConversationId } from '../preferences/preferenceSlice';
import {
selectConversationId,
selectToken,
} from '../preferences/preferenceSlice';
import { AppDispatch } from '../store';
import ConversationBubble from './ConversationBubble';
import { handleSendFeedback } from './conversationHandlers';
@@ -34,6 +37,7 @@ import Upload from '../upload/Upload';
import { ActiveState } from '../models/misc';
export default function Conversation() {
const token = useSelector(selectToken);
const queries = useSelector(selectQueries);
const navigate = useNavigate();
const status = useSelector(selectStatus);
@@ -161,6 +165,7 @@ export default function Conversation() {
feedback,
conversationId as string,
index,
token,
).catch(() =>
handleSendFeedback(
query.prompt,
@@ -168,6 +173,7 @@ export default function Conversation() {
feedback,
conversationId as string,
index,
token,
).catch(() =>
dispatch(updateQuery({ index, query: { feedback: prevFeedback } })),
),

View File

@@ -6,6 +6,7 @@ import { ToolCallsType } from './types';
export function handleFetchAnswer(
question: string,
signal: AbortSignal,
token: string | null,
selectedDocs: Doc | null,
history: Array<any> = [],
conversationId: string | null,
@@ -52,7 +53,7 @@ export function handleFetchAnswer(
}
payload.retriever = selectedDocs?.retriever as string;
return conversationService
.answer(payload, signal)
.answer(payload, token, signal)
.then((response) => {
if (response.ok) {
return response.json();
@@ -76,6 +77,7 @@ export function handleFetchAnswer(
export function handleFetchAnswerSteaming(
question: string,
signal: AbortSignal,
token: string | null,
selectedDocs: Doc | null,
history: Array<any> = [],
conversationId: string | null,
@@ -109,7 +111,7 @@ export function handleFetchAnswerSteaming(
return new Promise<Answer>((resolve, reject) => {
conversationService
.answerStream(payload, signal)
.answerStream(payload, token, signal)
.then((response) => {
if (!response.body) throw Error('No response body');
@@ -160,6 +162,7 @@ export function handleFetchAnswerSteaming(
export function handleSearch(
question: string,
token: string | null,
selectedDocs: Doc | null,
conversation_id: string | null,
history: Array<any> = [],
@@ -185,7 +188,7 @@ export function handleSearch(
payload.active_docs = selectedDocs.id as string;
payload.retriever = selectedDocs?.retriever as string;
return conversationService
.search(payload)
.search(payload, token)
.then((response) => response.json())
.then((data) => {
return data;
@@ -206,11 +209,14 @@ export function handleSearchViaApiKey(
};
});
return conversationService
.search({
question: question,
history: JSON.stringify(history),
api_key: api_key,
})
.search(
{
question: question,
history: JSON.stringify(history),
api_key: api_key,
},
null,
)
.then((response) => response.json())
.then((data) => {
return data;
@@ -224,15 +230,19 @@ export function handleSendFeedback(
feedback: FEEDBACK,
conversation_id: string,
prompt_index: number,
token: string | null,
) {
return conversationService
.feedback({
question: prompt,
answer: response,
feedback: feedback,
conversation_id: conversation_id,
question_index: prompt_index,
})
.feedback(
{
question: prompt,
answer: response,
feedback: feedback,
conversation_id: conversation_id,
question_index: prompt_index,
},
token,
)
.then((response) => {
if (response.ok) {
return Promise.resolve();
@@ -265,7 +275,7 @@ export function handleFetchSharedAnswerStreaming( //for shared conversations
save_conversation: false,
};
conversationService
.answerStream(payload, signal)
.answerStream(payload, null, signal)
.then((response) => {
if (!response.body) throw Error('No response body');
@@ -339,6 +349,7 @@ export function handleFetchSharedAnswer(
question: question,
api_key: apiKey,
},
null,
signal,
)
.then((response) => {

View File

@@ -42,6 +42,7 @@ export const fetchAnswer = createAsyncThunk<
await handleFetchAnswerSteaming(
question,
signal,
state.preference.token,
state.preference.selectedDocs!,
state.conversation.queries,
state.conversation.conversationId,
@@ -53,7 +54,7 @@ export const fetchAnswer = createAsyncThunk<
if (data.type === 'end') {
dispatch(conversationSlice.actions.setStatus('idle'));
getConversations()
getConversations(state.preference.token)
.then((fetchedConversations) => {
dispatch(setConversations(fetchedConversations));
})
@@ -114,6 +115,7 @@ export const fetchAnswer = createAsyncThunk<
const answer = await handleFetchAnswer(
question,
signal,
state.preference.token,
state.preference.selectedDocs!,
state.conversation.queries,
state.conversation.conversationId,
@@ -150,7 +152,7 @@ export const fetchAnswer = createAsyncThunk<
}),
);
dispatch(conversationSlice.actions.setStatus('idle'));
getConversations()
getConversations(state.preference.token)
.then((fetchedConversations) => {
dispatch(setConversations(fetchedConversations));
})