blob: ced9a855ee8b40a606ae9c76856f07bec16b56bc [file] [log] [blame]
simon416d0792022-11-03 02:46:18 -04001/*
2 * Copyright (C) 2022 Savoir-faire Linux Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation; either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public
15 * License along with this program. If not, see
16 * <https://www.gnu.org/licenses/>.
17 */
simon94fe53e2022-11-10 12:51:58 -050018import axios, { AxiosInstance } from 'axios';
simon416d0792022-11-03 02:46:18 -040019import { Account } from 'jami-web-common/dist/Account';
20import { HttpStatusCode } from 'jami-web-common/dist/enums/http-status-code';
simon94fe53e2022-11-10 12:51:58 -050021import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
Issam E. Maghni09a3a1f2022-11-02 04:56:21 +000022import { useNavigate } from 'react-router-dom';
simon416d0792022-11-03 02:46:18 -040023
24import ProcessingRequest from '../components/ProcessingRequest';
25import { apiUrl } from '../utils/constants';
Issam E. Maghni09a3a1f2022-11-02 04:56:21 +000026import { WithChildren } from '../utils/utils';
simon416d0792022-11-03 02:46:18 -040027
28interface IAuthContext {
29 token: string;
30 account: Account;
simonf929a362022-11-18 16:53:45 -050031 accountId: string;
simon416d0792022-11-03 02:46:18 -040032 logout: () => void;
simon94fe53e2022-11-10 12:51:58 -050033 axiosInstance: AxiosInstance;
simon416d0792022-11-03 02:46:18 -040034}
35
36const AuthContext = createContext<IAuthContext | undefined>(undefined);
37
Issam E. Maghni09a3a1f2022-11-02 04:56:21 +000038export default ({ children }: WithChildren) => {
simon416d0792022-11-03 02:46:18 -040039 const [token, setToken] = useState<string | undefined>();
40 const [account, setAccount] = useState<Account | undefined>();
41 const navigate = useNavigate();
42
43 const logout = useCallback(() => {
44 localStorage.removeItem('accessToken');
simon3f5f3e72022-11-08 21:01:57 -050045 navigate('/login');
simon416d0792022-11-03 02:46:18 -040046 }, [navigate]);
47
simon94fe53e2022-11-10 12:51:58 -050048 const axiosInstance = useMemo(() => {
49 if (!token) {
50 return;
51 }
52
53 const instance = axios.create({
54 baseURL: apiUrl,
55 headers: {
56 Authorization: `Bearer ${token}`,
57 },
58 });
59
60 instance.interceptors.response.use(
61 (res) => res,
62 (e) => {
63 switch (e.response?.status) {
64 case HttpStatusCode.Unauthorized:
65 logout();
66 break;
67 }
68 throw e;
69 }
70 );
71
72 return instance;
73 }, [token, logout]);
74
simon416d0792022-11-03 02:46:18 -040075 useEffect(() => {
76 const accessToken = localStorage.getItem('accessToken');
77
78 if (!accessToken) {
79 console.warn('Missing authentication JWT. Redirecting to login page...');
80 logout();
81 } else {
82 setToken(accessToken);
83 }
84 }, [logout]);
85
86 useEffect(() => {
simon94fe53e2022-11-10 12:51:58 -050087 if (!axiosInstance) {
88 return;
simon416d0792022-11-03 02:46:18 -040089 }
simon416d0792022-11-03 02:46:18 -040090
simon94fe53e2022-11-10 12:51:58 -050091 axiosInstance.get('/account').then(({ data }) => setAccount(Account.from(data)));
92 }, [axiosInstance, logout]);
93
94 if (!token || !account || !axiosInstance) {
simon416d0792022-11-03 02:46:18 -040095 return <ProcessingRequest open />;
96 }
97
98 return (
99 <AuthContext.Provider
100 value={{
101 token,
102 logout,
103 account,
simonf929a362022-11-18 16:53:45 -0500104 accountId: account.getId(),
simon94fe53e2022-11-10 12:51:58 -0500105 axiosInstance,
simon416d0792022-11-03 02:46:18 -0400106 }}
107 >
Issam E. Maghni09a3a1f2022-11-02 04:56:21 +0000108 {children}
simon416d0792022-11-03 02:46:18 -0400109 </AuthContext.Provider>
110 );
111};
112
113export function useAuthContext(dontThrowIfUndefined: true): IAuthContext | undefined;
114export function useAuthContext(): IAuthContext;
115export function useAuthContext(dontThrowIfUndefined?: true) {
116 const authContext = useContext(AuthContext);
117 if (!authContext && !dontThrowIfUndefined) {
118 throw new Error('AuthContext is not provided');
119 }
120 return authContext;
121}