diff --git a/src/api/SwaggerApi.js b/src/api/SwaggerApi.js
index ca80c3923f21d847fe76d9f4428a16ddb4c21b95..9e29a25489fb8fcfa8891a2c4865f74b6b51862d 100644
--- a/src/api/SwaggerApi.js
+++ b/src/api/SwaggerApi.js
@@ -350,110 +350,6 @@ const emptyRecordListResponse = {
   recordList: []
 };
 
-export function unpackLogin(loginResponse) {
-  return { ...loginResponse };
-}
-
-export function useLogin(onError) {
-  const api = useContext(apiContext);
-  const method = useCallAndUnpack(
-    (username, password) =>
-      api.apis.Authentication.login(
-        {},
-        {
-          requestBody: {
-            userName: username,
-            password: password
-          }
-        }
-      ),
-    unpackLogin
-  );
-  return useAsync({ fcn: method, call: false, onError: onError });
-}
-
-export function unpackUser(user) {
-  if (user?.length > 0) {
-    return { ...user[0] };
-  } else {
-    return {};
-  }
-}
-
-export function useUser() {
-  const onError = useCallback((message) => {
-    console.warn("useUser error: ", message);
-  }, []);
-
-  const [userInfo, getUserInfo, resetUserInfo, userInfoLoading] = useUserInfo(
-    null,
-    onError
-  );
-  const [userRoles, getUserRoles, resetUserRoles, userRolesLoading] =
-    useUserRoles(onError);
-  const [user, setUser] = useState();
-  const [loading, setLoading] = useState(true);
-
-  const dataLoading = userInfoLoading || userRolesLoading;
-
-  useEffect(() => {
-    // userInfo and user Roles should:
-    // - both be defined when logged in
-    // - both be undefined when logged out
-    const loginStateConsistent = Boolean(userInfo) === Boolean(userRoles);
-    if (loginStateConsistent && !dataLoading) {
-      setUser({ userInfo, userRoles });
-      setLoading(false);
-    }
-  }, [dataLoading, userInfo, userRoles]);
-
-  const getUser = useCallback(() => {
-    setLoading(true);
-    getUserInfo();
-    getUserRoles();
-  }, [getUserInfo, getUserRoles]);
-
-  const resetUser = useCallback(() => {
-    setLoading(true);
-    resetUserInfo();
-    resetUserRoles();
-  }, [resetUserInfo, resetUserRoles]);
-
-  return [user, getUser, resetUser, loading];
-}
-
-export function useUserInfo(userName, onError) {
-  const api = useContext(apiContext);
-  const method = useCallAndUnpack(api.apis.Git.infoFromUserName, unpackUser);
-  const boundMethod = useCallback(method.bind(null, { user_name: userName }), [
-    userName
-  ]);
-  return useAsync({ fcn: boundMethod, call: false, onError: onError });
-}
-
-export function unpackUserRoles(roles) {
-  return roles;
-}
-
-export function useUserRoles(onError) {
-  const api = useContext(apiContext);
-  const method = useCallAndUnpack(
-    api.apis.Authentication.getUserRoles,
-    unpackUserRoles
-  );
-  return useAsync({ fcn: method, call: false, onError: onError });
-}
-
-export function useLogout() {
-  const api = useContext(apiContext);
-  const method = useCallAndUnpack(api.apis.Authentication.logout);
-  const [, /* value*/ logout /* reset*/, , loading] = useAsync({
-    fcn: method,
-    call: false
-  });
-  return [logout, loading];
-}
-
 export function useStartIOC(id, onError) {
   const api = useContext(apiContext);
   const method = useCallAndUnpack(api.apis.IOCs.startIoc);
diff --git a/src/api/UserProvider.js b/src/api/UserProvider.js
index 1ac4a6a9cfa7be16310650a3d5d15fc2d162b633..f0ba41b79679b119c7778e5ffb99f0bd543a801e 100644
--- a/src/api/UserProvider.js
+++ b/src/api/UserProvider.js
@@ -1,58 +1,108 @@
 import React from "react";
-import { useCallback, useEffect, useState } from "react";
-import { useLogin, useLogout, useUser } from "./SwaggerApi";
-import { userContext } from "@ess-ics/ce-ui-common";
+import { useCallback, useEffect, useState, useContext } from "react";
+import { userContext, useAPIMethod } from "@ess-ics/ce-ui-common";
+import { apiContext } from "./SwaggerApi";
 
-export function UserProvider({ children }) {
-  function onLoginError(message) {
-    setLoginError(message);
+function loginRequest(username, password) {
+  return {
+    userName: username, // fyi on template it is username, but on deploy it is userName
+    password: password
+  };
+}
+
+function unpackUser(user) {
+  if (user?.length > 0) {
+    return { ...user[0] };
+  } else {
+    return {};
   }
+}
 
-  const [user, getUser, resetUser, userLoading] = useUser();
-  const [loginError, setLoginError] = useState();
-  const [loginResponse, loginFcn /* reset*/, , loginLoading] =
-    useLogin(onLoginError);
-  const [logoutFcn, logoutLoading] = useLogout();
+export function UserProvider({ children }) {
   const [initialized, setInitialized] = useState(false);
+  const [user, setUser] = useState(null);
+  const [userRoles, setUserRoles] = useState([]);
+  const [loginErrorMsg, setLoginErrorMsg] = useState();
 
-  const resetLoginError = useCallback(
-    () => setLoginError(null),
-    [setLoginError]
-  );
-
-  useEffect(getUser, [loginResponse, getUser]);
-
-  const logout = useCallback(async () => {
-    resetUser();
-    logoutFcn();
-  }, [resetUser, logoutFcn]);
+  const client = useContext(apiContext);
+  const {
+    error: loginError,
+    wrapper: callLoginAPI,
+    value: loginResponse,
+    loading: loginLoading
+  } = useAPIMethod({ fcn: client.apis.Authentication.login, call: false });
+  const {
+    wrapper: callUserAPI,
+    value: userResponse,
+    loading: userLoading
+  } = useAPIMethod({
+    fcn: client.apis.Git.infoFromUserName,
+    call: true,
+    unpacker: unpackUser
+  });
+  const { wrapper: callLogoutAPI, loading: logoutLoading } = useAPIMethod({
+    fcn: client.apis.Authentication.logout,
+    call: false
+  });
+  const {
+    wrapper: callUserRolesAPI,
+    value: userRolesResponse,
+    loading: userRolesLoading
+  } = useAPIMethod({
+    fcn: client.apis.Authentication.getUserRoles,
+    call: true
+  });
 
   const login = useCallback(
     (username, password) => {
-      loginFcn(username, password);
+      callLoginAPI({}, { requestBody: loginRequest(username, password) });
     },
-    [loginFcn]
+    [callLoginAPI]
   );
 
-  const loading = Boolean(loginLoading || userLoading || logoutLoading);
+  const logout = useCallback(() => {
+    callLogoutAPI({}, {});
+    setUser(null);
+  }, [callLogoutAPI]);
+
+  useEffect(() => {
+    if (loginResponse) {
+      callUserAPI();
+      callUserRolesAPI();
+    }
+  }, [loginResponse, callUserAPI, callUserRolesAPI]);
+
+  useEffect(() => {
+    setUser(userResponse);
+  }, [userResponse, setUser]);
+
+  useEffect(() => {
+    setUserRoles(userRolesResponse);
+  }, [userRolesResponse, setUserRoles]);
+
+  const loading = Boolean(
+    loginLoading || userLoading || userRolesLoading || logoutLoading
+  );
+
+  useEffect(() => {
+    setLoginErrorMsg(loginError?.response?.body?.description);
+  }, [loginError]);
+
+  const resetLoginError = useCallback(
+    () => setLoginErrorMsg(null),
+    [setLoginErrorMsg]
+  );
 
   const createValue = useCallback(() => {
     return {
-      user: user?.userInfo,
-      userRoles: user?.userRoles,
+      user: user,
+      userRoles: userRoles,
       login,
-      loginError,
-      resetLoginError,
-      logout
+      loginError: loginErrorMsg,
+      logout,
+      resetLoginError
     };
-  }, [
-    user?.userInfo,
-    user?.userRoles,
-    login,
-    loginError,
-    resetLoginError,
-    logout
-  ]);
+  }, [user, userRoles, login, loginErrorMsg, logout, resetLoginError]);
 
   const [value, setValue] = useState(createValue());
 
diff --git a/src/components/IOC/IOCTable/IOCDescription.js b/src/components/IOC/IOCTable/IOCDescription.js
index 68fdf85abbfd3a84e025cceb34d1e9581f040362..a61e06b043205cfd1e272feb1e4db62c50cdadc6 100644
--- a/src/components/IOC/IOCTable/IOCDescription.js
+++ b/src/components/IOC/IOCTable/IOCDescription.js
@@ -1,5 +1,5 @@
 import React, { useContext, useMemo } from "react";
-import { apiContext } from "../../../api/SwaggerApi";
+import { apiContext } from "../../../api/DeployApi";
 import { Skeleton, Tooltip, Typography } from "@mui/material";
 import { useAPIMethod } from "@ess-ics/ce-ui-common";
 
diff --git a/src/components/navigation/NavigationMenu/LoginControls.js b/src/components/navigation/NavigationMenu/LoginControls.js
index 8e00b7cf3127998cbb0c156d6b30807c7935e8f2..8998e226db161871b5d13f91fe2d6d4bd9936e34 100644
--- a/src/components/navigation/NavigationMenu/LoginControls.js
+++ b/src/components/navigation/NavigationMenu/LoginControls.js
@@ -24,7 +24,7 @@ export function ProfileMenu({ user }) {
   const { userRoles, logout } = useContext(userContext);
   const navigate = useNavigate();
 
-  const objUserRoles = userRoles
+  const objUserRoles = (userRoles ?? [])
     ?.filter((role) => role.includes("DeploymentTool"))
     ?.map((role) => ({
       text: (
diff --git a/src/views/UserPage/UserDetailsContainer.js b/src/views/UserPage/UserDetailsContainer.js
index 868c4c84783f4649b0e77beae93c712bfa9ac668..aa6900cf9a21b8e490dc69994f91664ca1574bda 100644
--- a/src/views/UserPage/UserDetailsContainer.js
+++ b/src/views/UserPage/UserDetailsContainer.js
@@ -1,68 +1,88 @@
-import React, { useContext, useEffect, useState } from "react";
+import React, { useContext, useEffect, useMemo, useState } from "react";
 import { UserPageView } from "./UserPageView";
 import { LinearProgress } from "@mui/material";
 import NotFoundView from "../../components/navigation/NotFoundView/NotFoundView";
-import { useUserInfo } from "../../api/SwaggerApi";
 import { useParams } from "react-router-dom";
-import { userContext } from "@ess-ics/ce-ui-common/dist/contexts/User";
+import { userContext, useAPIMethod } from "@ess-ics/ce-ui-common";
+import { apiContext } from "../../api/DeployApi";
+
+function unpackUser(user) {
+  if (user?.length > 0) {
+    return { ...user[0] };
+  } else {
+    return {};
+  }
+}
 
 export function UserDetailsContainer() {
   const { userName } = useParams();
   const { user } = useContext(userContext);
   const [error, setError] = useState(null);
 
-  const [userInfo, getUserInfo, ,] = useUserInfo(userName, (m, s) => {
-    // log error message for userInfo
-    console.warn(m);
+  const client = useContext(apiContext);
 
-    // user not found
-    if (s === 404) {
-      setError({ message: "Page not found", status: `${s}` });
-      // do not show snackbar error
-      return false;
-    }
+  const params = useMemo(
+    () => ({
+      user_name: userName
+    }),
+    [userName]
+  );
 
-    // user doesn't have permission to fetch userInfo
-    if (s === 401) {
-      setError({ message: "Unauthorized", status: `${s}` });
-      // do not show snackbar error
-      return false;
-    }
+  const {
+    value: userInfo,
+    wrapper: getUserInfo,
+    error: userInfoResponseError
+  } = useAPIMethod({
+    fcn: client.apis.Git.infoFromUserName,
+    call: true,
+    params,
+    unpacker: unpackUser
   });
 
   useEffect(() => {
-    // user logs in => clear error message, and try to re-request userInfo
-    if (user) {
-      setError(null);
-    } else {
-      // user is not logged in => show a message
-      setError({ message: "Unauthorized", status: "401" });
+    if (userInfoResponseError) {
+      const { status } = userInfoResponseError;
+      if (status === 404) {
+        setError({ message: "Page not found", status: `${status}` });
+      }
+
+      // user doesn't have permission to fetch userInfo
+      if (status === 401) {
+        setError({ message: "Unauthorized", status: `${status}` });
+      }
     }
-  }, [user]);
+  }, [userInfoResponseError]);
 
   useEffect(() => {
-    // request userInfo only if user is logged in
+    // user logs in => clear error message, and try to re-request userInfo
     if (user) {
+      setError(null);
       getUserInfo();
     }
-  }, [getUserInfo, userName, user]);
+  }, [user, userName, getUserInfo]);
 
-  return (
-    <>
-      {error ? (
-        <NotFoundView
-          status={error?.status ?? "404"}
-          message={error?.message}
-        />
-      ) : user ? (
-        <UserPageView
-          userName={userName}
-          user={user}
-          userInfo={userInfo}
-        />
-      ) : (
-        <LinearProgress color="primary" />
-      )}
-    </>
-  );
+  // If there is an error, show it; highest priority
+  if (error) {
+    return (
+      <NotFoundView
+        status={error?.status ?? "404"}
+        message={error?.message}
+      />
+    );
+  }
+
+  // If the user is logged in and the userInfo is available
+  // Then show the user page
+  if (user && userInfo) {
+    return (
+      <UserPageView
+        userName={userName}
+        user={user}
+        userInfo={userInfo}
+      />
+    );
+  }
+
+  // Otherwise assume loading (smoothest experience / least flickering)
+  return <LinearProgress color="primary" />;
 }