blob: 65d14a2020001503a5035ca3d7091d335d62f9a2 [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;
Misha Krieger-Raynauldb7ade042022-11-29 15:56:57 -050067 default:
68 throw e;
simon94fe53e2022-11-10 12:51:58 -050069 }
simon94fe53e2022-11-10 12:51:58 -050070 }
71 );
72
73 return instance;
74 }, [token, logout]);
75
simon416d0792022-11-03 02:46:18 -040076 useEffect(() => {
77 const accessToken = localStorage.getItem('accessToken');
78
79 if (!accessToken) {
80 console.warn('Missing authentication JWT. Redirecting to login page...');
81 logout();
82 } else {
83 setToken(accessToken);
84 }
85 }, [logout]);
86
87 useEffect(() => {
simon94fe53e2022-11-10 12:51:58 -050088 if (!axiosInstance) {
89 return;
simon416d0792022-11-03 02:46:18 -040090 }
simon416d0792022-11-03 02:46:18 -040091
simon94fe53e2022-11-10 12:51:58 -050092 axiosInstance.get('/account').then(({ data }) => setAccount(Account.from(data)));
93 }, [axiosInstance, logout]);
94
95 if (!token || !account || !axiosInstance) {
simon416d0792022-11-03 02:46:18 -040096 return <ProcessingRequest open />;
97 }
98
99 return (
100 <AuthContext.Provider
101 value={{
102 token,
103 logout,
104 account,
simonf929a362022-11-18 16:53:45 -0500105 accountId: account.getId(),
simon94fe53e2022-11-10 12:51:58 -0500106 axiosInstance,
simon416d0792022-11-03 02:46:18 -0400107 }}
108 >
Issam E. Maghni09a3a1f2022-11-02 04:56:21 +0000109 {children}
simon416d0792022-11-03 02:46:18 -0400110 </AuthContext.Provider>
111 );
112};
113
114export function useAuthContext(dontThrowIfUndefined: true): IAuthContext | undefined;
115export function useAuthContext(): IAuthContext;
116export function useAuthContext(dontThrowIfUndefined?: true) {
117 const authContext = useContext(AuthContext);
118 if (!authContext && !dontThrowIfUndefined) {
119 throw new Error('AuthContext is not provided');
120 }
121 return authContext;
122}