diff --git a/backend/src/server/routes/v1/sso-router.ts b/backend/src/server/routes/v1/sso-router.ts index 18c8595af..e79b18e6d 100644 --- a/backend/src/server/routes/v1/sso-router.ts +++ b/backend/src/server/routes/v1/sso-router.ts @@ -280,10 +280,6 @@ export const registerSsoRouter = async (server: FastifyZodProvider) => { providerAuthToken: req.body.providerAuthToken }); - if (data.isMfaEnabled) { - return { mfaEnabled: true, token: data.token } as const; // for discriminated union - } - void res.setCookie("jid", data.token.refresh, { httpOnly: true, path: "/", diff --git a/backend/src/server/routes/v3/login-router.ts b/backend/src/server/routes/v3/login-router.ts index b5f523a54..ca9bf0108 100644 --- a/backend/src/server/routes/v3/login-router.ts +++ b/backend/src/server/routes/v3/login-router.ts @@ -47,7 +47,8 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => { }), response: { 200: z.object({ - token: z.string() + token: z.string(), + isMfaEnabled: z.boolean() }) } }, @@ -60,6 +61,13 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => { ipAddress: req.realIp }); + if (tokens.isMfaEnabled) { + return { + token: tokens.mfa as string, + isMfaEnabled: true + }; + } + void res.setCookie("jid", tokens.refresh, { httpOnly: true, path: "/", @@ -67,7 +75,7 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => { secure: cfg.HTTPS_ENABLED }); - return { token: tokens.access }; + return { token: tokens.access, isMfaEnabled: false }; } }); @@ -86,21 +94,18 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => { password: z.string().optional() }), response: { - 200: z.discriminatedUnion("mfaEnabled", [ - z.object({ mfaEnabled: z.literal(true), token: z.string() }), - z.object({ - mfaEnabled: z.literal(false), - encryptionVersion: z.number().default(1).nullable().optional(), - protectedKey: z.string().nullable(), - protectedKeyIV: z.string().nullable(), - protectedKeyTag: z.string().nullable(), - publicKey: z.string(), - encryptedPrivateKey: z.string(), - iv: z.string(), - tag: z.string(), - token: z.string() - }) - ]) + 200: z.object({ + mfaEnabled: z.literal(false), + encryptionVersion: z.number().default(1).nullable().optional(), + protectedKey: z.string().nullable(), + protectedKeyIV: z.string().nullable(), + protectedKeyTag: z.string().nullable(), + publicKey: z.string(), + encryptedPrivateKey: z.string(), + iv: z.string(), + tag: z.string(), + token: z.string() + }) } }, handler: async (req, res) => { @@ -118,10 +123,6 @@ export const registerLoginRouter = async (server: FastifyZodProvider) => { password: req.body.password }); - if (data.isMfaEnabled) { - return { mfaEnabled: true, token: data.token } as const; // for discriminated union - } - void res.setCookie("jid", data.token.refresh, { httpOnly: true, path: "/", diff --git a/backend/src/services/auth/auth-login-service.ts b/backend/src/services/auth/auth-login-service.ts index a80f0bc85..a6c3a5bf6 100644 --- a/backend/src/services/auth/auth-login-service.ts +++ b/backend/src/services/auth/auth-login-service.ts @@ -298,30 +298,6 @@ export const authLoginServiceFactory = ({ }); } - // send multi factor auth token if they it enabled - if (userEnc.isMfaEnabled && userEnc.email) { - enforceUserLockStatus(Boolean(user.isLocked), user.temporaryLockDateEnd); - - const mfaToken = jwt.sign( - { - authMethod, - authTokenType: AuthTokenType.MFA_TOKEN, - userId: userEnc.userId - }, - cfg.AUTH_SECRET, - { - expiresIn: cfg.JWT_MFA_LIFETIME - } - ); - - await sendUserMfaCode({ - userId: userEnc.userId, - email: userEnc.email - }); - - return { isMfaEnabled: true, token: mfaToken } as const; - } - const token = await generateUserTokens({ user: { ...userEnc, @@ -333,7 +309,7 @@ export const authLoginServiceFactory = ({ organizationId }); - return { token, isMfaEnabled: false, user: userEnc } as const; + return { token, user: userEnc } as const; }; const selectOrganization = async ({ @@ -373,6 +349,30 @@ export const authLoginServiceFactory = ({ }); } + // send multi factor auth token if they it enabled + if (user.isMfaEnabled && user.email) { + enforceUserLockStatus(Boolean(user.isLocked), user.temporaryLockDateEnd); + + const mfaToken = jwt.sign( + { + authMethod: decodedToken.authMethod, + authTokenType: AuthTokenType.MFA_TOKEN, + userId: user.id + }, + cfg.AUTH_SECRET, + { + expiresIn: cfg.JWT_MFA_LIFETIME + } + ); + + await sendUserMfaCode({ + userId: user.id, + email: user.email + }); + + return { isMfaEnabled: true, mfa: mfaToken } as const; + } + const tokens = await generateUserTokens({ authMethod: decodedToken.authMethod, user, @@ -381,7 +381,10 @@ export const authLoginServiceFactory = ({ organizationId }); - return tokens; + return { + ...tokens, + isMfaEnabled: false + }; }; /* @@ -629,7 +632,6 @@ export const authLoginServiceFactory = ({ const oauth2TokenExchange = async ({ userAgent, ip, providerAuthToken, email }: TOauthTokenExchangeDTO) => { const decodedProviderToken = validateProviderAuthToken(providerAuthToken, email); - const appCfg = getConfig(); const { authMethod, userName } = decodedProviderToken; if (!userName) throw new BadRequestError({ message: "Missing user name" }); const organizationId = @@ -644,29 +646,6 @@ export const authLoginServiceFactory = ({ if (!userEnc) throw new BadRequestError({ message: "Invalid token" }); if (!userEnc.serverEncryptedPrivateKey) throw new BadRequestError({ message: "Key handoff incomplete. Please try logging in again." }); - // send multi factor auth token if they it enabled - if (userEnc.isMfaEnabled && userEnc.email) { - enforceUserLockStatus(Boolean(userEnc.isLocked), userEnc.temporaryLockDateEnd); - - const mfaToken = jwt.sign( - { - authMethod, - authTokenType: AuthTokenType.MFA_TOKEN, - userId: userEnc.userId - }, - appCfg.AUTH_SECRET, - { - expiresIn: appCfg.JWT_MFA_LIFETIME - } - ); - - await sendUserMfaCode({ - userId: userEnc.userId, - email: userEnc.email - }); - - return { isMfaEnabled: true, token: mfaToken } as const; - } const token = await generateUserTokens({ user: { ...userEnc, id: userEnc.userId }, diff --git a/frontend/src/hooks/api/auth/queries.tsx b/frontend/src/hooks/api/auth/queries.tsx index 28d5f3941..91c2e7be1 100644 --- a/frontend/src/hooks/api/auth/queries.tsx +++ b/frontend/src/hooks/api/auth/queries.tsx @@ -65,7 +65,7 @@ export const selectOrganization = async (data: { organizationId: string; userAgent?: UserAgentType; }) => { - const { data: res } = await apiRequest.post<{ token: string }>( + const { data: res } = await apiRequest.post<{ token: string; isMfaEnabled: boolean }>( "/api/v3/auth/select-organization", data );