Migrate client features to use new server

Remove all authManager references where possible.
Change fetch calls url to new server.

GitLab: #79
GitLab: #100
GitLab: #110
Change-Id: I1dce64108ceba67531372df764f8f7563cc50a3b
diff --git a/client/src/AuthManager.ts b/client/src/AuthManager.ts
deleted file mode 100644
index 91ac981..0000000
--- a/client/src/AuthManager.ts
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2022 Savoir-faire Linux Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation; either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this program.  If not, see
- * <https://www.gnu.org/licenses/>.
- */
-
-/* eslint-disable no-undef */
-// TODO: This hides eslint errors for this file. This should be removed once this file is cleaned up.
-
-import { PromiseExecutor } from 'jami-web-common';
-
-interface AuthManagerState {
-  initialized: boolean;
-  authenticated: boolean;
-  setupComplete: boolean;
-  error: boolean;
-}
-
-interface AuthManagerTask extends PromiseExecutor<Response> {
-  url: string;
-  init?: RequestInit;
-}
-
-interface InitData {
-  loggedin?: true;
-  username?: string;
-  type?: string;
-  setupComplete?: boolean;
-}
-
-type OnAuthChanged = (auth: AuthManagerState) => void;
-
-class AuthManager {
-  private authenticating: boolean;
-  private readonly _state: AuthManagerState;
-  private tasks: AuthManagerTask[];
-  private onAuthChanged: OnAuthChanged | undefined;
-
-  constructor() {
-    console.log('AuthManager()');
-    this.authenticating = false;
-
-    this._state = {
-      initialized: false,
-      authenticated: true,
-      setupComplete: true,
-      error: false,
-    };
-
-    this.tasks = [];
-    this.onAuthChanged = undefined;
-  }
-
-  isAuthenticated() {
-    return this._state.authenticated;
-  }
-
-  getState() {
-    return this._state;
-  }
-
-  setInitData(data: InitData) {
-    this.authenticating = false;
-    this._state.initialized = true;
-    if (data.username) {
-      Object.assign(this._state, {
-        authenticated: true,
-        setupComplete: true,
-        error: false,
-        user: { username: data.username, type: data.type },
-      });
-    } else {
-      Object.assign(this._state, {
-        authenticated: false,
-        setupComplete: data.setupComplete ?? true,
-        error: false,
-      });
-    }
-    console.log('Init ended');
-    /*if (this.onAuthChanged)
-            this.onAuthChanged(this._state)*/
-  }
-
-  init(cb: OnAuthChanged) {
-    this.onAuthChanged = cb;
-    if (this._state.initialized || this.authenticating) return;
-    /*if (initData) {
-            console.log("Using static initData")
-            this.setInitData(initData)
-            return
-        }*/
-    this.authenticating = true;
-    fetch('/auth')
-      .then(async (response) => {
-        this.authenticating = false;
-        this._state.initialized = true;
-        if (response.status === 200) {
-          this.setInitData(await response.json());
-        } else if (response.status === 401) {
-          this.setInitData(await response.json());
-        } else {
-          this._state.error = true;
-          if (this.onAuthChanged) this.onAuthChanged(this._state);
-        }
-      })
-      .catch((e) => {
-        this.authenticating = false;
-        console.log(e);
-      });
-  }
-
-  deinit() {
-    console.log('Deinit');
-    this.onAuthChanged = undefined;
-  }
-
-  async setup(password: string) {
-    if (this.authenticating || this._state.setupComplete) return;
-    console.log('Starting setup');
-    this.authenticating = true;
-    const response = await fetch(`/setup`, {
-      method: 'POST',
-      headers: {
-        Accept: 'application/json',
-        'Content-Type': 'application/json',
-      },
-      body: JSON.stringify({ password }),
-    });
-    console.log(response);
-    if (response.ok) {
-      console.log('Success, going home');
-      //navigate('/')
-    }
-
-    this.authenticating = false;
-    this._state.setupComplete = true;
-    if (this.onAuthChanged) this.onAuthChanged(this._state);
-    return response.ok;
-  }
-
-  authenticate(username: string, password: string) {
-    if (this.authenticating) return;
-    console.log('Starting authentication');
-    this.authenticating = true;
-    fetch(`/auth/local?username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`, {
-      method: 'POST',
-    })
-      .then((response) => {
-        console.log(response);
-        this.authenticating = false;
-        this._state.authenticated = response.ok && response.status === 200;
-        if (this.onAuthChanged) this.onAuthChanged(this._state);
-        while (true) {
-          const task = this.tasks.shift();
-          if (!task) {
-            break;
-          }
-          if (this._state.authenticated) {
-            fetch(task.url, task.init)
-              .then((res) => task.resolve(res))
-              .catch((e) => console.log('Error executing pending task: ' + e));
-          } else {
-            task.reject(new Error('Authentication failed'));
-          }
-        }
-      })
-      .catch((e) => {
-        this.authenticating = false;
-        console.log(e);
-      });
-  }
-
-  disconnect() {
-    console.log('Disconnect');
-    this._state.authenticated = false;
-    if (this.onAuthChanged) this.onAuthChanged(this._state);
-  }
-
-  fetch(url: string, init?: RequestInit): Promise<Response> {
-    console.log(`fetch ${url}`);
-    if (!this._state.authenticated) {
-      if (!init || !init.method || init.method === 'GET') {
-        return new Promise<Response>((resolve, reject) => this.tasks.push({ url, init, resolve, reject }));
-      } else {
-        return new Promise<Response>((resolve, reject) => reject('Not authenticated'));
-      }
-    }
-    return fetch(url, init).then((response) => {
-      if (response.status === 401) {
-        this.disconnect();
-        return this.fetch(url, init);
-      }
-      return response;
-    });
-  }
-}
-
-export default new AuthManager();
diff --git a/client/src/components/AccountPreferences.tsx b/client/src/components/AccountPreferences.tsx
index 8ca098e..f0c5d31 100644
--- a/client/src/components/AccountPreferences.tsx
+++ b/client/src/components/AccountPreferences.tsx
@@ -38,8 +38,8 @@
 import { Account, AccountDetails } from 'jami-web-common';
 import { useState } from 'react';
 
-import authManager from '../AuthManager';
 import { useAuthContext } from '../contexts/AuthProvider';
+import { apiUrl } from '../utils/constants';
 import ConversationAvatar from './ConversationAvatar';
 import ConversationsOverviewCard from './ConversationsOverviewCard';
 import JamiIdCard from './JamiIdCard';
@@ -64,7 +64,8 @@
 export default function AccountPreferences({ account: _account }: AccountPreferencesProps) {
   const authContext = useAuthContext(true);
   const account = _account ?? authContext?.account;
-  if (!account) {
+  const token = authContext?.token;
+  if (!account || !token) {
     throw new Error('Account not defined');
   }
 
@@ -83,23 +84,34 @@
 
   const addModerator = () => {
     if (defaultModeratorUri) {
-      authManager.fetch(`/api/accounts/${account.getId()}/defaultModerators/${defaultModeratorUri}`, { method: 'PUT' });
+      fetch(new URL(`/default-moderators/${defaultModeratorUri}`, apiUrl), {
+        headers: {
+          Authorization: `Bearer ${token}`,
+        },
+        method: 'PUT',
+      });
       setDefaultModeratorUri('');
     }
   };
 
   const removeModerator = (uri: string) =>
-    authManager.fetch(`/api/accounts/${account.getId()}/defaultModerators/${uri}`, { method: 'DELETE' });
+    fetch(new URL(`/default-moderators/${uri}`, apiUrl), {
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+      method: 'DELETE',
+    });
 
   const handleToggle = (key: keyof AccountDetails, value: boolean) => {
     console.log(`handleToggle ${key} ${value}`);
     const newDetails: Partial<AccountDetails> = {};
     newDetails[key] = value ? 'true' : 'false';
     console.log(newDetails);
-    authManager.fetch(`/api/accounts/${account.getId()}`, {
-      method: 'POST',
+    fetch(new URL('/account', apiUrl), {
+      method: 'PATCH',
       headers: {
         Accept: 'application/json',
+        Authorization: `Bearer ${token}`,
         'Content-Type': 'application/json',
       },
       body: JSON.stringify(newDetails),
@@ -133,7 +145,7 @@
 
         <Grid item xs={12} sm={6}>
           <motion.div variants={thumbnailVariants}>
-            <ConversationsOverviewCard accountId={account.getId()} />
+            <ConversationsOverviewCard />
           </motion.div>
         </Grid>
 
diff --git a/client/src/components/ContactList.jsx b/client/src/components/ContactList.jsx
index c35c4f0..3bc040b 100644
--- a/client/src/components/ContactList.jsx
+++ b/client/src/components/ContactList.jsx
@@ -21,8 +21,9 @@
 import { useEffect, useState } from 'react';
 import Modal from 'react-modal';
 
-import authManager from '../AuthManager';
+import { useAuthContext } from '../contexts/AuthProvider';
 import { useAppDispatch, useAppSelector } from '../redux/hooks';
+import { apiUrl } from '../utils/constants';
 import ConversationAvatar from './ConversationAvatar';
 
 const customStyles = {
@@ -37,6 +38,7 @@
 };
 
 export default function ContactList() {
+  const { token } = useAuthContext();
   const { accountId } = useAppSelector((state) => state.userInfo);
   const dispatch = useAppDispatch();
 
@@ -59,10 +61,12 @@
 
   const getContactDetails = () => {
     const controller = new AbortController();
-    authManager
-      .fetch(`/api/accounts/${accountId}/contacts/details/${currentContact.id}`, {
-        signal: controller.signal,
-      })
+    fetch(new URL(`/contacts/${currentContact.id}`, apiUrl), {
+      signal: controller.signal,
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+    })
       .then((res) => res.json())
       .then((result) => {
         console.log('CONTACT LIST - DETAILS: ', result);
@@ -70,33 +74,41 @@
       .catch((e) => console.log('ERROR GET CONTACT DETAILS: ', e));
   };
 
-  const removeOrBlock = (typeOfRemove) => {
+  const removeOrBlock = (block = false) => {
     console.log('REMOVE');
     setBlockOrRemove(false);
     const controller = new AbortController();
-    authManager
-      .fetch(`/api/accounts/${accountId}/contacts/${typeOfRemove}/${currentContact.id}`, {
-        signal: controller.signal,
-        method: 'DELETE',
-      })
+    let url = `/contacts/${currentContact.id}`;
+    if (block) {
+      url += '/block';
+    }
+    fetch(new URL(url, apiUrl), {
+      signal: controller.signal,
+      method: block ? 'POST' : 'DELETE',
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+    })
       .then((res) => res.json())
-      .catch((e) => console.log(`ERROR ${typeOfRemove}ing CONTACT : `, e));
+      .catch((e) => console.log(`ERROR ${block ? 'blocking' : 'removing'} CONTACT : `, e));
     closeModalDelete();
   };
 
   useEffect(() => {
     const controller = new AbortController();
-    authManager
-      .fetch(`/api/accounts/${accountId}/contacts`, {
-        signal: controller.signal,
-      })
+    fetch(new URL(`/contacts`, apiUrl), {
+      signal: controller.signal,
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+    })
       .then((res) => res.json())
       .then((result) => {
         console.log('CONTACTS: ', result);
         setContacts(result);
       });
     return () => controller.abort();
-  }, [accountId, blockOrRemove]);
+  }, [token]);
 
   return (
     <div className="rooms-list">
@@ -165,9 +177,9 @@
         Voulez vous vraiment {blockOrRemove ? 'bloquer' : 'supprimer'} ce contact?
         <br />
         {blockOrRemove ? (
-          <button onClick={() => removeOrBlock('block')}>Bloquer</button>
+          <button onClick={() => removeOrBlock(true)}>Bloquer</button>
         ) : (
-          <button onClick={() => removeOrBlock('remove')}>Supprimer</button>
+          <button onClick={() => removeOrBlock()}>Supprimer</button>
         )}
         <button onClick={closeModalDelete}>Annuler</button>
       </Modal>
diff --git a/client/src/components/ConversationListItem.tsx b/client/src/components/ConversationListItem.tsx
index 9a928e7..c094d71 100644
--- a/client/src/components/ConversationListItem.tsx
+++ b/client/src/components/ConversationListItem.tsx
@@ -33,12 +33,20 @@
 import Modal from 'react-modal';
 import { useNavigate, useParams } from 'react-router-dom';
 
-import authManager from '../AuthManager';
+import { useAuthContext } from '../contexts/AuthProvider';
 import { setRefreshFromSlice } from '../redux/appSlice';
 import { useAppDispatch } from '../redux/hooks';
+import { apiUrl } from '../utils/constants';
 import ConversationAvatar from './ConversationAvatar';
-import { CancelIcon, RemoveContactIcon, VideoCallIcon } from './SvgIcon';
-import { AudioCallIcon, BlockContactIcon, ContactDetailsIcon, MessageIcon } from './SvgIcon';
+import {
+  AudioCallIcon,
+  BlockContactIcon,
+  CancelIcon,
+  ContactDetailsIcon,
+  MessageIcon,
+  RemoveContactIcon,
+  VideoCallIcon,
+} from './SvgIcon';
 
 const cancelStyles: Modal.Styles = {
   content: {
@@ -81,6 +89,7 @@
 };
 
 export default function ConversationListItem({ conversation }: ConversationListItemProps) {
+  const { token } = useAuthContext();
   const { conversationId, contactId } = useParams();
   const dispatch = useAppDispatch();
 
@@ -95,8 +104,6 @@
   const [userId] = useState(conversation?.getFirstMember()?.contact.getUri());
   const [isSwarm] = useState(true);
 
-  const navigateUrlPrefix = `/deprecated-account/${conversation.getAccountId()}`;
-
   const openMenu = (e: MouseEvent<HTMLDivElement>) => {
     e.preventDefault();
     console.log(e);
@@ -110,10 +117,12 @@
 
   const getContactDetails = () => {
     const controller = new AbortController();
-    authManager
-      .fetch(`/api/accounts/${conversation.getAccountId()}/contacts/details/${userId}`, {
-        signal: controller.signal,
-      })
+    fetch(new URL(`/contacts/${userId}`, apiUrl), {
+      signal: controller.signal,
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+    })
       .then((res) => res.json())
       .then((result) => {
         console.log('CONTACT LIST - DETAILS: ', result);
@@ -121,38 +130,43 @@
       .catch((e) => console.log('ERROR GET CONTACT DETAILS: ', e));
   };
 
-  const removeOrBlock = (typeOfRemove: 'block' | 'remove') => {
-    console.log(typeOfRemove);
+  const removeOrBlock = (block = false) => {
     setBlockOrRemove(false);
 
-    console.log('EEEH', typeOfRemove, conversation.getAccountId(), userId);
+    console.log('EEEH', conversation.getAccountId(), userId);
 
     const controller = new AbortController();
-    authManager
-      .fetch(`/api/accounts/${conversation.getAccountId()}/contacts/${typeOfRemove}/${userId}`, {
-        signal: controller.signal,
-        method: 'DELETE',
-      })
+    let url = `/contacts/${userId}`;
+    if (block) {
+      url += '/block';
+    }
+    fetch(new URL(url, apiUrl), {
+      signal: controller.signal,
+      method: block ? 'POST' : 'DELETE',
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+    })
       .then((res) => res.json())
       .then(() => {
         console.log('propre');
         dispatch(setRefreshFromSlice());
       })
       .catch((e) => {
-        console.log(`ERROR ${typeOfRemove}ing CONTACT : `, e);
+        console.log(`ERROR ${block ? 'blocking' : 'removing'} CONTACT : `, e);
         dispatch(setRefreshFromSlice());
       });
     closeModalDelete();
   };
 
-  const uri = conversation.getId() ? `conversation/${conversation.getId()}` : `addContact/${userId}`;
+  const uri = conversation.getId() ? `/account/conversation/${conversation.getId()}` : `/account/addContact/${userId}`;
   return (
     <div onContextMenu={openMenu}>
       <div>
         <Menu open={!!menuAnchorEl} onClose={closeModal} anchorEl={menuAnchorEl}>
           <MenuItem
             onClick={() => {
-              navigate(`${navigateUrlPrefix}/${uri}`);
+              navigate(uri);
               closeModal();
             }}
           >
@@ -165,7 +179,7 @@
           </MenuItem>
           <MenuItem
             onClick={() => {
-              navigate(`${navigateUrlPrefix}/call/${conversation.getId()}`);
+              navigate(`/account/call/${conversation.getId()}`);
             }}
           >
             <ListItemIcon>
@@ -178,7 +192,7 @@
 
           <MenuItem
             onClick={() => {
-              navigate(`${navigateUrlPrefix}/call/${conversation.getId()}?video=true`);
+              navigate(`call/${conversation.getId()}?video=true`);
             }}
           >
             <ListItemIcon>
@@ -192,7 +206,7 @@
           {isSelected && (
             <MenuItem
               onClick={() => {
-                navigate(`${navigateUrlPrefix}/`);
+                navigate(`/account`);
                 closeModal();
               }}
             >
@@ -366,8 +380,8 @@
             <Stack direction={'row'} top={'25px'} alignSelf="center" spacing={1}>
               <Box
                 onClick={() => {
-                  if (blockOrRemove) removeOrBlock('block');
-                  else removeOrBlock('remove');
+                  if (blockOrRemove) removeOrBlock(true);
+                  else removeOrBlock(false);
                 }}
                 style={{
                   width: '100px',
@@ -398,12 +412,7 @@
         </Modal>
       </div>
 
-      <ListItem
-        button
-        alignItems="flex-start"
-        selected={isSelected}
-        onClick={() => navigate(`${navigateUrlPrefix}/${uri}`)}
-      >
+      <ListItem button alignItems="flex-start" selected={isSelected} onClick={() => navigate(uri)}>
         <ListItemAvatar>
           <ConversationAvatar displayName={conversation.getDisplayNameNoFallback()} />
         </ListItemAvatar>
diff --git a/client/src/components/ConversationView.tsx b/client/src/components/ConversationView.tsx
index 4ecffe8..03f0717 100644
--- a/client/src/components/ConversationView.tsx
+++ b/client/src/components/ConversationView.tsx
@@ -21,33 +21,27 @@
 import { useTranslation } from 'react-i18next';
 import { useNavigate } from 'react-router';
 
+import { useAuthContext } from '../contexts/AuthProvider';
 import { SocketContext } from '../contexts/Socket';
 import ChatInterface from '../pages/ChatInterface';
-import { useAccountQuery } from '../services/Account';
 import { useConversationQuery } from '../services/Conversation';
 import { translateEnumeration, TranslateEnumerationOptions } from '../utils/translations';
 import { AddParticipantButton, ShowOptionsMenuButton, StartAudioCallButton, StartVideoCallButton } from './Button';
 import LoadingPage from './Loading';
 
 type ConversationViewProps = {
-  accountId: string;
   conversationId: string;
 };
-const ConversationView = ({ accountId, conversationId }: ConversationViewProps) => {
+const ConversationView = ({ conversationId }: ConversationViewProps) => {
+  const { account } = useAuthContext();
   const socket = useContext(SocketContext);
-  const [account, setAccount] = useState<Account | undefined>();
   const [conversation, setConversation] = useState<Conversation | undefined>();
   const [isLoading, setIsLoading] = useState(true);
   const [error, setError] = useState(false);
 
-  const accountQuery = useAccountQuery(accountId);
-  const conversationQuery = useConversationQuery(accountId, conversationId);
+  const accountId = account.getId();
 
-  useEffect(() => {
-    if (accountQuery.isSuccess) {
-      setAccount(Account.from(accountQuery.data));
-    }
-  }, [accountQuery.isSuccess, accountQuery.data]);
+  const conversationQuery = useConversationQuery(conversationId);
 
   useEffect(() => {
     if (conversationQuery.isSuccess) {
@@ -57,12 +51,12 @@
   }, [accountId, conversationQuery.isSuccess, conversationQuery.data]);
 
   useEffect(() => {
-    setIsLoading(accountQuery.isLoading || conversationQuery.isLoading);
-  }, [accountQuery.isLoading, conversationQuery.isLoading]);
+    setIsLoading(conversationQuery.isLoading);
+  }, [conversationQuery.isLoading]);
 
   useEffect(() => {
-    setError(accountQuery.isError || conversationQuery.isError);
-  }, [accountQuery.isError, conversationQuery.isError]);
+    setError(conversationQuery.isError);
+  }, [conversationQuery.isError]);
 
   useEffect(() => {
     if (!conversation) return;
@@ -94,7 +88,7 @@
           borderTop: '1px solid #E5E5E5',
         }}
       />
-      <ChatInterface account={account} conversationId={conversationId} members={conversation.getMembers()} />
+      <ChatInterface conversationId={conversationId} members={conversation.getMembers()} />
     </Stack>
   );
 };
diff --git a/client/src/components/ConversationsOverviewCard.jsx b/client/src/components/ConversationsOverviewCard.tsx
similarity index 60%
rename from client/src/components/ConversationsOverviewCard.jsx
rename to client/src/components/ConversationsOverviewCard.tsx
index d233df0..4ed0ed4 100644
--- a/client/src/components/ConversationsOverviewCard.jsx
+++ b/client/src/components/ConversationsOverviewCard.tsx
@@ -16,43 +16,46 @@
  * <https://www.gnu.org/licenses/>.
  */
 import { Card, CardActionArea, CardContent, CircularProgress, Typography } from '@mui/material';
-import { Conversation } from 'jami-web-common';
+import { Conversation } from 'jami-web-common/dist/Conversation';
 import { useEffect, useState } from 'react';
-import { useNavigate, useParams } from 'react-router';
+import { useNavigate } from 'react-router';
 
-import authManager from '../AuthManager';
+import { useAuthContext } from '../contexts/AuthProvider';
+import { apiUrl } from '../utils/constants';
 
-export default function ConversationsOverviewCard(props) {
+export default function ConversationsOverviewCard() {
+  const { token, account } = useAuthContext();
   const navigate = useNavigate();
-  let accountId = useParams().accountId;
-  if (props.accountId) {
-    accountId = props.accountId;
-  }
-  const [loaded, setLoaded] = useState(false);
-  const [conversations, setConversations] = useState([]);
+
+  const [conversationCount, setConversationCount] = useState<number | undefined>();
+
+  const accountId = account.getId();
 
   useEffect(() => {
     const controller = new AbortController();
-    authManager
-      .fetch(`/api/accounts/${accountId}/conversations`, { signal: controller.signal })
+    fetch(new URL('/conversations', apiUrl), {
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+      signal: controller.signal,
+    })
       .then((res) => res.json())
-      .then((result) => {
+      .then((result: Conversation[]) => {
         console.log(result);
-        setLoaded(true);
-        setConversations(Object.values(result).map((c) => Conversation.from(accountId, c)));
+        setConversationCount(result.length);
       });
-    // return () => controller.abort() // crash on React18
-  }, [accountId]);
+    return () => controller.abort(); // crash on React18
+  }, [token, accountId]);
 
   return (
-    <Card onClick={() => navigate(`/deprecated-account/${accountId}`)}>
+    <Card onClick={() => navigate(`/account`)}>
       <CardActionArea>
         <CardContent>
           <Typography color="textSecondary" gutterBottom>
             Conversations
           </Typography>
           <Typography gutterBottom variant="h5" component="h2">
-            {loaded ? conversations.length : <CircularProgress size={24} />}
+            {conversationCount != null ? conversationCount : <CircularProgress size={24} />}
           </Typography>
         </CardContent>
       </CardActionArea>
diff --git a/client/src/components/Header.tsx b/client/src/components/Header.tsx
index 445dbae..6276fa4 100644
--- a/client/src/components/Header.tsx
+++ b/client/src/components/Header.tsx
@@ -17,29 +17,19 @@
  */
 import { Box, Button, Menu, MenuItem } from '@mui/material';
 import { MouseEvent, useState } from 'react';
-import { useNavigate, useParams } from 'react-router-dom';
+import { useNavigate } from 'react-router-dom';
 
 import { useAuthContext } from '../contexts/AuthProvider';
-import { setAccessToken } from '../utils/auth';
 
 export default function Header() {
-  const authContext = useAuthContext(true);
+  const { logout } = useAuthContext();
 
   const navigate = useNavigate();
   const [anchorEl, setAnchorEl] = useState<HTMLButtonElement | null>(null);
   const handleClick = (event: MouseEvent<HTMLButtonElement>) => setAnchorEl(event.currentTarget);
   const handleClose = () => setAnchorEl(null);
-  const params = useParams();
 
   const goToContacts = () => navigate(`/contacts`);
-  const goToAccountSettings = () => navigate(`/deprecated-account/${params.accountId}/settings`);
-
-  const deprecatedLogout = () => {
-    setAccessToken('');
-    navigate('/deprecated-account', { replace: true });
-  };
-  // TODO: Remove deprecated_logout once migration to new server is complete
-  const logout = authContext?.logout ?? deprecatedLogout;
 
   return (
     <Box>
@@ -48,7 +38,7 @@
       </Button>
       <Menu id="simple-menu" anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleClose}>
         <MenuItem onClick={goToContacts}>Contacts</MenuItem>
-        {params.accountId && <MenuItem onClick={goToAccountSettings}>Account settings</MenuItem>}
+        <MenuItem onClick={() => navigate('/settings')}>Account settings</MenuItem>
         <MenuItem onClick={logout}>Log out</MenuItem>
       </Menu>
     </Box>
diff --git a/client/src/components/MessageList.tsx b/client/src/components/MessageList.tsx
index 7b9bf2d..0ae04d2 100644
--- a/client/src/components/MessageList.tsx
+++ b/client/src/components/MessageList.tsx
@@ -17,21 +17,22 @@
  */
 import { Typography } from '@mui/material';
 import { Box, Stack } from '@mui/system';
-import { Account, ConversationMember, Message } from 'jami-web-common';
+import { ConversationMember, Message } from 'jami-web-common';
 import { MutableRefObject, useRef, useState } from 'react';
 import { useTranslation } from 'react-i18next';
 import { Waypoint } from 'react-waypoint';
 
+import { useAuthContext } from '../contexts/AuthProvider';
 import { MessageRow } from './Message';
 import { ArrowDownIcon } from './SvgIcon';
 
 interface MessageListProps {
-  account: Account;
   members: ConversationMember[];
   messages: Message[];
 }
 
-export default function MessageList({ account, members, messages }: MessageListProps) {
+export default function MessageList({ members, messages }: MessageListProps) {
+  const { account } = useAuthContext();
   const [showScrollButton, setShowScrollButton] = useState(false);
   const listBottomRef = useRef<HTMLElement>();
 
diff --git a/client/src/components/SendMessageForm.tsx b/client/src/components/SendMessageForm.tsx
index 797d810..dfb5f3d 100644
--- a/client/src/components/SendMessageForm.tsx
+++ b/client/src/components/SendMessageForm.tsx
@@ -17,10 +17,11 @@
  */
 import { InputBase } from '@mui/material';
 import { Stack } from '@mui/system';
-import { Account, ConversationMember } from 'jami-web-common';
+import { ConversationMember } from 'jami-web-common';
 import { ChangeEvent, FormEvent, useCallback, useMemo, useState } from 'react';
 import { useTranslation } from 'react-i18next';
 
+import { useAuthContext } from '../contexts/AuthProvider';
 import { translateEnumeration, TranslateEnumerationOptions } from '../utils/translations';
 import {
   RecordVideoMessageButton,
@@ -31,15 +32,14 @@
 } from './Button';
 
 type SendMessageFormProps = {
-  account: Account;
   members: ConversationMember[];
   onSend: (message: string) => void;
   openFilePicker: () => void;
 };
 
-export default function SendMessageForm({ account, members, onSend, openFilePicker }: SendMessageFormProps) {
+export default function SendMessageForm({ members, onSend, openFilePicker }: SendMessageFormProps) {
   const [currentMessage, setCurrentMessage] = useState('');
-  const placeholder = usePlaceholder(account, members);
+  const placeholder = usePlaceholder(members);
 
   const handleSubmit = (e: FormEvent<HTMLFormElement>) => {
     e.preventDefault();
@@ -90,7 +90,8 @@
   );
 }
 
-const usePlaceholder = (account: Account, members: ConversationMember[]) => {
+const usePlaceholder = (members: ConversationMember[]) => {
+  const { account } = useAuthContext();
   const { t } = useTranslation();
 
   return useMemo(() => {
diff --git a/client/src/components/UsernameChooser.jsx b/client/src/components/UsernameChooser.jsx
index 486d947..3c1f584 100644
--- a/client/src/components/UsernameChooser.jsx
+++ b/client/src/components/UsernameChooser.jsx
@@ -20,7 +20,7 @@
 import { useEffect, useState } from 'react';
 import usePromise from 'react-fetch-hook/usePromise';
 
-import authManager from '../AuthManager';
+import { apiUrl } from '../utils/constants.js';
 
 const isInputValid = (input) => input && input.length > 2;
 
@@ -30,7 +30,7 @@
   const { isLoading, data, error } = usePromise(
     () =>
       isInputValid(query)
-        ? authManager.fetch(`/api/ns/name/${query}`).then((res) => {
+        ? fetch(new URL(`/ns/username/${query}`, apiUrl)).then((res) => {
             if (res.status === 200) return res.json();
             else throw res.status;
           })
diff --git a/client/src/index.tsx b/client/src/index.tsx
index ef5e5d4..c8885ad 100644
--- a/client/src/index.tsx
+++ b/client/src/index.tsx
@@ -32,12 +32,8 @@
 import AuthProvider from './contexts/AuthProvider';
 import { SocketProvider } from './contexts/Socket';
 import WebSocketProvider from './contexts/WebSocketProvider';
-import AccountSelection from './pages/AccountSelection';
 import AccountSettings from './pages/AccountSettings';
-import CallInterface from './pages/CallInterface';
-import DeprecatedAccountSettings from './pages/DeprecatedAccountSettings';
 import JamiMessenger from './pages/JamiMessenger';
-import Messenger from './pages/Messenger';
 import ServerSetup from './pages/ServerSetup';
 import Welcome from './pages/Welcome';
 import { store } from './redux/store';
@@ -73,14 +69,6 @@
         <Route path="contacts" element={<ContactList />} />
       </Route>
       <Route path="setup" element={<ServerSetup />} />
-      {/* TODO: Remove this block after migration to new server*/}
-      <Route path="deprecated-account" element={<AccountSelection />} />
-      <Route path="deprecated-account/:accountId" element={<Messenger />}>
-        <Route path="addContact/:contactId" element={<Messenger />} />
-        <Route path="conversation/:conversationId" element={<Messenger />} />
-        <Route path="call/:conversationId" element={<CallInterface />} />
-      </Route>
-      <Route path="deprecated-account/:accountId/settings" element={<DeprecatedAccountSettings />} />
     </Route>
   )
 );
diff --git a/client/src/pages/AccountSelection.tsx b/client/src/pages/AccountSelection.tsx
deleted file mode 100644
index f8daf0a..0000000
--- a/client/src/pages/AccountSelection.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2022 Savoir-faire Linux Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation; either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this program.  If not, see
- * <https://www.gnu.org/licenses/>.
- */
-import { AddRounded } from '@mui/icons-material';
-import { Avatar, Card, CardHeader, Container, List } from '@mui/material';
-import { motion } from 'framer-motion';
-import { Account } from 'jami-web-common';
-import { Fragment, useEffect, useState } from 'react';
-import { useNavigate } from 'react-router';
-
-import authManager from '../AuthManager';
-import ConversationAvatar from '../components/ConversationAvatar';
-import Header from '../components/Header';
-import ListItemLink from '../components/ListItemLink';
-import LoadingPage from '../components/Loading';
-
-const variants = {
-  enter: { opacity: 1, y: 0 },
-  exit: { opacity: 0, y: '-50px' },
-};
-
-const AccountSelection = () => {
-  const navigate = useNavigate();
-  const [loaded, setLoaded] = useState(false);
-  const [, setError] = useState(false);
-  const [accounts, setAccounts] = useState<Account[]>([]);
-
-  authManager.authenticate('admin', 'admin');
-
-  useEffect(() => {
-    const controller = new AbortController();
-    authManager
-      .fetch(`/api/accounts`, { signal: controller.signal })
-      .then((res) => res.json())
-      .then(
-        (result: Account[]) => {
-          console.log(result);
-          if (result.length === 0) {
-            navigate('/newAccount');
-          } else {
-            setLoaded(true);
-            setAccounts(result.map((account) => Account.from(account)));
-          }
-        },
-        (error) => {
-          console.log(`get error ${error}`);
-          setLoaded(true);
-          setError(true);
-        }
-      )
-      .catch((e) => console.log(e));
-    // return () => controller.abort() // crash on React18
-  }, [navigate]);
-
-  if (!loaded) return <LoadingPage />;
-  return (
-    <Fragment>
-      <Header />
-      <Container maxWidth="sm" style={{ paddingBottom: 32 }}>
-        <motion.div drag="x" initial="exit" animate="enter" exit="exit" variants={variants}>
-          <Card style={{ marginTop: 32, marginBottom: 32 }}>
-            <CardHeader title="Choose an account" />
-            <List>
-              {accounts.map((account) => (
-                <ListItemLink
-                  key={account.getId()}
-                  icon={<ConversationAvatar displayName={account.getDisplayNameNoFallback()} />}
-                  to={`/deprecated-account/${account.getId()}/settings`}
-                  primary={account.getDisplayName()}
-                  secondary={account.getDisplayUri()}
-                />
-              ))}
-              <ListItemLink
-                icon={
-                  <Avatar>
-                    <AddRounded />
-                  </Avatar>
-                }
-                to="/newAccount"
-                primary="Create new account"
-              />
-            </List>
-          </Card>
-        </motion.div>
-      </Container>
-    </Fragment>
-  );
-};
-
-export default AccountSelection;
diff --git a/client/src/pages/AddContactPage.tsx b/client/src/pages/AddContactPage.tsx
index b0dfad0..dd93376 100644
--- a/client/src/pages/AddContactPage.tsx
+++ b/client/src/pages/AddContactPage.tsx
@@ -17,43 +17,40 @@
  */
 import GroupAddRounded from '@mui/icons-material/GroupAddRounded';
 import { Box, Card, CardContent, Container, Fab, Typography } from '@mui/material';
-import { useNavigate, useParams } from 'react-router-dom';
+import { useNavigate } from 'react-router-dom';
 
-import authManager from '../AuthManager';
+import { useAuthContext } from '../contexts/AuthProvider';
 import { setRefreshFromSlice } from '../redux/appSlice';
 import { useAppDispatch } from '../redux/hooks';
+import { apiUrl } from '../utils/constants';
 
 type AddContactPageProps = {
-  accountId: string;
   contactId: string;
 };
 
-export default function AddContactPage(props: AddContactPageProps) {
+export default function AddContactPage({ contactId }: AddContactPageProps) {
+  const { token } = useAuthContext();
   const navigate = useNavigate();
 
-  const params = useParams();
-  const accountId = props.accountId || params.accountId;
-  const contactId = props.contactId || params.contactId;
   const dispatch = useAppDispatch();
 
   const handleClick = async () => {
-    const response = await authManager
-      .fetch(`/api/accounts/${accountId}/conversations`, {
-        method: 'POST',
-        headers: {
-          Accept: 'application/json',
-          'Content-Type': 'application/json',
-        },
-        body: JSON.stringify({ members: [contactId] }),
-      })
-      .then((res) => {
-        dispatch(setRefreshFromSlice());
-        return res.json();
-      });
+    const response = await fetch(new URL(`/conversations`, apiUrl), {
+      method: 'POST',
+      headers: {
+        Accept: 'application/json',
+        Authorization: `Bearer ${token}`,
+        'Content-Type': 'application/json',
+      },
+      body: JSON.stringify({ members: [contactId] }),
+    }).then((res) => {
+      dispatch(setRefreshFromSlice());
+      return res.json();
+    });
 
     console.log(response);
     if (response.conversationId) {
-      navigate(`/deprecated-account/${accountId}/conversation/${response.conversationId}`);
+      navigate(`/account/conversation/${response.conversationId}`);
     }
   };
 
diff --git a/client/src/pages/ChatInterface.tsx b/client/src/pages/ChatInterface.tsx
index 4ad1830..b09f2fd 100644
--- a/client/src/pages/ChatInterface.tsx
+++ b/client/src/pages/ChatInterface.tsx
@@ -16,7 +16,7 @@
  * <https://www.gnu.org/licenses/>.
  */
 import { Box, Divider, Stack } from '@mui/material';
-import { Account, ConversationMember, Message } from 'jami-web-common';
+import { ConversationMember, Message } from 'jami-web-common';
 import { useCallback, useContext, useEffect, useState } from 'react';
 import { useDropzone } from 'react-dropzone';
 
@@ -29,18 +29,17 @@
 import { FileHandler } from '../utils/files';
 
 type ChatInterfaceProps = {
-  account: Account;
   conversationId: string;
   members: ConversationMember[];
 };
-const ChatInterface = ({ account, conversationId, members }: ChatInterfaceProps) => {
+const ChatInterface = ({ conversationId, members }: ChatInterfaceProps) => {
   const socket = useContext(SocketContext);
   const [messages, setMessages] = useState<Message[]>([]);
   const [isLoading, setIsLoading] = useState(true);
   const [error, setError] = useState(false);
 
-  const messagesQuery = useMessagesQuery(account.getId(), conversationId);
-  const sendMessageMutation = useSendMessageMutation(account.getId(), conversationId);
+  const messagesQuery = useMessagesQuery(conversationId);
+  const sendMessageMutation = useSendMessageMutation(conversationId);
 
   const [fileHandlers, setFileHandlers] = useState<FileHandler[]>([]);
 
@@ -119,14 +118,14 @@
         />
       )}
       <input {...getInputProps()} />
-      <MessageList account={account} members={members} messages={messages} />
+      <MessageList members={members} messages={messages} />
       <Divider
         sx={{
           margin: '30px 16px 0px 16px',
           borderTop: '1px solid #E5E5E5',
         }}
       />
-      <SendMessageForm account={account} members={members} onSend={sendMessage} openFilePicker={openFilePicker} />
+      <SendMessageForm members={members} onSend={sendMessage} openFilePicker={openFilePicker} />
       {fileHandlers.length > 0 && <FilePreviewsList fileHandlers={fileHandlers} removeFile={removeFile} />}
     </Stack>
   );
diff --git a/client/src/pages/DeprecatedAccountSettings.tsx b/client/src/pages/DeprecatedAccountSettings.tsx
deleted file mode 100644
index f69334d..0000000
--- a/client/src/pages/DeprecatedAccountSettings.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2022 Savoir-faire Linux Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation; either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this program.  If not, see
- * <https://www.gnu.org/licenses/>.
- */
-import { CircularProgress, Container } from '@mui/material';
-import { Account } from 'jami-web-common';
-import { useEffect, useState } from 'react';
-import { useParams } from 'react-router';
-
-import authManager from '../AuthManager';
-import AccountPreferences from '../components/AccountPreferences';
-import Header from '../components/Header';
-import { setAccountId } from '../redux/appSlice';
-import { useAppDispatch } from '../redux/hooks';
-
-type AccountSettingsProps = {
-  accountId?: string;
-  account?: Account;
-};
-
-const DeprecatedAccountSettings = (props: AccountSettingsProps) => {
-  console.log('ACCOUNT SETTINGS', props.account);
-  const params = useParams();
-  const accountId = props.accountId || params.accountId;
-
-  if (accountId == null) {
-    throw new Error('Missing accountId');
-  }
-
-  const dispatch = useAppDispatch();
-
-  const [localAccount, setLocalAccount] = useState<Account | null>(null);
-
-  useEffect(() => {
-    dispatch(setAccountId(accountId));
-
-    const controller = new AbortController();
-    authManager
-      .fetch(`/api/accounts/${accountId}`, { signal: controller.signal })
-      .then((res) => res.json())
-      .then((result) => {
-        console.log(result);
-        const account = Account.from(result);
-        account.setDevices(result.devices);
-        setLocalAccount(account);
-      })
-      .catch((e) => console.log(e));
-    // return () => controller.abort() // crash on React18
-  }, [accountId, dispatch]);
-
-  return (
-    <Container maxWidth="sm">
-      <Header />
-      {localAccount != null ? <AccountPreferences account={localAccount} /> : <CircularProgress />}
-    </Container>
-  );
-};
-
-export default DeprecatedAccountSettings;
diff --git a/client/src/pages/JamiMessenger.tsx b/client/src/pages/JamiMessenger.tsx
index 2cb485b..b0b0812 100644
--- a/client/src/pages/JamiMessenger.tsx
+++ b/client/src/pages/JamiMessenger.tsx
@@ -21,6 +21,7 @@
 import CallInterface from './CallInterface';
 import Messenger from './Messenger';
 
+export type MessengerRouteParams = RouteParams<{ conversationId?: string; contactId?: string }, Record<string, never>>;
 export type CallRouteParams = RouteParams<{ conversationId: string }, { video?: 'true' }>;
 
 export default function JamiMessenger() {
diff --git a/client/src/pages/Messenger.tsx b/client/src/pages/Messenger.tsx
index c38294a..fdbb0f4 100644
--- a/client/src/pages/Messenger.tsx
+++ b/client/src/pages/Messenger.tsx
@@ -18,58 +18,60 @@
 import { Stack } from '@mui/material';
 import { Contact, Conversation } from 'jami-web-common';
 import { useEffect, useState } from 'react';
-import { useParams } from 'react-router';
 
-import authManager from '../AuthManager';
 //import Sound from 'react-sound';
 import ConversationList from '../components/ConversationList';
 import ConversationView from '../components/ConversationView';
 import Header from '../components/Header';
 import LoadingPage from '../components/Loading';
 import NewContactForm from '../components/NewContactForm';
+import { useAuthContext } from '../contexts/AuthProvider';
 import { useAppSelector } from '../redux/hooks';
+import { apiUrl } from '../utils/constants';
+import { useUrlParams } from '../utils/hooks';
 import AddContactPage from './AddContactPage';
+import { MessengerRouteParams } from './JamiMessenger';
 
-type MessengerProps = {
-  accountId?: string;
-  conversationId?: string;
-  contactId?: string;
-};
-
-const Messenger = (props: MessengerProps) => {
+const Messenger = () => {
   const { refresh } = useAppSelector((state) => state.userInfo);
+  const { token, account } = useAuthContext();
 
   const [conversations, setConversations] = useState<Conversation[] | undefined>(undefined);
   const [searchQuery, setSearchQuery] = useState('');
   const [searchResult, setSearchResults] = useState<Conversation | undefined>(undefined);
 
-  const params = useParams();
-  const accountId = props.accountId || params.accountId;
-  const conversationId = props.conversationId || params.conversationId;
-  const contactId = props.contactId || params.contactId;
+  const {
+    urlParams: { conversationId, contactId },
+  } = useUrlParams<MessengerRouteParams>();
 
-  if (accountId == null) {
-    throw new Error('Missing accountId');
-  }
+  const accountId = account.getId();
 
   useEffect(() => {
     console.log('REFRESH CONVERSATIONS FROM MESSENGER');
     const controller = new AbortController();
-    authManager
-      .fetch(`/api/accounts/${accountId}/conversations`, { signal: controller.signal })
+    fetch(new URL(`/conversations`, apiUrl), {
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+      signal: controller.signal,
+    })
       .then((res) => res.json())
       .then((result: Conversation[]) => {
         console.log(result);
         setConversations(Object.values(result).map((c) => Conversation.from(accountId, c)));
       });
     // return () => controller.abort()
-  }, [accountId, refresh]);
+  }, [token, accountId, refresh]);
 
   useEffect(() => {
     if (!searchQuery) return;
     const controller = new AbortController();
-    authManager
-      .fetch(`/api/accounts/${accountId}/ns/name/${searchQuery}`, { signal: controller.signal })
+    fetch(new URL(`/ns/username/${searchQuery}`, apiUrl), {
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+      signal: controller.signal,
+    })
       .then((response) => {
         if (response.status === 200) {
           return response.json();
@@ -80,14 +82,14 @@
       .then((response) => {
         console.log(response);
         const contact = new Contact(response.address);
-        contact.setRegisteredName(response.name);
+        contact.setRegisteredName(response.username);
         setSearchResults(contact ? Conversation.fromSingleContact(accountId, contact) : undefined);
       })
       .catch(() => {
         setSearchResults(undefined);
       });
     // return () => controller.abort() // crash on React18
-  }, [accountId, searchQuery]);
+  }, [accountId, searchQuery, token]);
 
   console.log('Messenger render');
   return (
@@ -95,7 +97,7 @@
       <Stack flexGrow={0} flexShrink={0} overflow="auto">
         <Header />
         <NewContactForm onChange={setSearchQuery} />
-        {contactId && <AddContactPage accountId={accountId} contactId={contactId} />}
+        {contactId && <AddContactPage contactId={contactId} />}
         {conversations ? (
           <ConversationList search={searchResult} conversations={conversations} accountId={accountId} />
         ) : (
@@ -104,9 +106,7 @@
           </div>
         )}
       </Stack>
-      <Stack flexGrow={1}>
-        {conversationId && <ConversationView accountId={accountId} conversationId={conversationId} />}
-      </Stack>
+      <Stack flexGrow={1}>{conversationId && <ConversationView conversationId={conversationId} />}</Stack>
     </Stack>
   );
 };
diff --git a/client/src/pages/ServerConfiguration.tsx b/client/src/pages/ServerConfiguration.tsx
deleted file mode 100644
index 56d06a8..0000000
--- a/client/src/pages/ServerConfiguration.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2022 Savoir-faire Linux Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation; either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this program.  If not, see
- * <https://www.gnu.org/licenses/>.
- */
-import CircularProgress from '@mui/material/CircularProgress';
-import Container from '@mui/material/Container';
-import { Account } from 'jami-web-common';
-import { useEffect, useState } from 'react';
-import { useParams } from 'react-router-dom';
-
-import authManager from '../AuthManager';
-import AccountPreferences from '../components/AccountPreferences';
-import Header from '../components/Header';
-
-type ServerOverviewProps = {
-  accountId?: string;
-};
-
-const ServerOverview = (props: ServerOverviewProps) => {
-  const [account, setAccount] = useState<Account | null>(null);
-  const params = useParams();
-  const accountId = props.accountId || params.accountId;
-
-  useEffect(() => {
-    const controller = new AbortController();
-    authManager
-      .fetch(`/api/serverConfig`, { signal: controller.signal })
-      .then((res) => res.json())
-      .then((result) => {
-        console.log(result);
-        setAccount(Account.from(result));
-      })
-      .catch((e) => console.log(e));
-    // return () => controller.abort() // crash on React18
-  }, [accountId]);
-
-  return (
-    <Container maxWidth="sm" className="app">
-      <Header />
-      {account != null ? <AccountPreferences account={account} /> : <CircularProgress />}
-    </Container>
-  );
-};
-
-export default ServerOverview;
diff --git a/client/src/pages/ServerSetup.tsx b/client/src/pages/ServerSetup.tsx
index e045751..e6ff0aa 100644
--- a/client/src/pages/ServerSetup.tsx
+++ b/client/src/pages/ServerSetup.tsx
@@ -19,8 +19,6 @@
 import { Box, Card, CardContent, Container, Fab, Input, Typography } from '@mui/material';
 import { FormEvent, useState } from 'react';
 
-import authManager from '../AuthManager';
-
 export default function ServerSetup() {
   const [password, setPassword] = useState('');
   const [passwordRepeat, setPasswordRepeat] = useState('');
@@ -32,7 +30,8 @@
     e.preventDefault();
     setLoading(true);
     if (!isValid()) return;
-    authManager.setup(password);
+    // TODO: Migrate to new server
+    // authManager.setup(password);
   };
 
   return (
diff --git a/client/src/services/Account.ts b/client/src/services/Account.ts
deleted file mode 100644
index a955883..0000000
--- a/client/src/services/Account.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2022 Savoir-faire Linux Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation; either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public
- * License along with this program.  If not, see
- * <https://www.gnu.org/licenses/>.
- */
-import { useQuery } from '@tanstack/react-query';
-import axios from 'axios';
-
-export const useAccountQuery = (accountId: string) => {
-  return useQuery(['accounts', accountId], () => fetchAccount(accountId), {
-    enabled: !!accountId,
-  });
-};
-
-const fetchAccount = (accountId: string) => axios.get(`/api/accounts/${accountId}`).then((result) => result.data);
diff --git a/client/src/services/Conversation.ts b/client/src/services/Conversation.ts
index f89d5e9..d742730 100644
--- a/client/src/services/Conversation.ts
+++ b/client/src/services/Conversation.ts
@@ -18,30 +18,57 @@
 import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
 import axios from 'axios';
 
-export const useConversationQuery = (accountId: string, conversationId: string) => {
-  return useQuery(['conversation', accountId, conversationId], () => fetchConversation(accountId, conversationId), {
-    enabled: !!(accountId && conversationId),
+import { useAuthContext } from '../contexts/AuthProvider';
+import { apiUrl } from '../utils/constants';
+
+export const useConversationQuery = (conversationId: string) => {
+  const { token } = useAuthContext();
+  return useQuery(['conversation', conversationId], () => fetchConversation(conversationId, token), {
+    enabled: !!conversationId,
   });
 };
 
-export const useMessagesQuery = (accountId: string, conversationId: string) => {
-  return useQuery(['messages', accountId, conversationId], () => fetchMessages(accountId, conversationId), {
-    enabled: !!(accountId && conversationId),
+export const useMessagesQuery = (conversationId: string) => {
+  const { token } = useAuthContext();
+  return useQuery(['messages', conversationId], () => fetchMessages(conversationId, token), {
+    enabled: !!conversationId,
   });
 };
 
-export const useSendMessageMutation = (accountId: string, conversationId: string) => {
+export const useSendMessageMutation = (conversationId: string) => {
+  const { token } = useAuthContext();
   const queryClient = useQueryClient();
   return useMutation(
-    (message: string) => axios.post(`/api/accounts/${accountId}/conversations/${conversationId}`, { message }),
+    (message: string) =>
+      axios.post(
+        new URL(`/conversations/${conversationId}/messages`, apiUrl).toString(),
+        { message },
+        {
+          headers: {
+            Authorization: `Bearer ${token}`,
+          },
+        }
+      ),
     {
-      onSuccess: () => queryClient.invalidateQueries(['messages', accountId, conversationId]),
+      onSuccess: () => queryClient.invalidateQueries(['messages', conversationId]),
     }
   );
 };
 
-const fetchConversation = (accountId: string, conversationId: string) =>
-  axios.get(`/api/accounts/${accountId}/conversations/${conversationId}`).then((result) => result.data);
+const fetchConversation = (conversationId: string, token: string) =>
+  axios
+    .get(new URL(`/conversations/${conversationId}`, apiUrl).toString(), {
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+    })
+    .then((result) => result.data);
 
-const fetchMessages = (accountId: string, conversationId: string) =>
-  axios.get(`/api/accounts/${accountId}/conversations/${conversationId}/messages`).then((result) => result.data);
+const fetchMessages = (conversationId: string, token: string) =>
+  axios
+    .get(new URL(`/conversations/${conversationId}/messages`, apiUrl).toString(), {
+      headers: {
+        Authorization: `Bearer ${token}`,
+      },
+    })
+    .then((result) => result.data);