diff --git a/backend/src/routes/v1/auth.ts b/backend/src/routes/v1/auth.ts
index 0999e9a2d..2ff0e6d27 100644
--- a/backend/src/routes/v1/auth.ts
+++ b/backend/src/routes/v1/auth.ts
@@ -84,7 +84,7 @@ router.post(
);
router.get(
- '/login/federated/google',
+ '/login/google',
authLimiter,
passport.authenticate('google', {
scope: ['profile', 'email'],
diff --git a/frontend/src/components/login/LoginStep.tsx b/frontend/src/components/login/LoginStep.tsx
index b19bafdd9..a45ebe3e5 100644
--- a/frontend/src/components/login/LoginStep.tsx
+++ b/frontend/src/components/login/LoginStep.tsx
@@ -47,7 +47,10 @@ export default function LoginStep ({
}
setIsLoading(true);
- const isLoginSuccessful = await attemptLogin(email, password);
+ const isLoginSuccessful = await attemptLogin({
+ email,
+ password,
+ });
if (isLoginSuccessful && isLoginSuccessful.success) {
// case: login was successful
diff --git a/frontend/src/components/login/PasswordInputStep.tsx b/frontend/src/components/login/PasswordInputStep.tsx
new file mode 100644
index 000000000..b3c881a03
--- /dev/null
+++ b/frontend/src/components/login/PasswordInputStep.tsx
@@ -0,0 +1,138 @@
+import React, { useState } from 'react';
+import Link from 'next/link';
+import { useRouter } from 'next/router';
+import { useTranslation } from 'next-i18next';
+
+import Button from '@app/components/basic/buttons/Button';
+import Error from '@app/components/basic/Error';
+import InputField from '@app/components/basic/InputField';
+import attemptLogin from '@app/components/utilities/attemptLogin';
+import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps';
+
+import SecurityClient from '../utilities/SecurityClient';
+
+export default function PasswordInputStep({
+ userId,
+ email,
+ password,
+ setPassword,
+ setProviderAuthToken,
+ setStep
+}: {
+ email: string;
+ userId: string;
+ password: string;
+ setPassword: (password: string) => void;
+ setProviderAuthToken: (value: string) => void;
+ setStep: (step: number) => void;
+}) {
+ const router = useRouter();
+ const [isLoading, setIsLoading] = useState(false);
+ const [loginError, setLoginError] = useState(false);
+
+ const { t } = useTranslation();
+
+ const handleLogin = async () => {
+ try {
+ if (!userId || !password) {
+ return;
+ }
+
+ setIsLoading(true);
+ const isLoginSuccessful = await attemptLogin({
+ userId,
+ email,
+ password
+ });
+
+ if (isLoginSuccessful && isLoginSuccessful.success) {
+ // case: login was successful
+
+ if (isLoginSuccessful.mfaEnabled) {
+ // case: login requires MFA step
+ setStep(2);
+ setIsLoading(false);
+ return;
+ }
+
+ // case: login does not require MFA step
+ router.push(`/dashboard/${localStorage.getItem('projectData.id')}`);
+ }
+ } catch (err) {
+ setLoginError(true);
+ }
+
+ setIsLoading(false);
+ };
+
+ return (
+
+ );
+}
+
+export const getStaticProps = getTranslatedStaticProps(['auth', 'login']);
diff --git a/frontend/src/components/utilities/attemptLogin.ts b/frontend/src/components/utilities/attemptLogin.ts
index e92a65e77..08bef1441 100644
--- a/frontend/src/components/utilities/attemptLogin.ts
+++ b/frontend/src/components/utilities/attemptLogin.ts
@@ -26,20 +26,33 @@ interface IsLoginSuccessful {
* @param {string} password - password of user to log in
*/
const attemptLogin = async (
- email: string,
- password: string
+ {
+ email,
+ password,
+ userId,
+ }: {
+ email: string;
+ userId?: string;
+ password: string;
+ }
): Promise => {
+
+ const username = userId ?? email;
const telemetry = new Telemetry().getInstance();
return new Promise((resolve, reject) => {
client.init(
{
- username: email,
+ username,
password
},
async () => {
try {
const clientPublicKey = client.getPublicKey();
- const { serverPublicKey, salt } = await login1(email, clientPublicKey);
+ const { serverPublicKey, salt } = await login1({
+ email,
+ clientPublicKey,
+ userId,
+ });
client.setSalt(salt);
client.setServerPublicKey(serverPublicKey);
@@ -57,8 +70,11 @@ const attemptLogin = async (
iv,
tag
} = await login2(
- email,
- clientProof
+ {
+ email,
+ userId,
+ clientProof,
+ }
);
if (mfaEnabled) {
@@ -137,4 +153,4 @@ const attemptLogin = async (
});
};
-export default attemptLogin;
\ No newline at end of file
+export default attemptLogin;
diff --git a/frontend/src/pages/api/auth/Login1.ts b/frontend/src/pages/api/auth/Login1.ts
index bb7afc82b..2685a770c 100644
--- a/frontend/src/pages/api/auth/Login1.ts
+++ b/frontend/src/pages/api/auth/Login1.ts
@@ -9,16 +9,17 @@ interface Login1 {
* @param {*} clientPublicKey
* @returns
*/
-const login1 = async (email: string, clientPublicKey: string) => {
+const login1 = async (loginDetails: {
+ email: string;
+ clientPublicKey: string;
+ userId?: string;
+}) => {
const response = await fetch("/api/v2/auth/login1", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
- body: JSON.stringify({
- email,
- clientPublicKey,
- }),
+ body: JSON.stringify(loginDetails),
});
// need precise error handling about the status code
if (response?.status === 200) {
diff --git a/frontend/src/pages/api/auth/Login2.ts b/frontend/src/pages/api/auth/Login2.ts
index e3d625950..724a8b1d4 100644
--- a/frontend/src/pages/api/auth/Login2.ts
+++ b/frontend/src/pages/api/auth/Login2.ts
@@ -17,16 +17,17 @@ interface Login2Response {
* @param {*} clientPublicKey
* @returns
*/
-const login2 = async (email: string, clientProof: string) => {
+const login2 = async (loginDetails: {
+ email: string;
+ clientProof: string;
+ userId?: string;
+}) => {
const response = await fetch('/api/v2/auth/login2', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
- body: JSON.stringify({
- email,
- clientProof
- }),
+ body: JSON.stringify(loginDetails),
credentials: 'include'
});
// need precise error handling about the status code
diff --git a/frontend/src/pages/login.tsx b/frontend/src/pages/login.tsx
index 64f1caca5..1794b834b 100644
--- a/frontend/src/pages/login.tsx
+++ b/frontend/src/pages/login.tsx
@@ -8,7 +8,9 @@ import { useTranslation } from 'next-i18next';
import ListBox from '@app/components/basic/Listbox';
import LoginStep from '@app/components/login/LoginStep';
import MFAStep from '@app/components/login/MFAStep';
+import PasswordInputStep from '@app/components/login/PasswordInputStep';
import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps';
+import { useProviderAuth } from '@app/hooks/useProviderAuth';
import { isLoggedIn } from '@app/reactQuery';
import getWorkspaces from './api/workspace/getWorkspaces';
@@ -20,8 +22,14 @@ export default function Login() {
const [step, setStep] = useState(1);
const { t } = useTranslation();
const lang = router.locale ?? 'en';
+ const [isLoginWithEmail, setIsLoginWithEmail] = useState(false);
+ const {
+ providerAuthToken,
+ userId,
+ email: providerEmail,
+ setProviderAuthToken
+ } = useProviderAuth();
-
const setLanguage = async (to: string) => {
router.push('/login', '/login', { locale: to });
localStorage.setItem('lang', to);
@@ -44,30 +52,58 @@ export default function Login() {
}
}, []);
- const renderStep = (loginStep: number) => {
- // TODO: add MFA step
- switch (loginStep) {
- case 1:
- return (
-
- );
- case 2:
- // TODO: add MFA step
- return (
-
- );
- default:
- return
+ const renderView = (loginStep: number) => {
+
+ if (providerAuthToken && step === 1) {
+ return (
+
+ )
}
+
+ if (isLoginWithEmail && loginStep === 1) {
+ return (
+
+ )
+ }
+
+ if (!isLoginWithEmail && loginStep === 1) {
+ return (
+ <>
+
+
+ >
+ )
+ }
+
+ if (step === 2) {
+
+ }
+
+ return
}
return (
@@ -84,7 +120,7 @@ export default function Login() {
- {renderStep(step)}
+ {renderView(step)}