diff --git a/enterprise/frontend/src/metabase-enterprise/auth/actions.ts b/enterprise/frontend/src/metabase-enterprise/auth/actions.ts
index 695b2b82a031c240e2c114545f32009d2e096c70..6dc4409fdcee76d718110e02e30fdb035fcf36aa 100644
--- a/enterprise/frontend/src/metabase-enterprise/auth/actions.ts
+++ b/enterprise/frontend/src/metabase-enterprise/auth/actions.ts
@@ -1,12 +1,20 @@
-import { createThunkAction } from "metabase/lib/redux";
+import { createAsyncThunk } from "@reduxjs/toolkit";
+import { getSetting } from "metabase/selectors/settings";
+import { State } from "metabase-types/store";
 import { trackLoginSSO } from "./analytics";
 import { getSSOUrl } from "./utils";
 
+interface ThunkConfig {
+  state: State;
+}
+
 export const LOGIN_SSO = "metabase-enterprise/auth/LOGIN_SSO";
-export const loginSSO = createThunkAction(
+export const loginSSO = createAsyncThunk<void, string | undefined, ThunkConfig>(
   LOGIN_SSO,
-  (redirectUrl?: string) => async () => {
+  (redirectUrl: string | undefined, { getState }) => {
     trackLoginSSO();
-    window.location.href = getSSOUrl(redirectUrl);
+
+    const siteUrl = getSetting(getState(), "site-url");
+    window.location.href = getSSOUrl(siteUrl, redirectUrl);
   },
 );
diff --git a/enterprise/frontend/src/metabase-enterprise/auth/components/SSOButton/SSOButton.tsx b/enterprise/frontend/src/metabase-enterprise/auth/components/SSOButton/SSOButton.tsx
deleted file mode 100644
index a9fcde7e86f371ca647c21d86e8b403db76bf4f2..0000000000000000000000000000000000000000
--- a/enterprise/frontend/src/metabase-enterprise/auth/components/SSOButton/SSOButton.tsx
+++ /dev/null
@@ -1,34 +0,0 @@
-import React, { useCallback, useEffect } from "react";
-import { t } from "ttag";
-import AuthButton from "metabase/auth/components/AuthButton";
-
-export interface SSOButtonProps {
-  isCard?: boolean;
-  isEmbedded?: boolean;
-  redirectUrl?: string;
-  onLogin: (redirectUrl?: string) => void;
-}
-
-const SSOButton = ({
-  isCard,
-  isEmbedded,
-  redirectUrl,
-  onLogin,
-}: SSOButtonProps): JSX.Element => {
-  const handleLogin = useCallback(() => {
-    onLogin(redirectUrl);
-  }, [onLogin, redirectUrl]);
-
-  useEffect(() => {
-    isEmbedded && handleLogin();
-  }, [isEmbedded, handleLogin]);
-
-  return (
-    <AuthButton isCard={isCard} onClick={handleLogin}>
-      {t`Sign in with SSO`}
-    </AuthButton>
-  );
-};
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default SSOButton;
diff --git a/enterprise/frontend/src/metabase-enterprise/auth/components/SSOButton/SSOButton.unit.spec.tsx b/enterprise/frontend/src/metabase-enterprise/auth/components/SSOButton/SSOButton.unit.spec.tsx
deleted file mode 100644
index 03707389b4640799bec788d16b9e05db6e6c8f78..0000000000000000000000000000000000000000
--- a/enterprise/frontend/src/metabase-enterprise/auth/components/SSOButton/SSOButton.unit.spec.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from "react";
-import { render } from "@testing-library/react";
-import SSOButton from "./SSOButton";
-
-describe("SSOButton", () => {
-  it("should login immediately when embedded", () => {
-    const onLogin = jest.fn();
-
-    render(<SSOButton isEmbedded={true} onLogin={onLogin} />);
-
-    expect(onLogin).toHaveBeenCalled();
-  });
-});
diff --git a/enterprise/frontend/src/metabase-enterprise/auth/components/SSOButton/index.ts b/enterprise/frontend/src/metabase-enterprise/auth/components/SSOButton/index.ts
deleted file mode 100644
index 0b95973c5a42776dc797b38a96e98608ea58fbd1..0000000000000000000000000000000000000000
--- a/enterprise/frontend/src/metabase-enterprise/auth/components/SSOButton/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./SSOButton";
diff --git a/enterprise/frontend/src/metabase-enterprise/auth/components/SsoButton/SsoButton.tsx b/enterprise/frontend/src/metabase-enterprise/auth/components/SsoButton/SsoButton.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..edba5e8407d39ae3487c980f5e8593a92df42f52
--- /dev/null
+++ b/enterprise/frontend/src/metabase-enterprise/auth/components/SsoButton/SsoButton.tsx
@@ -0,0 +1,35 @@
+import React, { useCallback, useEffect } from "react";
+import { t } from "ttag";
+import { isWithinIframe } from "metabase/lib/dom";
+import { useDispatch } from "metabase/lib/redux";
+import { AuthButton } from "metabase/auth/components/AuthButton";
+import { loginSSO } from "../../actions";
+
+interface SsoButtonProps {
+  isCard?: boolean;
+  redirectUrl?: string;
+}
+
+export const SsoButton = ({
+  isCard,
+  redirectUrl,
+}: SsoButtonProps): JSX.Element => {
+  const isEmbedded = isWithinIframe();
+  const dispatch = useDispatch();
+
+  const handleLogin = useCallback(() => {
+    dispatch(loginSSO(redirectUrl));
+  }, [dispatch, redirectUrl]);
+
+  useEffect(() => {
+    if (isEmbedded) {
+      handleLogin();
+    }
+  }, [isEmbedded, handleLogin]);
+
+  return (
+    <AuthButton isCard={isCard} onClick={handleLogin}>
+      {t`Sign in with SSO`}
+    </AuthButton>
+  );
+};
diff --git a/enterprise/frontend/src/metabase-enterprise/auth/components/SsoButton/SsoButton.unit.spec.tsx b/enterprise/frontend/src/metabase-enterprise/auth/components/SsoButton/SsoButton.unit.spec.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..ffe1404a1450c747a2a60caae315395b9b1f2768
--- /dev/null
+++ b/enterprise/frontend/src/metabase-enterprise/auth/components/SsoButton/SsoButton.unit.spec.tsx
@@ -0,0 +1,37 @@
+import React from "react";
+import {
+  createMockSettingsState,
+  createMockState,
+} from "metabase-types/store/mocks";
+import { renderWithProviders, waitFor } from "__support__/ui";
+import { SsoButton } from "./SsoButton";
+
+const SITE_URL = "http://metabase.test";
+
+const setup = () => {
+  const state = createMockState({
+    settings: createMockSettingsState({
+      "site-url": SITE_URL,
+    }),
+  });
+
+  jest.spyOn(window, "top", "get").mockReturnValue({
+    ...window,
+  });
+  jest.spyOn(window, "location", "get").mockReturnValue({
+    ...window.location,
+    href: `${SITE_URL}/auth/login`,
+  });
+
+  renderWithProviders(<SsoButton />, { storeInitialState: state });
+};
+
+describe("SSOButton", () => {
+  it("should login immediately when embedded", async () => {
+    setup();
+
+    await waitFor(() => {
+      expect(window.location.href).toBe(`${SITE_URL}/auth/sso`);
+    });
+  });
+});
diff --git a/enterprise/frontend/src/metabase-enterprise/auth/components/SsoButton/index.ts b/enterprise/frontend/src/metabase-enterprise/auth/components/SsoButton/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cd277d89707b4d0738eb1eed85d6e84ba3e62c2d
--- /dev/null
+++ b/enterprise/frontend/src/metabase-enterprise/auth/components/SsoButton/index.ts
@@ -0,0 +1 @@
+export * from "./SsoButton";
diff --git a/enterprise/frontend/src/metabase-enterprise/auth/containers/SSOButton/SSOButton.tsx b/enterprise/frontend/src/metabase-enterprise/auth/containers/SSOButton/SSOButton.tsx
deleted file mode 100644
index 52a557c9027870c3dd85fd9a0e49111b847e7218..0000000000000000000000000000000000000000
--- a/enterprise/frontend/src/metabase-enterprise/auth/containers/SSOButton/SSOButton.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { connect } from "react-redux";
-import { isWithinIframe } from "metabase/lib/dom";
-import SSOButton from "../../components/SSOButton";
-import { loginSSO } from "../../actions";
-
-const mapStateToProps = () => ({
-  isEmbedded: isWithinIframe(),
-});
-
-const mapDispatchToProps = {
-  onLogin: loginSSO,
-};
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default connect(mapStateToProps, mapDispatchToProps)(SSOButton);
diff --git a/enterprise/frontend/src/metabase-enterprise/auth/containers/SSOButton/index.ts b/enterprise/frontend/src/metabase-enterprise/auth/containers/SSOButton/index.ts
deleted file mode 100644
index 0b95973c5a42776dc797b38a96e98608ea58fbd1..0000000000000000000000000000000000000000
--- a/enterprise/frontend/src/metabase-enterprise/auth/containers/SSOButton/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./SSOButton";
diff --git a/enterprise/frontend/src/metabase-enterprise/auth/index.js b/enterprise/frontend/src/metabase-enterprise/auth/index.js
index a92a477c317afec6ae3f348ad29ca496ff74fc01..1845d8d5bdffc04400ffbcf635422d06fdf7c6e1 100644
--- a/enterprise/frontend/src/metabase-enterprise/auth/index.js
+++ b/enterprise/frontend/src/metabase-enterprise/auth/index.js
@@ -17,7 +17,7 @@ import SessionTimeoutSetting from "metabase-enterprise/auth/components/SessionTi
 import { createSessionMiddleware } from "../auth/middleware/session-middleware";
 import SettingsSAMLForm from "./components/SettingsSAMLForm";
 import SettingsJWTForm from "./components/SettingsJWTForm";
-import SSOButton from "./containers/SSOButton";
+import { SsoButton } from "./components/SsoButton";
 import JwtAuthCard from "./containers/JwtAuthCard";
 import SamlAuthCard from "./containers/SamlAuthCard";
 
@@ -217,7 +217,7 @@ PLUGIN_ADMIN_SETTINGS_UPDATES.push(sections => ({
 
 const SSO_PROVIDER = {
   name: "sso",
-  Button: SSOButton,
+  Button: SsoButton,
 };
 
 PLUGIN_AUTH_PROVIDERS.push(providers => {
diff --git a/enterprise/frontend/src/metabase-enterprise/auth/middleware/session-middleware.js b/enterprise/frontend/src/metabase-enterprise/auth/middleware/session-middleware.js
index a2d1a2a853a3426b62f3e335e120e619acb204d6..05d1e2948f68a94e67189e370704fe43706c4051 100644
--- a/enterprise/frontend/src/metabase-enterprise/auth/middleware/session-middleware.js
+++ b/enterprise/frontend/src/metabase-enterprise/auth/middleware/session-middleware.js
@@ -37,7 +37,7 @@ export const createSessionMiddleware = (
           if (isLoggedIn) {
             // get the redirect url before refreshing the session because after the refresh the url will be reset
             const redirectUrl = getRedirectUrl();
-            await store.dispatch(refreshSession());
+            await store.dispatch(refreshSession())?.unwrap();
 
             if (redirectUrl !== null) {
               store.dispatch(replace(redirectUrl));
diff --git a/enterprise/frontend/src/metabase-enterprise/auth/utils.ts b/enterprise/frontend/src/metabase-enterprise/auth/utils.ts
index 4fe1e1e9edbdec7a7baf5772bd3ba3d1fa4f28bf..98d4222068dab67209be376cf9f2c1b851ed71bb 100644
--- a/enterprise/frontend/src/metabase-enterprise/auth/utils.ts
+++ b/enterprise/frontend/src/metabase-enterprise/auth/utils.ts
@@ -1,8 +1,4 @@
-import Settings from "metabase/lib/settings";
-
-export const getSSOUrl = (redirectUrl?: string): string => {
-  const siteUrl = Settings.get("site-url");
-
+export const getSSOUrl = (siteUrl: string, redirectUrl?: string): string => {
   if (redirectUrl) {
     return `${siteUrl}/auth/sso?redirect=${encodeURIComponent(redirectUrl)}`;
   } else {
diff --git a/frontend/src/metabase-types/api/index.ts b/frontend/src/metabase-types/api/index.ts
index ada47ac44ded0b255d891dde189d71e74d344dd9..1faaead28fc1d92693dd139321bcbe178409b259 100644
--- a/frontend/src/metabase-types/api/index.ts
+++ b/frontend/src/metabase-types/api/index.ts
@@ -21,6 +21,7 @@ export * from "./query";
 export * from "./revision";
 export * from "./schema";
 export * from "./segment";
+export * from "./session";
 export * from "./settings";
 export * from "./setup";
 export * from "./slack";
diff --git a/frontend/src/metabase-types/api/mocks/index.ts b/frontend/src/metabase-types/api/mocks/index.ts
index e8a5c862ef6530a99349d76a885d299662752152..8ce1fbbc0fb2fa3cf9dd19a1d233b90918ff072c 100644
--- a/frontend/src/metabase-types/api/mocks/index.ts
+++ b/frontend/src/metabase-types/api/mocks/index.ts
@@ -15,10 +15,12 @@ export * from "./parameters";
 export * from "./query";
 export * from "./schema";
 export * from "./segment";
-export * from "./table";
-export * from "./timeline";
+export * from "./series";
+export * from "./session";
 export * from "./settings";
 export * from "./setup";
 export * from "./snippets";
 export * from "./store";
+export * from "./table";
+export * from "./timeline";
 export * from "./user";
diff --git a/frontend/src/metabase-types/api/mocks/session.ts b/frontend/src/metabase-types/api/mocks/session.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cc0adfa1df6b2b1167cb3d108598bcabef36bab7
--- /dev/null
+++ b/frontend/src/metabase-types/api/mocks/session.ts
@@ -0,0 +1,8 @@
+import { PasswordResetTokenInfo } from "metabase-types/api";
+
+export const createMockPasswordResetTokenInfo = (
+  opts?: Partial<PasswordResetTokenInfo>,
+): PasswordResetTokenInfo => ({
+  valid: false,
+  ...opts,
+});
diff --git a/frontend/src/metabase-types/api/session.ts b/frontend/src/metabase-types/api/session.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9a72a8cdbff3beb0163d210acac438ab1d48e9ad
--- /dev/null
+++ b/frontend/src/metabase-types/api/session.ts
@@ -0,0 +1,3 @@
+export interface PasswordResetTokenInfo {
+  valid: boolean;
+}
diff --git a/frontend/src/metabase/auth/actions.ts b/frontend/src/metabase/auth/actions.ts
index a8c99466b36e18cc002c098fe6636453bfb327a4..c30ce381bd56fd48b8a657c18649476eab9444f2 100644
--- a/frontend/src/metabase/auth/actions.ts
+++ b/frontend/src/metabase/auth/actions.ts
@@ -1,8 +1,9 @@
+import { createAsyncThunk } from "@reduxjs/toolkit";
 import { push } from "react-router-redux";
 import { getIn } from "icepick";
 import { SessionApi, UtilApi } from "metabase/services";
+import { getSetting } from "metabase/selectors/settings";
 import MetabaseSettings from "metabase/lib/settings";
-import { createThunkAction } from "metabase/lib/redux";
 import { loadLocalization } from "metabase/lib/i18n";
 import { deleteSession } from "metabase/lib/auth";
 import * as Urls from "metabase/lib/urls";
@@ -18,82 +19,125 @@ import {
 } from "./analytics";
 import { LoginData } from "./types";
 
+interface ThunkConfig {
+  state: State;
+}
+
 export const REFRESH_LOCALE = "metabase/user/REFRESH_LOCALE";
-export const refreshLocale = createThunkAction(
+export const refreshLocale = createAsyncThunk<void, void, ThunkConfig>(
   REFRESH_LOCALE,
-  () => async (dispatch: any, getState: () => State) => {
+  async (_, { getState }) => {
     const userLocale = getUser(getState())?.locale;
-    const siteLocale = MetabaseSettings.get("site-locale");
+    const siteLocale = getSetting(getState(), "site-locale");
     await loadLocalization(userLocale ?? siteLocale ?? "en");
   },
 );
 
 export const REFRESH_SESSION = "metabase/auth/REFRESH_SESSION";
-export const refreshSession = createThunkAction(
+export const refreshSession = createAsyncThunk<void, void, ThunkConfig>(
   REFRESH_SESSION,
-  () => async (dispatch: any) => {
+  async (_, { dispatch }) => {
     await Promise.all([
       dispatch(refreshCurrentUser()),
       dispatch(refreshSiteSettings()),
     ]);
-    await dispatch(refreshLocale());
+    await dispatch(refreshLocale()).unwrap();
   },
 );
 
+interface LoginPayload {
+  data: LoginData;
+  redirectUrl?: string;
+}
+
 export const LOGIN = "metabase/auth/LOGIN";
-export const login = createThunkAction(
+export const login = createAsyncThunk<void, LoginPayload, ThunkConfig>(
   LOGIN,
-  (data: LoginData, redirectUrl = "/") =>
-    async (dispatch: any) => {
+  async ({ data, redirectUrl = "/" }, { dispatch, rejectWithValue }) => {
+    try {
       await SessionApi.create(data);
-      await dispatch(refreshSession());
+      await dispatch(refreshSession()).unwrap();
       trackLogin();
-
       dispatch(push(redirectUrl));
-    },
+    } catch (error) {
+      return rejectWithValue(error);
+    }
+  },
 );
 
+interface LoginGooglePayload {
+  credential: string;
+  redirectUrl?: string;
+}
+
 export const LOGIN_GOOGLE = "metabase/auth/LOGIN_GOOGLE";
-export const loginGoogle = createThunkAction(
+export const loginGoogle = createAsyncThunk<
+  void,
+  LoginGooglePayload,
+  ThunkConfig
+>(
   LOGIN_GOOGLE,
-  (token: string, redirectUrl = "/") =>
-    async (dispatch: any) => {
-      await SessionApi.createWithGoogleAuth({ token });
-      await dispatch(refreshSession());
+  async ({ credential, redirectUrl = "/" }, { dispatch, rejectWithValue }) => {
+    try {
+      await SessionApi.createWithGoogleAuth({ token: credential });
+      await dispatch(refreshSession()).unwrap();
       trackLoginGoogle();
-
       dispatch(push(redirectUrl));
-    },
+    } catch (error) {
+      return rejectWithValue(error);
+    }
+  },
 );
 
 export const LOGOUT = "metabase/auth/LOGOUT";
-export const logout = createThunkAction(LOGOUT, (redirectUrl: string) => {
-  return async (dispatch: any) => {
-    await deleteSession();
-    await dispatch(clearCurrentUser());
-    await dispatch(refreshLocale());
-    trackLogout();
-
-    dispatch(push(Urls.login(redirectUrl)));
-    window.location.reload(); // clears redux state and browser caches
-  };
-});
+export const logout = createAsyncThunk<void, string | undefined, ThunkConfig>(
+  LOGOUT,
+  async (redirectUrl, { dispatch, rejectWithValue }) => {
+    try {
+      await deleteSession();
+      await dispatch(clearCurrentUser());
+      await dispatch(refreshLocale()).unwrap();
+      trackLogout();
+      dispatch(push(Urls.login(redirectUrl)));
+      window.location.reload(); // clears redux state and browser caches
+    } catch (error) {
+      return rejectWithValue(error);
+    }
+  },
+);
 
 export const FORGOT_PASSWORD = "metabase/auth/FORGOT_PASSWORD";
-export const forgotPassword = createThunkAction(
+export const forgotPassword = createAsyncThunk(
   FORGOT_PASSWORD,
-  (email: string) => async () => {
-    await SessionApi.forgot_password({ email });
+  async (email: string, { rejectWithValue }) => {
+    try {
+      await SessionApi.forgot_password({ email });
+    } catch (error) {
+      return rejectWithValue(error);
+    }
   },
 );
 
+interface ResetPasswordPayload {
+  token: string;
+  password: string;
+}
+
 export const RESET_PASSWORD = "metabase/auth/RESET_PASSWORD";
-export const resetPassword = createThunkAction(
+export const resetPassword = createAsyncThunk<
+  void,
+  ResetPasswordPayload,
+  ThunkConfig
+>(
   RESET_PASSWORD,
-  (token: string, password: string) => async (dispatch: any) => {
-    await SessionApi.reset_password({ token, password });
-    await dispatch(refreshSession());
-    trackPasswordReset();
+  async ({ token, password }, { dispatch, rejectWithValue }) => {
+    try {
+      await SessionApi.reset_password({ token, password });
+      await dispatch(refreshSession()).unwrap();
+      trackPasswordReset();
+    } catch (error) {
+      return rejectWithValue(error);
+    }
   },
 );
 
@@ -110,15 +154,11 @@ export const validatePassword = async (password: string) => {
   }
 };
 
-export const VALIDATE_PASSWORD_TOKEN = "metabase/auth/VALIDATE_TOKEN";
-export const validatePasswordToken = createThunkAction(
-  VALIDATE_PASSWORD_TOKEN,
-  (token: string) => async () => {
-    const result = await SessionApi.password_reset_token_valid({ token });
-    const valid = getIn(result, ["valid"]);
+export const validatePasswordToken = async (token: string) => {
+  const result = await SessionApi.password_reset_token_valid({ token });
+  const valid = getIn(result, ["valid"]);
 
-    if (!valid) {
-      throw result;
-    }
-  },
-);
+  if (!valid) {
+    throw result;
+  }
+};
diff --git a/frontend/src/metabase/auth/components/AuthButton/AuthButton.styled.tsx b/frontend/src/metabase/auth/components/AuthButton/AuthButton.styled.tsx
index 4c7e37402e9cdfed90cc2ad124d41be9ce79859c..525625acb9ad92515420ceaebd075dc7b03963d6 100644
--- a/frontend/src/metabase/auth/components/AuthButton/AuthButton.styled.tsx
+++ b/frontend/src/metabase/auth/components/AuthButton/AuthButton.styled.tsx
@@ -1,6 +1,5 @@
 import styled from "@emotion/styled";
 import { color } from "metabase/lib/colors";
-import Icon from "metabase/components/Icon";
 import Link from "metabase/core/components/Link";
 
 export const TextLink = styled(Link)`
@@ -22,10 +21,6 @@ export const CardLink = styled(TextLink)`
   border-radius: 6px;
 `;
 
-export const CardIcon = styled(Icon)`
-  margin-right: 0.5rem;
-`;
-
 export const CardText = styled.span`
   font-weight: 700;
   line-height: 1rem;
diff --git a/frontend/src/metabase/auth/components/AuthButton/AuthButton.tsx b/frontend/src/metabase/auth/components/AuthButton/AuthButton.tsx
index f0e6d4daa61cbdd766ce8fb227dae1930dc2da22..8073db5974b0013f24061e68dfa673515c9e06c9 100644
--- a/frontend/src/metabase/auth/components/AuthButton/AuthButton.tsx
+++ b/frontend/src/metabase/auth/components/AuthButton/AuthButton.tsx
@@ -1,24 +1,21 @@
 import React, { ReactNode } from "react";
-import { CardIcon, CardLink, CardText, TextLink } from "./AuthButton.styled";
+import { CardLink, CardText, TextLink } from "./AuthButton.styled";
 
-export interface AuthButtonProps {
+interface AuthButtonProps {
   link?: string;
-  icon?: string;
   isCard?: boolean;
   children?: ReactNode;
   onClick?: () => void;
 }
 
-const AuthButton = ({
+export const AuthButton = ({
   link = "",
-  icon,
   isCard,
   children,
   onClick,
 }: AuthButtonProps): JSX.Element => {
   return isCard ? (
     <CardLink to={link} onClick={onClick}>
-      {icon && <CardIcon name={icon} />}
       <CardText>{children}</CardText>
     </CardLink>
   ) : (
@@ -27,6 +24,3 @@ const AuthButton = ({
     </TextLink>
   );
 };
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default AuthButton;
diff --git a/frontend/src/metabase/auth/components/AuthButton/AuthButton.unit.spec.tsx b/frontend/src/metabase/auth/components/AuthButton/AuthButton.unit.spec.tsx
index ccf6b299ce1e4932028c8d3bceb2ae7fffc0ba9d..df2452a0d7f8e9c1621c47c4143bf1a710b24afe 100644
--- a/frontend/src/metabase/auth/components/AuthButton/AuthButton.unit.spec.tsx
+++ b/frontend/src/metabase/auth/components/AuthButton/AuthButton.unit.spec.tsx
@@ -1,21 +1,24 @@
 import React from "react";
-import { render, screen } from "@testing-library/react";
-import AuthButton from "./AuthButton";
+import { renderWithProviders, screen } from "__support__/ui";
+import { AuthButton } from "./AuthButton";
+
+interface SetupOpts {
+  isCard?: boolean;
+}
+
+const setup = ({ isCard }: SetupOpts = {}) => {
+  renderWithProviders(<AuthButton isCard={isCard}>Sign in</AuthButton>);
+};
 
 describe("AuthButton", () => {
   it("should render a card", () => {
-    render(
-      <AuthButton icon="google" isCard={true}>
-        Sign in
-      </AuthButton>,
-    );
+    setup({ isCard: true });
 
     expect(screen.getByText("Sign in")).toBeInTheDocument();
-    expect(screen.getByLabelText("google icon")).toBeInTheDocument();
   });
 
   it("should render a link", () => {
-    render(<AuthButton>Sign in</AuthButton>);
+    setup();
 
     expect(screen.getByText("Sign in")).toBeInTheDocument();
   });
diff --git a/frontend/src/metabase/auth/components/AuthButton/index.ts b/frontend/src/metabase/auth/components/AuthButton/index.ts
index 99dd939a01a6da73971c1924594091aa1f7296ec..74f40bf0532e70eee995ab76bc19531d41de3a0c 100644
--- a/frontend/src/metabase/auth/components/AuthButton/index.ts
+++ b/frontend/src/metabase/auth/components/AuthButton/index.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./AuthButton";
+export * from "./AuthButton";
diff --git a/frontend/src/metabase/auth/components/AuthLayout/AuthLayout.tsx b/frontend/src/metabase/auth/components/AuthLayout/AuthLayout.tsx
index c3d4b299452b165da2176e7a47949ae0d35f81f7..e4ab86648c54568dac9c797c5bb94496d2de2e41 100644
--- a/frontend/src/metabase/auth/components/AuthLayout/AuthLayout.tsx
+++ b/frontend/src/metabase/auth/components/AuthLayout/AuthLayout.tsx
@@ -1,5 +1,7 @@
 import React, { ReactNode } from "react";
+import { useSelector } from "metabase/lib/redux";
 import LogoIcon from "metabase/components/LogoIcon";
+import { getHasIllustration } from "../../selectors";
 import {
   LayoutBody,
   LayoutCard,
@@ -7,18 +9,16 @@ import {
   LayoutRoot,
 } from "./AuthLayout.styled";
 
-export interface AuthLayoutProps {
-  showIllustration: boolean;
+interface AuthLayoutProps {
   children?: ReactNode;
 }
 
-const AuthLayout = ({
-  showIllustration,
-  children,
-}: AuthLayoutProps): JSX.Element => {
+export const AuthLayout = ({ children }: AuthLayoutProps): JSX.Element => {
+  const hasIllustration = useSelector(getHasIllustration);
+
   return (
     <LayoutRoot>
-      {showIllustration && <LayoutIllustration />}
+      {hasIllustration && <LayoutIllustration />}
       <LayoutBody>
         <LogoIcon height={65} />
         <LayoutCard>{children}</LayoutCard>
@@ -26,6 +26,3 @@ const AuthLayout = ({
     </LayoutRoot>
   );
 };
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default AuthLayout;
diff --git a/frontend/src/metabase/auth/components/AuthLayout/index.ts b/frontend/src/metabase/auth/components/AuthLayout/index.ts
index d2486700846e8f2b98799e8d24ea28f91105aea1..30e3bd9490dade6d5e9f4a45e3a164470ddde4c4 100644
--- a/frontend/src/metabase/auth/components/AuthLayout/index.ts
+++ b/frontend/src/metabase/auth/components/AuthLayout/index.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./AuthLayout";
+export * from "./AuthLayout";
diff --git a/frontend/src/metabase/auth/components/ForgotPassword/ForgotPassword.tsx b/frontend/src/metabase/auth/components/ForgotPassword/ForgotPassword.tsx
index 7de72315d25180566449a9743362458685d295ff..cf8013c64b638d7eb16ea06eab09839554d911c2 100644
--- a/frontend/src/metabase/auth/components/ForgotPassword/ForgotPassword.tsx
+++ b/frontend/src/metabase/auth/components/ForgotPassword/ForgotPassword.tsx
@@ -1,8 +1,12 @@
 import React, { useCallback, useState } from "react";
 import { t } from "ttag";
+import { Location } from "history";
+import { useDispatch, useSelector } from "metabase/lib/redux";
 import Button from "metabase/core/components/Button";
-import AuthLayout from "../../containers/AuthLayout";
-import ForgotPasswordForm from "../ForgotPasswordForm";
+import { forgotPassword } from "../../actions";
+import { getIsEmailConfigured, getIsLdapEnabled } from "../../selectors";
+import { AuthLayout } from "../AuthLayout";
+import { ForgotPasswordForm } from "../ForgotPasswordForm";
 import {
   InfoBody,
   InfoIcon,
@@ -13,27 +17,33 @@ import {
 
 type ViewType = "form" | "disabled" | "success";
 
-export interface ForgotPasswordProps {
-  canResetPassword: boolean;
-  initialEmail?: string;
-  onResetPassword: (email: string) => void;
+interface ForgotPasswordQueryString {
+  email?: string;
 }
 
-const ForgotPassword = ({
-  canResetPassword,
-  initialEmail,
-  onResetPassword,
+interface ForgotPasswordProps {
+  location?: Location<ForgotPasswordQueryString>;
+}
+
+export const ForgotPassword = ({
+  location,
 }: ForgotPasswordProps): JSX.Element => {
+  const isEmailConfigured = useSelector(getIsEmailConfigured);
+  const isLdapEnabled = useSelector(getIsLdapEnabled);
+  const canResetPassword = isEmailConfigured && !isLdapEnabled;
+  const initialEmail = location?.query?.email;
+
   const [view, setView] = useState<ViewType>(
     canResetPassword ? "form" : "disabled",
   );
+  const dispatch = useDispatch();
 
   const handleSubmit = useCallback(
     async (email: string) => {
-      await onResetPassword(email);
+      await dispatch(forgotPassword(email)).unwrap();
       setView("success");
     },
-    [onResetPassword],
+    [dispatch],
   );
 
   return (
@@ -74,6 +84,3 @@ const ForgotPasswordDisabled = (): JSX.Element => {
     </InfoBody>
   );
 };
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default ForgotPassword;
diff --git a/frontend/src/metabase/auth/components/ForgotPassword/ForgotPassword.unit.spec.tsx b/frontend/src/metabase/auth/components/ForgotPassword/ForgotPassword.unit.spec.tsx
index 6ee770f67d4e7dda383eb525282079b2dcbd3bfb..397f588a2b945d1adc32ba4fb1a0220d8676b070 100644
--- a/frontend/src/metabase/auth/components/ForgotPassword/ForgotPassword.unit.spec.tsx
+++ b/frontend/src/metabase/auth/components/ForgotPassword/ForgotPassword.unit.spec.tsx
@@ -1,60 +1,62 @@
-import React, { ReactNode } from "react";
-import { render, screen, waitFor } from "@testing-library/react";
+import React from "react";
+import { Route } from "react-router";
 import userEvent from "@testing-library/user-event";
-import ForgotPassword, { ForgotPasswordProps } from "./ForgotPassword";
+import {
+  createMockSettingsState,
+  createMockState,
+} from "metabase-types/store/mocks";
+import { setupForgotPasswordEndpoint } from "__support__/server-mocks";
+import { renderWithProviders, screen, waitFor } from "__support__/ui";
+import { ForgotPassword } from "./ForgotPassword";
+
+const TEST_EMAIL = "user@metabase.test";
+
+interface SetupOpts {
+  isEmailConfigured?: boolean;
+  isLdapEnabled?: boolean;
+}
+
+const setup = ({ isEmailConfigured, isLdapEnabled }: SetupOpts) => {
+  const state = createMockState({
+    settings: createMockSettingsState({
+      "email-configured?": isEmailConfigured,
+      "ldap-enabled": isLdapEnabled,
+    }),
+  });
+
+  setupForgotPasswordEndpoint();
+
+  renderWithProviders(
+    <Route path="/auth/forgot_password" component={ForgotPassword} />,
+    {
+      storeInitialState: state,
+      withRouter: true,
+      initialRoute: "/auth/forgot_password",
+    },
+  );
+};
 
 describe("ForgotPassword", () => {
   it("should show a form when the user can reset their password", () => {
-    const props = getProps({ canResetPassword: true });
-
-    render(<ForgotPassword {...props} />);
+    setup({ isEmailConfigured: true });
 
     expect(screen.getByText("Forgot password")).toBeInTheDocument();
   });
 
   it("should show a success message when the form is submitted", async () => {
-    const email = "user@metabase.test";
-    const props = getProps({
-      canResetPassword: true,
-      onResetPassword: jest.fn().mockResolvedValue({}),
-    });
-
-    render(<ForgotPassword {...props} />);
-    userEvent.type(screen.getByLabelText("Email address"), email);
+    setup({ isEmailConfigured: true });
+    userEvent.type(screen.getByLabelText("Email address"), TEST_EMAIL);
     await waitFor(() => {
       expect(screen.getByText("Send password reset email")).toBeEnabled();
     });
 
     userEvent.click(screen.getByText("Send password reset email"));
-    await waitFor(() => {
-      expect(props.onResetPassword).toHaveBeenCalledWith(email);
-    });
-    expect(screen.getByText(/Check your email/)).toBeInTheDocument();
+    expect(await screen.findByText(/Check your email/)).toBeInTheDocument();
   });
 
   it("should show an error message when the user cannot reset their password", () => {
-    const props = getProps({ canResetPassword: false });
-
-    render(<ForgotPassword {...props} />);
+    setup({ isEmailConfigured: false });
 
     expect(screen.getByText(/contact an administrator/)).toBeInTheDocument();
   });
 });
-
-const getProps = (
-  opts?: Partial<ForgotPasswordProps>,
-): ForgotPasswordProps => ({
-  canResetPassword: false,
-  onResetPassword: jest.fn(),
-  ...opts,
-});
-
-interface AuthLayoutMockProps {
-  children?: ReactNode;
-}
-
-const AuthLayoutMock = ({ children }: AuthLayoutMockProps) => {
-  return <div>{children}</div>;
-};
-
-jest.mock("../../containers/AuthLayout", () => AuthLayoutMock);
diff --git a/frontend/src/metabase/auth/components/ForgotPassword/index.ts b/frontend/src/metabase/auth/components/ForgotPassword/index.ts
index 263142555dce09e67a8d6ceedc82ed67b8d96cb5..b3376b429bc420c7363490d8819a8bdcd0e92d7f 100644
--- a/frontend/src/metabase/auth/components/ForgotPassword/index.ts
+++ b/frontend/src/metabase/auth/components/ForgotPassword/index.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./ForgotPassword";
+export * from "./ForgotPassword";
diff --git a/frontend/src/metabase/auth/components/ForgotPasswordForm/ForgotPasswordForm.tsx b/frontend/src/metabase/auth/components/ForgotPasswordForm/ForgotPasswordForm.tsx
index 940534d12be51753d88bc4c715a35e5240364083..e8edd83bdb5979f741be2c11462569b642a33715 100644
--- a/frontend/src/metabase/auth/components/ForgotPasswordForm/ForgotPasswordForm.tsx
+++ b/frontend/src/metabase/auth/components/ForgotPasswordForm/ForgotPasswordForm.tsx
@@ -18,12 +18,12 @@ const FORGOT_PASSWORD_SCHEMA = Yup.object({
   email: Yup.string().required(Errors.required).email(Errors.email),
 });
 
-export interface ForgotPasswordFormProps {
+interface ForgotPasswordFormProps {
   initialEmail?: string;
   onSubmit: (email: string) => void;
 }
 
-const ForgotPasswordForm = ({
+export const ForgotPasswordForm = ({
   initialEmail = "",
   onSubmit,
 }: ForgotPasswordFormProps): JSX.Element => {
@@ -66,6 +66,3 @@ const ForgotPasswordForm = ({
     </div>
   );
 };
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default ForgotPasswordForm;
diff --git a/frontend/src/metabase/auth/components/ForgotPasswordForm/index.ts b/frontend/src/metabase/auth/components/ForgotPasswordForm/index.ts
index 4a89912858560fb6b3ec55d36ccdea57d85d761d..d594a39d2da0ad0cde77ddb727ee336aa92d6138 100644
--- a/frontend/src/metabase/auth/components/ForgotPasswordForm/index.ts
+++ b/frontend/src/metabase/auth/components/ForgotPasswordForm/index.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./ForgotPasswordForm";
+export * from "./ForgotPasswordForm";
diff --git a/frontend/src/metabase/auth/components/GoogleButton/GoogleButton.tsx b/frontend/src/metabase/auth/components/GoogleButton/GoogleButton.tsx
index 1c6ccd92f01958fd33307ef6d2a64328f942c9c1..edc824487afd44ff3f5ec324b82149d2480dd981 100644
--- a/frontend/src/metabase/auth/components/GoogleButton/GoogleButton.tsx
+++ b/frontend/src/metabase/auth/components/GoogleButton/GoogleButton.tsx
@@ -2,7 +2,10 @@ import React, { useCallback, useState } from "react";
 import { t } from "ttag";
 import { getIn } from "icepick";
 import { GoogleOAuthProvider, GoogleLogin } from "@react-oauth/google";
+import { useDispatch, useSelector } from "metabase/lib/redux";
 import * as Urls from "metabase/lib/urls";
+import { loginGoogle } from "../../actions";
+import { getGoogleClientId, getSiteLocale } from "../../selectors";
 import {
   GoogleButtonRoot,
   AuthError,
@@ -10,37 +13,31 @@ import {
   TextLink,
 } from "./GoogleButton.styled";
 
-export interface GoogleButtonProps {
-  clientId: string | null;
-  locale: string;
+interface GoogleButtonProps {
   redirectUrl?: string;
   isCard?: boolean;
-  onLogin: (token: string, redirectUrl?: string) => void;
 }
 
 interface CredentialResponse {
   credential?: string;
 }
 
-const GoogleButton = ({
-  clientId,
-  locale,
-  redirectUrl,
-  isCard,
-  onLogin,
-}: GoogleButtonProps) => {
+export const GoogleButton = ({ redirectUrl, isCard }: GoogleButtonProps) => {
+  const clientId = useSelector(getGoogleClientId);
+  const locale = useSelector(getSiteLocale);
   const [errors, setErrors] = useState<string[]>([]);
+  const dispatch = useDispatch();
 
   const handleLogin = useCallback(
     async ({ credential = "" }: CredentialResponse) => {
       try {
         setErrors([]);
-        await onLogin(credential, redirectUrl);
+        await dispatch(loginGoogle({ credential, redirectUrl })).unwrap();
       } catch (error) {
         setErrors(getErrors(error));
       }
     },
-    [onLogin, redirectUrl],
+    [dispatch, redirectUrl],
   );
 
   const handleError = useCallback(() => {
@@ -82,6 +79,3 @@ const getErrors = (error: unknown): string[] => {
   const errors = getIn(error, ["data", "errors"]);
   return errors ? Object.values(errors) : [];
 };
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default GoogleButton;
diff --git a/frontend/src/metabase/auth/components/GoogleButton/index.ts b/frontend/src/metabase/auth/components/GoogleButton/index.ts
index 077d745d8ae34ac0711dc7e66e46a17c5a00244d..3d53a8c344c58eaef8734adf6bf888e39dc0f593 100644
--- a/frontend/src/metabase/auth/components/GoogleButton/index.ts
+++ b/frontend/src/metabase/auth/components/GoogleButton/index.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./GoogleButton";
+export * from "./GoogleButton";
diff --git a/frontend/src/metabase/auth/components/Login/Login.tsx b/frontend/src/metabase/auth/components/Login/Login.tsx
index 0571e567b5f7862f48578f98ac34c1e4fe4fdf2c..c565be27a4647dc2056300f5c47ebb5541972124 100644
--- a/frontend/src/metabase/auth/components/Login/Login.tsx
+++ b/frontend/src/metabase/auth/components/Login/Login.tsx
@@ -1,7 +1,10 @@
 import React from "react";
 import { t } from "ttag";
-import AuthLayout from "../../containers/AuthLayout";
-import { AuthProvider } from "../../types";
+import { Location } from "history";
+import { useSelector } from "metabase/lib/redux";
+import { AuthProvider } from "metabase/plugins/types";
+import { AuthLayout } from "../AuthLayout";
+import { getAuthProviders } from "../../selectors";
 import {
   ActionList,
   ActionListItem,
@@ -9,18 +12,23 @@ import {
   LoginTitle,
 } from "./Login.styled";
 
-export interface LoginProps {
-  providers: AuthProvider[];
-  providerName?: string;
-  redirectUrl?: string;
+interface LoginQueryString {
+  redirect?: string;
 }
 
-const Login = ({
-  providers,
-  providerName,
-  redirectUrl,
-}: LoginProps): JSX.Element => {
-  const selection = getSelectedProvider(providers, providerName);
+interface LoginQueryParams {
+  provider?: string;
+}
+
+interface LoginProps {
+  params?: LoginQueryParams;
+  location?: Location<LoginQueryString>;
+}
+
+export const Login = ({ params, location }: LoginProps): JSX.Element => {
+  const providers = useSelector(getAuthProviders);
+  const selection = getSelectedProvider(providers, params?.provider);
+  const redirectUrl = location?.query?.redirect;
 
   return (
     <AuthLayout>
@@ -54,6 +62,3 @@ const getSelectedProvider = (
 
   return provider?.Panel ? provider : undefined;
 };
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default Login;
diff --git a/frontend/src/metabase/auth/components/Login/Login.unit.spec.tsx b/frontend/src/metabase/auth/components/Login/Login.unit.spec.tsx
index 8ef9d0e2f2ed80d22432c6f59470c8e291cc2abd..3d4f39f908bead914b14c476fd096ba672d9ae40 100644
--- a/frontend/src/metabase/auth/components/Login/Login.unit.spec.tsx
+++ b/frontend/src/metabase/auth/components/Login/Login.unit.spec.tsx
@@ -1,66 +1,75 @@
-import React, { ReactNode } from "react";
-import { render, screen } from "@testing-library/react";
-import { AuthProvider } from "../../types";
-import Login from "./Login";
+import React from "react";
+import { Route } from "react-router";
+import MetabaseSettings from "metabase/lib/settings";
+import {
+  createMockSettingsState,
+  createMockState,
+} from "metabase-types/store/mocks";
+import { renderWithProviders, screen } from "__support__/ui";
+import { Login } from "./Login";
+
+interface SetupOpts {
+  initialRoute?: string;
+  isPasswordLoginEnabled?: boolean;
+  isGoogleAuthEnabled?: boolean;
+}
+
+const setup = ({
+  initialRoute = "/auth/login",
+  isPasswordLoginEnabled = true,
+  isGoogleAuthEnabled = false,
+}: SetupOpts = {}) => {
+  const state = createMockState({
+    settings: createMockSettingsState({
+      "enable-password-login": isPasswordLoginEnabled,
+      "google-auth-enabled": isGoogleAuthEnabled,
+    }),
+  });
+
+  MetabaseSettings.set("enable-password-login", isPasswordLoginEnabled);
+  MetabaseSettings.set("google-auth-enabled", isGoogleAuthEnabled);
+
+  renderWithProviders(
+    <>
+      <Route path="/auth/login" component={Login} />
+      <Route path="/auth/login/:provider" component={Login} />
+    </>,
+    { storeInitialState: state, withRouter: true, initialRoute },
+  );
+};
+
+const cleanUp = () => {
+  MetabaseSettings.set("enable-password-login", true);
+  MetabaseSettings.set("google-auth-enabled", false);
+};
 
 describe("Login", () => {
-  it("should render a list of auth providers", () => {
-    const providers = [
-      getAuthProvider({ name: "password", Panel: AuthPanelMock }),
-      getAuthProvider({ name: "google" }),
-    ];
+  afterEach(() => {
+    cleanUp();
+  });
 
-    render(<Login providers={providers} />);
+  it("should render a list of auth providers", () => {
+    setup({ isPasswordLoginEnabled: true, isGoogleAuthEnabled: true });
 
     expect(screen.getAllByRole("link")).toHaveLength(2);
   });
 
   it("should render the panel of the selected provider", () => {
-    const providers = [
-      getAuthProvider({ name: "password", Panel: AuthPanelMock }),
-      getAuthProvider({ name: "google" }),
-    ];
-
-    render(<Login providers={providers} providerName="password" />);
+    setup({
+      initialRoute: "/auth/login/password",
+      isPasswordLoginEnabled: true,
+      isGoogleAuthEnabled: true,
+    });
 
     expect(screen.getByRole("button")).toBeInTheDocument();
   });
 
   it("should implicitly select the only provider with a panel", () => {
-    const providers = [
-      getAuthProvider({ name: "password", Panel: AuthPanelMock }),
-    ];
-
-    render(<Login providers={providers} />);
+    setup({
+      isPasswordLoginEnabled: true,
+      isGoogleAuthEnabled: false,
+    });
 
     expect(screen.getByRole("button")).toBeInTheDocument();
   });
-
-  it("should not implicitly select the only provider without a panel", () => {
-    const providers = [getAuthProvider({ name: "google" })];
-
-    render(<Login providers={providers} />);
-
-    expect(screen.getByRole("link")).toBeInTheDocument();
-  });
 });
-
-const getAuthProvider = (opts?: Partial<AuthProvider>): AuthProvider => ({
-  name: "password",
-  Button: AuthButtonMock,
-  ...opts,
-});
-
-const AuthButtonMock = () => <a href="/">Sign in</a>;
-
-const AuthPanelMock = () => <button>Sign in</button>;
-
-interface AuthLayoutMockProps {
-  children?: ReactNode;
-}
-
-const AuthLayoutMock = ({ children }: AuthLayoutMockProps) => {
-  return <div>{children}</div>;
-};
-
-jest.mock("../../containers/AuthLayout", () => AuthLayoutMock);
diff --git a/frontend/src/metabase/auth/components/Login/index.ts b/frontend/src/metabase/auth/components/Login/index.ts
index 41a4e665dd05db6749bdd7b17524bc4571601daf..2b0a75c361244c8f62196a76e4b4102e5cc85c51 100644
--- a/frontend/src/metabase/auth/components/Login/index.ts
+++ b/frontend/src/metabase/auth/components/Login/index.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./Login";
+export * from "./Login";
diff --git a/frontend/src/metabase/auth/components/LoginForm/LoginForm.tsx b/frontend/src/metabase/auth/components/LoginForm/LoginForm.tsx
index f9e94a47f3c0db06d22ea9cd598744a92497ff92..eaddfe8f95687c4730e205b48faa8a0191f96107 100644
--- a/frontend/src/metabase/auth/components/LoginForm/LoginForm.tsx
+++ b/frontend/src/metabase/auth/components/LoginForm/LoginForm.tsx
@@ -21,13 +21,13 @@ const LOGIN_SCHEMA = Yup.object().shape({
   remember: Yup.boolean(),
 });
 
-export interface LoginFormProps {
+interface LoginFormProps {
   isLdapEnabled: boolean;
   hasSessionCookies: boolean;
   onSubmit: (data: LoginData) => void;
 }
 
-const LoginForm = ({
+export const LoginForm = ({
   isLdapEnabled,
   hasSessionCookies,
   onSubmit,
@@ -80,6 +80,3 @@ const LoginForm = ({
     </FormProvider>
   );
 };
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default LoginForm;
diff --git a/frontend/src/metabase/auth/components/LoginForm/index.ts b/frontend/src/metabase/auth/components/LoginForm/index.ts
index a43cda62682fc642d8c6fd1285d786f80f8389ea..1cad6f418a35ee8307e98724cfbddce6b5b00628 100644
--- a/frontend/src/metabase/auth/components/LoginForm/index.ts
+++ b/frontend/src/metabase/auth/components/LoginForm/index.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./LoginForm";
+export * from "./LoginForm";
diff --git a/frontend/src/metabase/auth/components/Logout/Logout.tsx b/frontend/src/metabase/auth/components/Logout/Logout.tsx
index 0ce511f62309651cd86e2f52583dca0c50fa3d67..722a20a76608bec029d4c09af2d9732e071cfb79 100644
--- a/frontend/src/metabase/auth/components/Logout/Logout.tsx
+++ b/frontend/src/metabase/auth/components/Logout/Logout.tsx
@@ -1,15 +1,13 @@
 import { useEffect } from "react";
+import { useDispatch } from "metabase/lib/redux";
+import { logout } from "../../actions";
 
-interface LogoutProps {
-  onLogout: () => void;
-}
+export const Logout = (): JSX.Element | null => {
+  const dispatch = useDispatch();
 
-const Logout = ({ onLogout }: LogoutProps): JSX.Element | null => {
   useEffect(() => {
-    onLogout();
-  }, [onLogout]);
+    dispatch(logout());
+  }, [dispatch]);
+
   return null;
 };
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default Logout;
diff --git a/frontend/src/metabase/auth/components/Logout/Logout.unit.spec.tsx b/frontend/src/metabase/auth/components/Logout/Logout.unit.spec.tsx
index 0c199146c4a9c62ddaf1ee76cbc8db331d471fe9..6b97a52ffc6dc106c0aeda956032826aa9661421 100644
--- a/frontend/src/metabase/auth/components/Logout/Logout.unit.spec.tsx
+++ b/frontend/src/metabase/auth/components/Logout/Logout.unit.spec.tsx
@@ -1,13 +1,28 @@
 import React from "react";
-import { render } from "@testing-library/react";
-import Logout from "./Logout";
+import fetchMock from "fetch-mock";
+import { setupLogoutEndpoint } from "__support__/server-mocks";
+import { renderWithProviders, waitFor } from "__support__/ui";
+import { Logout } from "./Logout";
+
+const setup = () => {
+  jest.spyOn(window, "location", "get").mockReturnValue({
+    ...window.location,
+    reload: jest.fn(),
+  });
+
+  setupLogoutEndpoint();
+  renderWithProviders(<Logout />);
+};
 
 describe("Logout", () => {
-  it("should logout on mount", () => {
-    const onLogout = jest.fn();
+  afterEach(() => {
+    jest.restoreAllMocks();
+  });
 
-    render(<Logout onLogout={onLogout} />);
+  it("should logout on mount", async () => {
+    setup();
 
-    expect(onLogout).toHaveBeenCalled();
+    await waitFor(() => expect(fetchMock.done("path:/api/session")).toBe(true));
+    await waitFor(() => expect(window.location.reload).toHaveBeenCalled());
   });
 });
diff --git a/frontend/src/metabase/auth/components/Logout/index.ts b/frontend/src/metabase/auth/components/Logout/index.ts
index 52935ff6628d2b11e76d3372269164916ef5cde2..ca4c0a0303ebf8bc78b94ae87eaa64a35134d238 100644
--- a/frontend/src/metabase/auth/components/Logout/index.ts
+++ b/frontend/src/metabase/auth/components/Logout/index.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./Logout";
+export * from "./Logout";
diff --git a/frontend/src/metabase/auth/components/PasswordButton/PasswordButton.tsx b/frontend/src/metabase/auth/components/PasswordButton/PasswordButton.tsx
index b7724454464050c246e97562ecfad8c6e39f6edd..8ba15511e4602c86b3bb1f8620cbac0b6b1d0878 100644
--- a/frontend/src/metabase/auth/components/PasswordButton/PasswordButton.tsx
+++ b/frontend/src/metabase/auth/components/PasswordButton/PasswordButton.tsx
@@ -1,28 +1,22 @@
 import React from "react";
 import { t } from "ttag";
-import AuthButton from "../AuthButton";
+import { useSelector } from "metabase/lib/redux";
+import * as Urls from "metabase/lib/urls";
+import { getIsLdapEnabled } from "../../selectors";
+import { AuthButton } from "../AuthButton";
 
-export interface PasswordButtonProps {
-  isLdapEnabled: boolean;
+interface PasswordButtonProps {
   redirectUrl?: string;
 }
 
-const PasswordButton = ({
-  isLdapEnabled,
-  redirectUrl,
-}: PasswordButtonProps) => {
-  const link = redirectUrl
-    ? `/auth/login/password?redirect=${encodeURIComponent(redirectUrl)}`
-    : `/auth/login/password`;
+export const PasswordButton = ({ redirectUrl }: PasswordButtonProps) => {
+  const isLdapEnabled = useSelector(getIsLdapEnabled);
 
   return (
-    <AuthButton link={link}>
+    <AuthButton link={Urls.password(redirectUrl)}>
       {isLdapEnabled
         ? t`Sign in with username or email`
         : t`Sign in with email`}
     </AuthButton>
   );
 };
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default PasswordButton;
diff --git a/frontend/src/metabase/auth/components/PasswordButton/PasswordButton.unit.spec.tsx b/frontend/src/metabase/auth/components/PasswordButton/PasswordButton.unit.spec.tsx
index 385f5d9419e236e6d5e8fee687361198c6e48488..a43abc8ce187d266dc42be54101f929b9a030e44 100644
--- a/frontend/src/metabase/auth/components/PasswordButton/PasswordButton.unit.spec.tsx
+++ b/frontend/src/metabase/auth/components/PasswordButton/PasswordButton.unit.spec.tsx
@@ -1,28 +1,35 @@
 import React from "react";
-import { render, screen } from "@testing-library/react";
-import PasswordButton, { PasswordButtonProps } from "./PasswordButton";
+import {
+  createMockSettingsState,
+  createMockState,
+} from "metabase-types/store/mocks";
+import { renderWithProviders, screen } from "__support__/ui";
+import { PasswordButton } from "./PasswordButton";
+
+interface SetupOpts {
+  isLdapEnabled?: boolean;
+}
+
+const setup = ({ isLdapEnabled }: SetupOpts = {}) => {
+  const state = createMockState({
+    settings: createMockSettingsState({
+      "ldap-enabled": isLdapEnabled,
+    }),
+  });
+
+  renderWithProviders(<PasswordButton />, { storeInitialState: state });
+};
 
 describe("PasswordButton", () => {
   it("should render the login button", () => {
-    const props = getProps();
-    render(<PasswordButton {...props} />);
-
+    setup();
     expect(screen.getByText("Sign in with email")).toBeInTheDocument();
   });
 
   it("should render the login button when ldap is enabled", () => {
-    const props = getProps({ isLdapEnabled: true });
-    render(<PasswordButton {...props} />);
-
+    setup({ isLdapEnabled: true });
     expect(
       screen.getByText("Sign in with username or email"),
     ).toBeInTheDocument();
   });
 });
-
-const getProps = (
-  opts?: Partial<PasswordButtonProps>,
-): PasswordButtonProps => ({
-  isLdapEnabled: false,
-  ...opts,
-});
diff --git a/frontend/src/metabase/auth/components/PasswordButton/index.ts b/frontend/src/metabase/auth/components/PasswordButton/index.ts
index bec09e6cb728712021640bd078184ac4b6d1bcb7..f49cd1686893972accc59d2be3159bab22e27fcf 100644
--- a/frontend/src/metabase/auth/components/PasswordButton/index.ts
+++ b/frontend/src/metabase/auth/components/PasswordButton/index.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./PasswordButton";
+export * from "./PasswordButton";
diff --git a/frontend/src/metabase/auth/components/PasswordPanel/PasswordPanel.tsx b/frontend/src/metabase/auth/components/PasswordPanel/PasswordPanel.tsx
index c062129d2df7735ddbd9f93c013c763cc91f59f2..66ffed0c6b6a57cb4bd6fa0fd750859d05eb09c8 100644
--- a/frontend/src/metabase/auth/components/PasswordPanel/PasswordPanel.tsx
+++ b/frontend/src/metabase/auth/components/PasswordPanel/PasswordPanel.tsx
@@ -1,30 +1,32 @@
 import React, { useCallback } from "react";
 import { t } from "ttag";
-import AuthButton from "../AuthButton";
-import LoginForm from "../LoginForm";
-import { AuthProvider, LoginData } from "../../types";
-import { ActionListItem, ActionList } from "./PasswordPanel.styled";
+import { useDispatch, useSelector } from "metabase/lib/redux";
+import { login } from "../../actions";
+import {
+  getExternalAuthProviders,
+  getHasSessionCookies,
+  getIsLdapEnabled,
+} from "../../selectors";
+import { LoginData } from "../../types";
+import { AuthButton } from "../AuthButton";
+import { LoginForm } from "../LoginForm";
+import { ActionList, ActionListItem } from "./PasswordPanel.styled";
 
-export interface PasswordPanelProps {
-  providers?: AuthProvider[];
+interface PasswordPanelProps {
   redirectUrl?: string;
-  isLdapEnabled: boolean;
-  hasSessionCookies: boolean;
-  onLogin: (data: LoginData, redirectUrl?: string) => void;
 }
 
-const PasswordPanel = ({
-  providers = [],
-  redirectUrl,
-  isLdapEnabled,
-  hasSessionCookies,
-  onLogin,
-}: PasswordPanelProps) => {
+export const PasswordPanel = ({ redirectUrl }: PasswordPanelProps) => {
+  const providers = useSelector(getExternalAuthProviders);
+  const isLdapEnabled = useSelector(getIsLdapEnabled);
+  const hasSessionCookies = useSelector(getHasSessionCookies);
+  const dispatch = useDispatch();
+
   const handleSubmit = useCallback(
     async (data: LoginData) => {
-      await onLogin(data, redirectUrl);
+      await dispatch(login({ data, redirectUrl })).unwrap();
     },
-    [onLogin, redirectUrl],
+    [dispatch, redirectUrl],
   );
 
   return (
@@ -49,6 +51,3 @@ const PasswordPanel = ({
     </div>
   );
 };
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default PasswordPanel;
diff --git a/frontend/src/metabase/auth/components/PasswordPanel/PasswordPanel.unit.spec.tsx b/frontend/src/metabase/auth/components/PasswordPanel/PasswordPanel.unit.spec.tsx
index 35632b19f9e7bbfd2639ec0d94fd58edb1452652..9f13ecf689d4cea9d4abf9b69d2bf6cd98c8b2d2 100644
--- a/frontend/src/metabase/auth/components/PasswordPanel/PasswordPanel.unit.spec.tsx
+++ b/frontend/src/metabase/auth/components/PasswordPanel/PasswordPanel.unit.spec.tsx
@@ -1,19 +1,49 @@
 import React from "react";
+import fetchMock from "fetch-mock";
 import userEvent from "@testing-library/user-event";
-import { render, screen, waitFor } from "__support__/ui";
-import { AuthProvider } from "metabase/auth/types";
-import PasswordPanel, { PasswordPanelProps } from "./PasswordPanel";
+import MetabaseSettings from "metabase/lib/settings";
+import {
+  createMockSettingsState,
+  createMockState,
+} from "metabase-types/store/mocks";
+import { setupLoginEndpoint } from "__support__/server-mocks";
+import { renderWithProviders, screen, waitFor } from "__support__/ui";
+import { PasswordPanel } from "./PasswordPanel";
 
-const NO_REDIRECT_URL_PARAM = undefined;
+const TEST_EMAIL = "user@example.test";
+const TEST_PASSWORD = "password";
+
+interface SetupOpts {
+  isGoogleAuthEnabled?: boolean;
+}
+
+const setup = ({ isGoogleAuthEnabled = false }: SetupOpts = {}) => {
+  const state = createMockState({
+    settings: createMockSettingsState({
+      "google-auth-enabled": isGoogleAuthEnabled,
+    }),
+  });
+
+  MetabaseSettings.set("google-auth-enabled", isGoogleAuthEnabled);
+
+  setupLoginEndpoint();
+  renderWithProviders(<PasswordPanel />, { storeInitialState: state });
+};
+
+const cleanUp = () => {
+  MetabaseSettings.set("google-auth-enabled", false);
+};
 
 describe("PasswordPanel", () => {
+  afterEach(() => {
+    cleanUp();
+  });
+
   it("should login successfully", async () => {
-    const props = getProps();
-    const data = { username: "user@example.test", password: "password" };
+    setup();
 
-    render(<PasswordPanel {...props} />);
-    userEvent.type(screen.getByLabelText("Email address"), data.username);
-    userEvent.type(screen.getByLabelText("Password"), data.password);
+    userEvent.type(screen.getByLabelText("Email address"), TEST_EMAIL);
+    userEvent.type(screen.getByLabelText("Password"), TEST_PASSWORD);
 
     await waitFor(() => {
       expect(screen.getByRole("button", { name: "Sign in" })).toBeEnabled();
@@ -22,35 +52,14 @@ describe("PasswordPanel", () => {
     userEvent.click(screen.getByRole("button", { name: "Sign in" }));
 
     await waitFor(() => {
-      expect(props.onLogin).toHaveBeenCalledWith(
-        { ...data, remember: true },
-        NO_REDIRECT_URL_PARAM,
-      );
+      expect(fetchMock.done("path:/api/session")).toBe(true);
     });
   });
 
   it("should render a link to reset the password and a list of auth providers", () => {
-    const props = getProps({ providers: [getAuthProvider()] });
-
-    render(<PasswordPanel {...props} />);
+    setup({ isGoogleAuthEnabled: true });
 
     expect(screen.getByText(/forgotten my password/)).toBeInTheDocument();
     expect(screen.getByText("Sign in with Google")).toBeInTheDocument();
   });
 });
-
-const getProps = (opts?: Partial<PasswordPanelProps>): PasswordPanelProps => ({
-  providers: [],
-  isLdapEnabled: false,
-  hasSessionCookies: false,
-  onLogin: jest.fn(),
-  ...opts,
-});
-
-const getAuthProvider = (opts?: Partial<AuthProvider>): AuthProvider => ({
-  name: "google",
-  Button: AuthButtonMock,
-  ...opts,
-});
-
-const AuthButtonMock = () => <a href="/">Sign in with Google</a>;
diff --git a/frontend/src/metabase/auth/components/PasswordPanel/index.ts b/frontend/src/metabase/auth/components/PasswordPanel/index.ts
index fc11a70348556ccb0db81d477807fee9c6fc7fa5..797913ce56b5d982a38ef0ac38d745b5ced471d2 100644
--- a/frontend/src/metabase/auth/components/PasswordPanel/index.ts
+++ b/frontend/src/metabase/auth/components/PasswordPanel/index.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./PasswordPanel";
+export * from "./PasswordPanel";
diff --git a/frontend/src/metabase/auth/components/ResetPassword/ResetPassword.tsx b/frontend/src/metabase/auth/components/ResetPassword/ResetPassword.tsx
index d3511320356040a96f5fcc899f006388f46885d6..c4cfa0876cfacd8593b534ce6625767f0f161fd7 100644
--- a/frontend/src/metabase/auth/components/ResetPassword/ResetPassword.tsx
+++ b/frontend/src/metabase/auth/components/ResetPassword/ResetPassword.tsx
@@ -1,49 +1,53 @@
 import React, { useCallback, useEffect, useState } from "react";
+import { replace } from "react-router-redux";
 import { t } from "ttag";
+import { useDispatch } from "metabase/lib/redux";
+import { addUndo } from "metabase/redux/undo";
 import Button from "metabase/core/components/Button";
 import Link from "metabase/core/components/Link";
-import AuthLayout from "../../containers/AuthLayout";
-import ResetPasswordForm from "../ResetPasswordForm";
+import { AuthLayout } from "../AuthLayout";
+import {
+  resetPassword,
+  validatePassword,
+  validatePasswordToken,
+} from "../../actions";
 import { ResetPasswordData } from "../../types";
+import { ResetPasswordForm } from "../ResetPasswordForm";
 import { InfoBody, InfoMessage, InfoTitle } from "./ResetPassword.styled";
 
-type ViewType = "none" | "form" | "success" | "expired";
+type ViewType = "none" | "form" | "expired";
 
-export interface ResetPasswordProps {
+interface ResetPasswordQueryParams {
   token: string;
-  onResetPassword: (token: string, password: string) => void;
-  onValidatePassword: (password: string) => Promise<string | undefined>;
-  onValidatePasswordToken: (token: string) => void;
-  onShowToast: (toast: { message: string }) => void;
-  onRedirect: (url: string) => void;
 }
 
-const ResetPassword = ({
-  token,
-  onResetPassword,
-  onValidatePassword,
-  onValidatePasswordToken,
-  onShowToast,
-  onRedirect,
+interface ResetPasswordProps {
+  params: ResetPasswordQueryParams;
+}
+
+export const ResetPassword = ({
+  params,
 }: ResetPasswordProps): JSX.Element | null => {
+  const { token } = params;
   const [view, setView] = useState<ViewType>("none");
+  const dispatch = useDispatch();
 
   const handleLoad = useCallback(async () => {
     try {
-      await onValidatePasswordToken(token);
+      await validatePasswordToken(token);
       setView("form");
     } catch (error) {
       setView("expired");
     }
-  }, [token, onValidatePasswordToken]);
+  }, [token]);
 
   const handlePasswordSubmit = useCallback(
     async ({ password }: ResetPasswordData) => {
-      await onResetPassword(token, password);
-      onRedirect("/");
-      onShowToast({ message: t`You've updated your password.` });
+      await dispatch(resetPassword({ token, password })).unwrap();
+      dispatch(replace("/"));
+      dispatch(addUndo({ message: t`You've updated your password.` }));
     },
-    [onResetPassword, token, onRedirect, onShowToast],
+    [token, dispatch],
   );
 
   useEffect(() => {
@@ -54,7 +58,7 @@ const ResetPassword = ({
     <AuthLayout>
       {view === "form" && (
         <ResetPasswordForm
-          onValidatePassword={onValidatePassword}
+          onValidatePassword={validatePassword}
           onSubmit={handlePasswordSubmit}
         />
       )}
@@ -76,6 +80,3 @@ const ResetPasswordExpired = (): JSX.Element => {
     </InfoBody>
   );
 };
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default ResetPassword;
diff --git a/frontend/src/metabase/auth/components/ResetPassword/ResetPassword.unit.spec.tsx b/frontend/src/metabase/auth/components/ResetPassword/ResetPassword.unit.spec.tsx
index 82529d56b07d5b4549d88bb0428a49e29c435029..92b2b5ff50023d45d63169cbde1d112bd5b7f738 100644
--- a/frontend/src/metabase/auth/components/ResetPassword/ResetPassword.unit.spec.tsx
+++ b/frontend/src/metabase/auth/components/ResetPassword/ResetPassword.unit.spec.tsx
@@ -1,87 +1,66 @@
-import React, { ReactNode } from "react";
-import { render, screen, waitFor } from "@testing-library/react";
+import React from "react";
+import { Route } from "react-router";
 import userEvent from "@testing-library/user-event";
-import ResetPassword, { ResetPasswordProps } from "./ResetPassword";
+import { createMockSettings, createMockUser } from "metabase-types/api/mocks";
+import {
+  setupCurrentUserEndpoint,
+  setupPasswordCheckEndpoint,
+  setupPasswordResetTokenEndpoint,
+  setupPropertiesEndpoints,
+  setupResetPasswordEndpoint,
+} from "__support__/server-mocks";
+import { renderWithProviders, screen, waitFor } from "__support__/ui";
+import { ResetPassword } from "./ResetPassword";
+
+interface SetupOpts {
+  isTokenValid?: boolean;
+}
 
-describe("ResetPassword", () => {
-  it("should show a form when token validations succeeds", async () => {
-    const props = getProps({
-      onValidatePasswordToken: jest.fn().mockResolvedValue({}),
-    });
+const setup = ({ isTokenValid = true }: SetupOpts = {}) => {
+  setupPasswordResetTokenEndpoint({ valid: isTokenValid });
+  setupResetPasswordEndpoint();
+  setupPasswordCheckEndpoint();
+  setupCurrentUserEndpoint(createMockUser());
+  setupPropertiesEndpoints(createMockSettings());
+
+  renderWithProviders(
+    <>
+      <Route path="/" component={TestHome} />
+      <Route path="/auth/reset_password/:token" component={ResetPassword} />
+    </>,
+    {
+      withRouter: true,
+      initialRoute: "/auth/reset_password/token",
+    },
+  );
+};
 
-    render(<ResetPassword {...props} />);
+const TestHome = () => <div>Home</div>;
 
-    await waitFor(() => {
-      expect(props.onValidatePasswordToken).toHaveBeenCalledWith(props.token);
-    });
-    expect(screen.getByText("New password")).toBeInTheDocument();
+describe("ResetPassword", () => {
+  it("should show a form when token validations succeeds", async () => {
+    setup({ isTokenValid: true });
+    expect(await screen.findByText("New password")).toBeInTheDocument();
   });
 
   it("should show an error message when token validation fails", async () => {
-    const props = getProps({
-      onValidatePasswordToken: jest.fn().mockRejectedValue({}),
-    });
-
-    render(<ResetPassword {...props} />);
-
-    await waitFor(() => {
-      expect(props.onValidatePasswordToken).toHaveBeenCalledWith(props.token);
-    });
-    expect(screen.getByText(/that's an expired link/)).toBeInTheDocument();
+    setup({ isTokenValid: false });
+    expect(
+      await screen.findByText(/that's an expired link/),
+    ).toBeInTheDocument();
   });
 
   it("should show a success message when the form is submitted", async () => {
-    const props = getProps({
-      onResetPassword: jest.fn().mockResolvedValue({}),
-      onValidatePassword: jest.fn().mockResolvedValue(undefined),
-      onValidatePasswordToken: jest.fn().mockResolvedValue({}),
-    });
-
-    render(<ResetPassword {...props} />);
-
-    await waitFor(() => {
-      expect(props.onValidatePasswordToken).toHaveBeenCalledWith(props.token);
-    });
-    expect(screen.getByText("New password")).toBeInTheDocument();
+    setup({ isTokenValid: true });
+    expect(await screen.findByText("New password")).toBeInTheDocument();
 
     userEvent.type(screen.getByLabelText("Create a password"), "test");
     userEvent.type(screen.getByLabelText("Confirm your password"), "test");
-
     await waitFor(() => {
-      expect(props.onValidatePassword).toHaveBeenCalledWith("test");
+      expect(screen.getByText("Save new password")).toBeEnabled();
     });
-    expect(screen.getByText("Save new password")).toBeEnabled();
 
     userEvent.click(screen.getByText("Save new password"));
-
-    await waitFor(() => {
-      expect(props.onResetPassword).toHaveBeenCalledWith(props.token, "test");
-    });
-    expect(props.onRedirect).toHaveBeenCalledWith("/");
-    expect(props.onShowToast).toHaveBeenCalledWith({
-      message: "You've updated your password.",
-    });
+    expect(await screen.findByText("Home")).toBeInTheDocument();
   });
 });
-
-const getProps = (opts?: Partial<ResetPasswordProps>): ResetPasswordProps => {
-  return {
-    token: "token",
-    onResetPassword: jest.fn(),
-    onValidatePassword: jest.fn(),
-    onValidatePasswordToken: jest.fn(),
-    onShowToast: jest.fn(),
-    onRedirect: jest.fn(),
-    ...opts,
-  };
-};
-
-interface AuthLayoutMockProps {
-  children?: ReactNode;
-}
-
-const AuthLayoutMock = ({ children }: AuthLayoutMockProps) => {
-  return <div>{children}</div>;
-};
-
-jest.mock("../../containers/AuthLayout", () => AuthLayoutMock);
diff --git a/frontend/src/metabase/auth/components/ResetPassword/index.ts b/frontend/src/metabase/auth/components/ResetPassword/index.ts
index 86d695e57e9b4698f8b9d664fec1c8aee8c12ba2..795c2ccaf7557568e2d098beeaab00ba876ac761 100644
--- a/frontend/src/metabase/auth/components/ResetPassword/index.ts
+++ b/frontend/src/metabase/auth/components/ResetPassword/index.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./ResetPassword";
+export * from "./ResetPassword";
diff --git a/frontend/src/metabase/auth/components/ResetPasswordForm/ResetPasswordForm.tsx b/frontend/src/metabase/auth/components/ResetPasswordForm/ResetPasswordForm.tsx
index 47fea0cf85c31645b27a6d0ced55fad3db47209b..5ba748830ba82bcdb37fc20518f0482f12caf654 100644
--- a/frontend/src/metabase/auth/components/ResetPasswordForm/ResetPasswordForm.tsx
+++ b/frontend/src/metabase/auth/components/ResetPasswordForm/ResetPasswordForm.tsx
@@ -34,7 +34,7 @@ interface ResetPasswordFormProps {
   onSubmit: (data: ResetPasswordData) => void;
 }
 
-const ResetPasswordForm = ({
+export const ResetPasswordForm = ({
   onValidatePassword,
   onSubmit,
 }: ResetPasswordFormProps): JSX.Element => {
@@ -86,6 +86,3 @@ const ResetPasswordForm = ({
     </div>
   );
 };
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default ResetPasswordForm;
diff --git a/frontend/src/metabase/auth/components/ResetPasswordForm/index.ts b/frontend/src/metabase/auth/components/ResetPasswordForm/index.ts
index 08304903847209155f224980cb6be94af5b67e75..090b601ad708fa29c72edb5c05eafabe42531e70 100644
--- a/frontend/src/metabase/auth/components/ResetPasswordForm/index.ts
+++ b/frontend/src/metabase/auth/components/ResetPasswordForm/index.ts
@@ -1,2 +1 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./ResetPasswordForm";
+export * from "./ResetPasswordForm";
diff --git a/frontend/src/metabase/auth/containers/AuthLayout/AuthLayout.tsx b/frontend/src/metabase/auth/containers/AuthLayout/AuthLayout.tsx
deleted file mode 100644
index 5376dc2139655168fdd19756238a3ab214521225..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/AuthLayout/AuthLayout.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import { connect } from "react-redux";
-import { getSetting } from "metabase/selectors/settings";
-import type { State } from "metabase-types/store";
-import AuthLayout from "../../components/AuthLayout";
-
-const mapStateToProps = (state: State) => ({
-  showIllustration: getSetting(state, "show-lighthouse-illustration"),
-});
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default connect(mapStateToProps)(AuthLayout);
diff --git a/frontend/src/metabase/auth/containers/AuthLayout/index.ts b/frontend/src/metabase/auth/containers/AuthLayout/index.ts
deleted file mode 100644
index d2486700846e8f2b98799e8d24ea28f91105aea1..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/AuthLayout/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./AuthLayout";
diff --git a/frontend/src/metabase/auth/containers/ForgotPasswordApp/ForgotPasswordApp.tsx b/frontend/src/metabase/auth/containers/ForgotPasswordApp/ForgotPasswordApp.tsx
deleted file mode 100644
index 376bb780004995fc8b3cf88d5909676f21545129..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/ForgotPasswordApp/ForgotPasswordApp.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import { connect } from "react-redux";
-import MetabaseSettings from "metabase/lib/settings";
-import ForgotPassword from "../../components/ForgotPassword";
-import { forgotPassword } from "../../actions";
-
-const canResetPassword = () => {
-  const isEmailConfigured = MetabaseSettings.isEmailConfigured();
-  const isLdapEnabled = MetabaseSettings.isLdapEnabled();
-  return isEmailConfigured && !isLdapEnabled;
-};
-
-const mapStateToProps = (state: any, props: any) => ({
-  canResetPassword: canResetPassword(),
-  initialEmail: props.location.query.email,
-});
-
-const mapDispatchToProps = {
-  onResetPassword: forgotPassword,
-};
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default connect(mapStateToProps, mapDispatchToProps)(ForgotPassword);
diff --git a/frontend/src/metabase/auth/containers/ForgotPasswordApp/index.ts b/frontend/src/metabase/auth/containers/ForgotPasswordApp/index.ts
deleted file mode 100644
index 2c8a60e5c75e106997a29da807d1800dbfa72084..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/ForgotPasswordApp/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./ForgotPasswordApp";
diff --git a/frontend/src/metabase/auth/containers/GoogleButton/GoogleButton.tsx b/frontend/src/metabase/auth/containers/GoogleButton/GoogleButton.tsx
deleted file mode 100644
index 774794360dda68fc9c65e43bc9e3ea2535a6195f..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/GoogleButton/GoogleButton.tsx
+++ /dev/null
@@ -1,17 +0,0 @@
-import { connect } from "react-redux";
-import { getSetting } from "metabase/selectors/settings";
-import type { State } from "metabase-types/store";
-import GoogleButton from "../../components/GoogleButton";
-import { loginGoogle } from "../../actions";
-
-const mapStateToProps = (state: State) => ({
-  clientId: getSetting(state, "google-auth-client-id"),
-  locale: getSetting(state, "site-locale"),
-});
-
-const mapDispatchToProps = {
-  onLogin: loginGoogle,
-};
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default connect(mapStateToProps, mapDispatchToProps)(GoogleButton);
diff --git a/frontend/src/metabase/auth/containers/GoogleButton/index.ts b/frontend/src/metabase/auth/containers/GoogleButton/index.ts
deleted file mode 100644
index 077d745d8ae34ac0711dc7e66e46a17c5a00244d..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/GoogleButton/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./GoogleButton";
diff --git a/frontend/src/metabase/auth/containers/LoginApp/LoginApp.tsx b/frontend/src/metabase/auth/containers/LoginApp/LoginApp.tsx
deleted file mode 100644
index 231097f2022d82487aaffe36943c5c87df655736..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/LoginApp/LoginApp.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { connect } from "react-redux";
-import Login from "../../components/Login";
-import { getAuthProviders } from "../../selectors";
-
-const mapStateToProps = (state: any, props: any) => ({
-  providers: getAuthProviders(state),
-  providerName: props.params.provider,
-  redirectUrl: props.location.query.redirect,
-});
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default connect(mapStateToProps)(Login);
diff --git a/frontend/src/metabase/auth/containers/LoginApp/index.ts b/frontend/src/metabase/auth/containers/LoginApp/index.ts
deleted file mode 100644
index f5b3eca7e1f71bd24a959ad431baf3d3c7adb6cf..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/LoginApp/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./LoginApp";
diff --git a/frontend/src/metabase/auth/containers/LogoutApp/LogoutApp.tsx b/frontend/src/metabase/auth/containers/LogoutApp/LogoutApp.tsx
deleted file mode 100644
index 7a0faba288d4efa1ae56ec78a0aa06f34ff1e015..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/LogoutApp/LogoutApp.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import { connect } from "react-redux";
-import { logout } from "../../actions";
-import Logout from "../../components/Logout";
-
-const mapDispatchToProps = {
-  onLogout: logout,
-};
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default connect(null, mapDispatchToProps)(Logout);
diff --git a/frontend/src/metabase/auth/containers/LogoutApp/index.ts b/frontend/src/metabase/auth/containers/LogoutApp/index.ts
deleted file mode 100644
index e4a8be262cfb728bee444fe7e2f47c1a548451c6..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/LogoutApp/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./LogoutApp";
diff --git a/frontend/src/metabase/auth/containers/PasswordButton/PasswordButton.tsx b/frontend/src/metabase/auth/containers/PasswordButton/PasswordButton.tsx
deleted file mode 100644
index 7943c8361a3ec1897b2230a8ca7a2567121ba511..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/PasswordButton/PasswordButton.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import { connect } from "react-redux";
-import { getSetting } from "metabase/selectors/settings";
-import type { State } from "metabase-types/store";
-import PasswordButton from "../../components/PasswordButton";
-
-const mapStateToProps = (state: State) => ({
-  isLdapEnabled: getSetting(state, "ldap-enabled"),
-});
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default connect(mapStateToProps, null)(PasswordButton);
diff --git a/frontend/src/metabase/auth/containers/PasswordButton/index.ts b/frontend/src/metabase/auth/containers/PasswordButton/index.ts
deleted file mode 100644
index bec09e6cb728712021640bd078184ac4b6d1bcb7..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/PasswordButton/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./PasswordButton";
diff --git a/frontend/src/metabase/auth/containers/PasswordPanel/PasswordPanel.tsx b/frontend/src/metabase/auth/containers/PasswordPanel/PasswordPanel.tsx
deleted file mode 100644
index b809ee32ef4cea9fdc9e01f7eb08b12bb54bcbff..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/PasswordPanel/PasswordPanel.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { connect } from "react-redux";
-import { getSetting } from "metabase/selectors/settings";
-import { getExternalAuthProviders } from "metabase/auth/selectors";
-import type { State } from "metabase-types/store";
-import { login } from "../../actions";
-import PasswordPanel from "../../components/PasswordPanel";
-
-const mapStateToProps = (state: State) => ({
-  providers: getExternalAuthProviders(state),
-  isLdapEnabled: getSetting(state, "ldap-enabled"),
-  hasSessionCookies: getSetting(state, "session-cookies") ?? false,
-});
-
-const mapDispatchToProps = {
-  onLogin: login,
-};
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default connect(mapStateToProps, mapDispatchToProps)(PasswordPanel);
diff --git a/frontend/src/metabase/auth/containers/PasswordPanel/index.ts b/frontend/src/metabase/auth/containers/PasswordPanel/index.ts
deleted file mode 100644
index fc11a70348556ccb0db81d477807fee9c6fc7fa5..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/PasswordPanel/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./PasswordPanel";
diff --git a/frontend/src/metabase/auth/containers/ResetPasswordApp/ResetPasswordApp.tsx b/frontend/src/metabase/auth/containers/ResetPasswordApp/ResetPasswordApp.tsx
deleted file mode 100644
index a72e6801fe18abbd28c2b7c0534f920641eecec8..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/ResetPasswordApp/ResetPasswordApp.tsx
+++ /dev/null
@@ -1,24 +0,0 @@
-import { connect } from "react-redux";
-import { replace } from "react-router-redux";
-import { addUndo } from "metabase/redux/undo";
-import ResetPassword from "../../components/ResetPassword";
-import {
-  resetPassword,
-  validatePassword,
-  validatePasswordToken,
-} from "../../actions";
-
-const mapStateToProps = (state: any, props: any) => ({
-  token: props.params.token,
-  onValidatePassword: validatePassword,
-});
-
-const mapDispatchToProps = {
-  onResetPassword: resetPassword,
-  onValidatePasswordToken: validatePasswordToken,
-  onShowToast: addUndo,
-  onRedirect: replace,
-};
-
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export default connect(mapStateToProps, mapDispatchToProps)(ResetPassword);
diff --git a/frontend/src/metabase/auth/containers/ResetPasswordApp/index.ts b/frontend/src/metabase/auth/containers/ResetPasswordApp/index.ts
deleted file mode 100644
index 2b9b38a54192732844f784abc0f8c560cf331e03..0000000000000000000000000000000000000000
--- a/frontend/src/metabase/auth/containers/ResetPasswordApp/index.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// eslint-disable-next-line import/no-default-export -- deprecated usage
-export { default } from "./ResetPasswordApp";
diff --git a/frontend/src/metabase/auth/selectors.ts b/frontend/src/metabase/auth/selectors.ts
index 3e591d6347a3096c6cbcdcf2a0180e585adb6fbe..67d9ca6a51ba05a955a1d64e7730a5e00264549d 100644
--- a/frontend/src/metabase/auth/selectors.ts
+++ b/frontend/src/metabase/auth/selectors.ts
@@ -1,21 +1,43 @@
 import { createSelector } from "@reduxjs/toolkit";
-
-import { getSettings } from "metabase/selectors/settings";
 import { PLUGIN_AUTH_PROVIDERS } from "metabase/plugins";
+import { getSetting, getSettings } from "metabase/selectors/settings";
+import { AuthProvider } from "metabase/plugins/types";
+import { State } from "metabase-types/store";
 
-import type { AuthProvider } from "./types";
+const EMPTY_PROVIDERS: AuthProvider[] = [];
 
-export const getAuthProviders = createSelector(
-  [getSettings],
-  (): AuthProvider[] =>
-    PLUGIN_AUTH_PROVIDERS.reduce(
-      (providers: any, getProviders: (providers: any) => any) =>
-        getProviders(providers),
-      [],
-    ),
+export const getAuthProviders = createSelector([getSettings], () =>
+  PLUGIN_AUTH_PROVIDERS.reduce(
+    (providers, getProviders) => getProviders(providers),
+    EMPTY_PROVIDERS,
+  ),
 );
 
 export const getExternalAuthProviders = createSelector(
   [getAuthProviders],
   providers => providers.filter(provider => provider.name !== "password"),
 );
+
+export const getIsEmailConfigured = (state: State) => {
+  return getSetting(state, "email-configured?");
+};
+
+export const getIsLdapEnabled = (state: State) => {
+  return getSetting(state, "ldap-enabled");
+};
+
+export const getHasSessionCookies = (state: State) => {
+  return getSetting(state, "session-cookies") ?? false;
+};
+
+export const getHasIllustration = (state: State) => {
+  return getSetting(state, "show-lighthouse-illustration");
+};
+
+export const getSiteLocale = (state: State) => {
+  return getSetting(state, "site-locale");
+};
+
+export const getGoogleClientId = (state: State) => {
+  return getSetting(state, "google-auth-client-id");
+};
diff --git a/frontend/src/metabase/auth/types.ts b/frontend/src/metabase/auth/types.ts
index 56db8b5d314431615dfce35c97687f1151a908be..1b2fdc4c98fdab28754b7f54fb910be1cc968961 100644
--- a/frontend/src/metabase/auth/types.ts
+++ b/frontend/src/metabase/auth/types.ts
@@ -1,20 +1,3 @@
-import { ComponentType } from "react";
-
-export interface AuthProvider {
-  name: string;
-  Button: ComponentType<AuthProviderButtonProps>;
-  Panel?: ComponentType<AuthProviderPanelProps>;
-}
-
-export interface AuthProviderButtonProps {
-  isCard?: boolean;
-  redirectUrl?: string;
-}
-
-export interface AuthProviderPanelProps {
-  redirectUrl?: string;
-}
-
 export interface LoginData {
   username: string;
   password: string;
diff --git a/frontend/src/metabase/lib/urls/auth.ts b/frontend/src/metabase/lib/urls/auth.ts
index 2fe58a88975f06f5f1a8a447c5feece17d6530a1..e7478513cdd8a3bcfc9caa6737ce5ced9ac9cc71 100644
--- a/frontend/src/metabase/lib/urls/auth.ts
+++ b/frontend/src/metabase/lib/urls/auth.ts
@@ -3,3 +3,9 @@ export const login = (redirectUrl?: string) => {
     ? `/auth/login?redirect=${encodeURIComponent(redirectUrl)}`
     : "/auth/login";
 };
+
+export const password = (redirectUrl?: string) => {
+  return redirectUrl
+    ? `/auth/login/password?redirect=${encodeURIComponent(redirectUrl)}`
+    : `/auth/login/password`;
+};
diff --git a/frontend/src/metabase/plugins/builtin/auth/google.js b/frontend/src/metabase/plugins/builtin/auth/google.js
index 75eba2180fab337112702493b871d8c1d549bb9b..20241f682727f6ca697e0e49c2fd88800d6bcc08 100644
--- a/frontend/src/metabase/plugins/builtin/auth/google.js
+++ b/frontend/src/metabase/plugins/builtin/auth/google.js
@@ -16,7 +16,7 @@ PLUGIN_AUTH_PROVIDERS.push(providers => {
   const googleProvider = {
     name: "google",
     // circular dependencies
-    Button: require("metabase/auth/containers/GoogleButton").default,
+    Button: require("metabase/auth/components/GoogleButton").GoogleButton,
   };
 
   return MetabaseSettings.isGoogleAuthEnabled()
diff --git a/frontend/src/metabase/plugins/builtin/auth/password.js b/frontend/src/metabase/plugins/builtin/auth/password.js
index 05da06692a7eae37b799f20878dde191925b07b4..15f030d5d370737bd0a2e89453c5183910f1dfb9 100644
--- a/frontend/src/metabase/plugins/builtin/auth/password.js
+++ b/frontend/src/metabase/plugins/builtin/auth/password.js
@@ -4,8 +4,8 @@ PLUGIN_AUTH_PROVIDERS.push(providers => {
   const passwordProvider = {
     name: "password",
     // circular dependencies
-    Button: require("metabase/auth/containers/PasswordButton").default,
-    Panel: require("metabase/auth/containers/PasswordPanel").default,
+    Button: require("metabase/auth/components/PasswordButton").PasswordButton,
+    Panel: require("metabase/auth/components/PasswordPanel").PasswordPanel,
   };
 
   return [...providers, passwordProvider];
diff --git a/frontend/src/metabase/plugins/index.ts b/frontend/src/metabase/plugins/index.ts
index bab05eb3a81da0d19e07038db7cda4f47708e438..bb5b00b141ef16cc0e1f60ef6324d2eb2f389498 100644
--- a/frontend/src/metabase/plugins/index.ts
+++ b/frontend/src/metabase/plugins/index.ts
@@ -23,7 +23,7 @@ import type {
 import type { AdminPathKey, State } from "metabase-types/store";
 import type Question from "metabase-lib/Question";
 
-import { PluginGroupManagersType } from "./types";
+import { GetAuthProviders, PluginGroupManagersType } from "./types";
 
 // functions called when the application is started
 export const PLUGIN_APP_INIT_FUCTIONS = [];
@@ -79,7 +79,7 @@ export const PLUGIN_ADMIN_USER_MENU_ITEMS = [];
 export const PLUGIN_ADMIN_USER_MENU_ROUTES = [];
 
 // authentication providers
-export const PLUGIN_AUTH_PROVIDERS = [] as any;
+export const PLUGIN_AUTH_PROVIDERS: GetAuthProviders[] = [];
 
 // Only show the password tab in account settings if these functions all return true.
 // Otherwise, the user is logged in via SSO and should hide first name, last name, and email field in profile settings metabase#23298.
diff --git a/frontend/src/metabase/plugins/types.ts b/frontend/src/metabase/plugins/types.ts
index d0ab96c45cab72f42b7d8b9a52b4b40664fe4463..2622f0baa46c697b924813b37bdd556da6af8c21 100644
--- a/frontend/src/metabase/plugins/types.ts
+++ b/frontend/src/metabase/plugins/types.ts
@@ -1,5 +1,23 @@
-import { Member, User } from "metabase-types/api";
-import { ConfirmationState } from "metabase/hooks/use-confirmation";
+import type { ComponentType } from "react";
+import type { Member, User } from "metabase-types/api";
+import type { ConfirmationState } from "metabase/hooks/use-confirmation";
+
+export interface AuthProvider {
+  name: string;
+  Button: ComponentType<AuthProviderButtonProps>;
+  Panel?: ComponentType<AuthProviderPanelProps>;
+}
+
+export interface AuthProviderButtonProps {
+  isCard?: boolean;
+  redirectUrl?: string;
+}
+
+export interface AuthProviderPanelProps {
+  redirectUrl?: string;
+}
+
+export type GetAuthProviders = (providers: AuthProvider[]) => AuthProvider[];
 
 export type GetChangeMembershipConfirmation = (
   currentUser: User,
diff --git a/frontend/src/metabase/routes.jsx b/frontend/src/metabase/routes.jsx
index 6c1e9ecb91e8f5c93d146baa16744f38886535eb..811f20865f7aa1ac0a3df52e7b916957602546b3 100644
--- a/frontend/src/metabase/routes.jsx
+++ b/frontend/src/metabase/routes.jsx
@@ -14,10 +14,10 @@ import ModelMetabotApp from "metabase/metabot/containers/ModelMetabotApp";
 import DatabaseMetabotApp from "metabase/metabot/containers/DatabaseMetabotApp";
 
 // auth containers
-import ForgotPasswordApp from "metabase/auth/containers/ForgotPasswordApp";
-import LoginApp from "metabase/auth/containers/LoginApp";
-import LogoutApp from "metabase/auth/containers/LogoutApp";
-import ResetPasswordApp from "metabase/auth/containers/ResetPasswordApp";
+import { ForgotPassword } from "metabase/auth/components/ForgotPassword";
+import { Login } from "metabase/auth/components/Login";
+import { Logout } from "metabase/auth/components/Logout";
+import { ResetPassword } from "metabase/auth/components/ResetPassword";
 
 /* Dashboards */
 import DashboardApp from "metabase/dashboard/containers/DashboardApp";
@@ -131,12 +131,12 @@ export const getRoutes = store => (
       <Route path="/auth">
         <IndexRedirect to="/auth/login" />
         <Route component={IsNotAuthenticated}>
-          <Route path="login" title={t`Login`} component={LoginApp} />
-          <Route path="login/:provider" title={t`Login`} component={LoginApp} />
+          <Route path="login" title={t`Login`} component={Login} />
+          <Route path="login/:provider" title={t`Login`} component={Login} />
         </Route>
-        <Route path="logout" component={LogoutApp} />
-        <Route path="forgot_password" component={ForgotPasswordApp} />
-        <Route path="reset_password/:token" component={ResetPasswordApp} />
+        <Route path="logout" component={Logout} />
+        <Route path="forgot_password" component={ForgotPassword} />
+        <Route path="reset_password/:token" component={ResetPassword} />
       </Route>
 
       {/* MAIN */}
diff --git a/frontend/test/__support__/server-mocks/index.ts b/frontend/test/__support__/server-mocks/index.ts
index 800d5d5ad87b0c09771af3c73568486a8b146051..4c3d251b48cbe3eab4fe727c5fb0e4b8185f7e87 100644
--- a/frontend/test/__support__/server-mocks/index.ts
+++ b/frontend/test/__support__/server-mocks/index.ts
@@ -20,3 +20,5 @@ export * from "./setup";
 export * from "./store";
 export * from "./table";
 export * from "./timeline";
+export * from "./user";
+export * from "./util";
diff --git a/frontend/test/__support__/server-mocks/session.ts b/frontend/test/__support__/server-mocks/session.ts
index d5840c7c5a61f44ba0a90e9201ca5eb54c7ec054..0916477947b880318333aa0aee7462d359a7461c 100644
--- a/frontend/test/__support__/server-mocks/session.ts
+++ b/frontend/test/__support__/server-mocks/session.ts
@@ -1,6 +1,26 @@
 import fetchMock from "fetch-mock";
-import { Settings } from "metabase-types/api";
+import { PasswordResetTokenInfo, Settings } from "metabase-types/api";
 
 export function setupPropertiesEndpoints(settings: Settings) {
   fetchMock.get("path:/api/session/properties", settings);
 }
+
+export function setupLoginEndpoint() {
+  fetchMock.post("path:/api/session", 204);
+}
+
+export function setupLogoutEndpoint() {
+  fetchMock.delete("path:/api/session", 204);
+}
+
+export function setupForgotPasswordEndpoint() {
+  fetchMock.post("path:/api/session/forgot_password", 204);
+}
+
+export function setupResetPasswordEndpoint() {
+  fetchMock.post("path:/api/session/reset_password", 204);
+}
+
+export function setupPasswordResetTokenEndpoint(info: PasswordResetTokenInfo) {
+  fetchMock.get("path:/api/session/password_reset_token_valid", info);
+}
diff --git a/frontend/test/__support__/server-mocks/user.ts b/frontend/test/__support__/server-mocks/user.ts
index 0eda1fcc68718a43ef073676cbe5ecdce6785459..548cc970f3170557cfbcf89719c3142db3fd221a 100644
--- a/frontend/test/__support__/server-mocks/user.ts
+++ b/frontend/test/__support__/server-mocks/user.ts
@@ -1,6 +1,10 @@
 import fetchMock from "fetch-mock";
-import { UserListResult } from "metabase-types/api";
+import { User, UserListResult } from "metabase-types/api";
 
 export function setupUsersEndpoints(users: UserListResult[]) {
   fetchMock.get("path:/api/user", users);
 }
+
+export function setupCurrentUserEndpoint(user: User) {
+  fetchMock.get("path:/api/user/current", user);
+}
diff --git a/frontend/test/__support__/server-mocks/util.ts b/frontend/test/__support__/server-mocks/util.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0a47c6f3aa7fd4171f4d230fc222632d4897f65e
--- /dev/null
+++ b/frontend/test/__support__/server-mocks/util.ts
@@ -0,0 +1,5 @@
+import fetchMock from "fetch-mock";
+
+export function setupPasswordCheckEndpoint() {
+  fetchMock.post("path:/api/util/password_check", 204);
+}