diff --git a/backend/src/server/routes/v1/auth-router.ts b/backend/src/server/routes/v1/auth-router.ts index 4465053ea..04ca958c6 100644 --- a/backend/src/server/routes/v1/auth-router.ts +++ b/backend/src/server/routes/v1/auth-router.ts @@ -1,5 +1,6 @@ import jwt from "jsonwebtoken"; import { z } from "zod"; + import { getConfig } from "@app/lib/config/env"; import { authRateLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; diff --git a/backend/src/services/auth-token/auth-token-service.ts b/backend/src/services/auth-token/auth-token-service.ts index 67920acf1..2468e3c8a 100644 --- a/backend/src/services/auth-token/auth-token-service.ts +++ b/backend/src/services/auth-token/auth-token-service.ts @@ -1,7 +1,7 @@ import crypto from "node:crypto"; -import jwt from "jsonwebtoken"; import bcrypt from "bcrypt"; +import jwt from "jsonwebtoken"; import { Knex } from "knex"; import { TAuthTokens, TAuthTokenSessions } from "@app/db/schemas"; @@ -101,40 +101,6 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, orgMembershipDAL }: TAu return token; }; - const validateRefreshToken = async (refreshToken?: string) => { - const appCfg = getConfig(); - if (!refreshToken) - throw new NotFoundError({ - name: "AuthTokenNotFound", - message: "Failed to find refresh token" - }); - - const decodedToken = jwt.verify(refreshToken, appCfg.AUTH_SECRET) as AuthModeRefreshJwtTokenPayload; - - if (decodedToken.authTokenType !== AuthTokenType.REFRESH_TOKEN) - throw new UnauthorizedError({ - message: "The token provided is not a refresh token", - name: "InvalidToken" - }); - - const tokenVersion = await getUserTokenSessionById(decodedToken.tokenVersionId, decodedToken.userId); - - if (!tokenVersion) - throw new UnauthorizedError({ - message: "Valid token version not found", - name: "InvalidToken" - }); - - if (decodedToken.refreshVersion !== tokenVersion.refreshVersion) { - throw new UnauthorizedError({ - message: "Token version mismatch", - name: "InvalidToken" - }); - } - - return { decodedToken, tokenVersion }; - }; - const validateTokenForUser = async ({ type, userId, @@ -185,6 +151,40 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, orgMembershipDAL }: TAu const revokeAllMySessions = async (userId: string) => tokenDAL.deleteTokenSession({ userId }); + const validateRefreshToken = async (refreshToken?: string) => { + const appCfg = getConfig(); + if (!refreshToken) + throw new NotFoundError({ + name: "AuthTokenNotFound", + message: "Failed to find refresh token" + }); + + const decodedToken = jwt.verify(refreshToken, appCfg.AUTH_SECRET) as AuthModeRefreshJwtTokenPayload; + + if (decodedToken.authTokenType !== AuthTokenType.REFRESH_TOKEN) + throw new UnauthorizedError({ + message: "The token provided is not a refresh token", + name: "InvalidToken" + }); + + const tokenVersion = await getUserTokenSessionById(decodedToken.tokenVersionId, decodedToken.userId); + + if (!tokenVersion) + throw new UnauthorizedError({ + message: "Valid token version not found", + name: "InvalidToken" + }); + + if (decodedToken.refreshVersion !== tokenVersion.refreshVersion) { + throw new UnauthorizedError({ + message: "Token version mismatch", + name: "InvalidToken" + }); + } + + return { decodedToken, tokenVersion }; + }; + // to parse jwt identity in inject identity plugin const fnValidateJwtIdentity = async (token: AuthModeJwtTokenPayload) => { const session = await tokenDAL.findOneTokenSession({ @@ -218,12 +218,12 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, orgMembershipDAL }: TAu return { createTokenForUser, - validateRefreshToken, validateTokenForUser, getUserTokenSession, clearTokenSessionById, getTokenSessionByUser, revokeAllMySessions, + validateRefreshToken, fnValidateJwtIdentity, getUserTokenSessionById }; diff --git a/backend/src/services/auth/auth-fns.ts b/backend/src/services/auth/auth-fns.ts index c73b32c1e..5f7aca812 100644 --- a/backend/src/services/auth/auth-fns.ts +++ b/backend/src/services/auth/auth-fns.ts @@ -2,6 +2,7 @@ import jwt from "jsonwebtoken"; import { getConfig } from "@app/lib/config/env"; import { ForbiddenRequestError, UnauthorizedError } from "@app/lib/errors"; + import { AuthModeProviderJwtTokenPayload, AuthModeProviderSignUpTokenPayload, AuthTokenType } from "./auth-type"; export const validateProviderAuthToken = (providerToken: string, username?: string) => { diff --git a/backend/src/services/kms/kms-root-config-dal.ts b/backend/src/services/kms/kms-root-config-dal.ts index 8745d286e..31826b79d 100644 --- a/backend/src/services/kms/kms-root-config-dal.ts +++ b/backend/src/services/kms/kms-root-config-dal.ts @@ -1,8 +1,9 @@ +import { Knex } from "knex"; + import { TDbClient } from "@app/db"; import { TableName } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify } from "@app/lib/knex"; -import { Knex } from "knex"; export type TKmsRootConfigDALFactory = ReturnType; diff --git a/frontend/src/hooks/api/users/queries.tsx b/frontend/src/hooks/api/users/queries.tsx index 6b85af9eb..06cde4d34 100644 --- a/frontend/src/hooks/api/users/queries.tsx +++ b/frontend/src/hooks/api/users/queries.tsx @@ -3,6 +3,7 @@ import { AxiosError } from "axios"; import { apiRequest } from "@app/config/request"; import { SessionStorageKeys } from "@app/const"; +import { queryClient as qc } from "@app/hooks/api/reactQuery"; import { APIKeyDataV2 } from "../apiKeys/types"; import { MfaMethod } from "../auth/types"; @@ -24,7 +25,6 @@ import { User, UserEnc } from "./types"; -import { queryClient } from "@app/hooks/api/reactQuery"; export const fetchUserDetails = async () => { const { data } = await apiRequest.get<{ user: User & UserEnc }>("/api/v1/user"); @@ -297,7 +297,7 @@ export const clearSession = (keepQueryClient?: boolean) => { sessionStorage.removeItem(SessionStorageKeys.CLI_TERMINAL_TOKEN); if (!keepQueryClient) { - queryClient.clear(); // Clear React Query cache + qc.clear(); // Clear React Query cache } }; diff --git a/frontend/src/pages/middlewares/authenticate.tsx b/frontend/src/pages/middlewares/authenticate.tsx index 93462a095..2b1e79a7b 100644 --- a/frontend/src/pages/middlewares/authenticate.tsx +++ b/frontend/src/pages/middlewares/authenticate.tsx @@ -1,12 +1,11 @@ import { createFileRoute, redirect } from "@tanstack/react-router"; +import { AxiosError } from "axios"; import { createNotification } from "@app/components/notifications"; import { ROUTE_PATHS } from "@app/const/routes"; import { userKeys } from "@app/hooks/api"; import { authKeys, fetchAuthToken } from "@app/hooks/api/auth/queries"; -import { fetchUserDetails } from "@app/hooks/api/users/queries"; -import { AxiosError } from "axios"; -import { clearSession, logoutUser } from "@app/hooks/api/users/queries"; +import { clearSession, fetchUserDetails, logoutUser } from "@app/hooks/api/users/queries"; export const Route = createFileRoute("/_authenticate")({ beforeLoad: async ({ context, location }) => { diff --git a/frontend/src/pages/organization/NoOrgPage/route.tsx b/frontend/src/pages/organization/NoOrgPage/route.tsx index d89f77c1c..5d34fed93 100644 --- a/frontend/src/pages/organization/NoOrgPage/route.tsx +++ b/frontend/src/pages/organization/NoOrgPage/route.tsx @@ -1,7 +1,7 @@ -import { createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from "@tanstack/react-router"; -import { NoOrgPage } from './NoOrgPage' +import { NoOrgPage } from "./NoOrgPage"; -export const Route = createFileRoute('/_authenticate/organization/none')({ - component: NoOrgPage, -}) +export const Route = createFileRoute("/_authenticate/organization/none")({ + component: NoOrgPage +}); diff --git a/frontend/src/pages/organization/layout.tsx b/frontend/src/pages/organization/layout.tsx index 5da0757be..79bdbf216 100644 --- a/frontend/src/pages/organization/layout.tsx +++ b/frontend/src/pages/organization/layout.tsx @@ -1,9 +1,7 @@ -import { createFileRoute } from '@tanstack/react-router' +import { createFileRoute } from "@tanstack/react-router"; -import { OrganizationLayout } from '@app/layouts/OrganizationLayout' +import { OrganizationLayout } from "@app/layouts/OrganizationLayout"; -export const Route = createFileRoute( - '/_authenticate/_inject-org-details/_org-layout', -)({ - component: OrganizationLayout, -}) +export const Route = createFileRoute("/_authenticate/_inject-org-details/_org-layout")({ + component: OrganizationLayout +});