blob: 82217457f0cd49cf2baa93802d61562e7648485a [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';
Misha Krieger-Raynauldcfa44302022-11-30 18:36:36 -050019import { HttpStatusCode, IAccount } from 'jami-web-common';
simon09fe4822022-11-30 23:36:25 -050020import { useCallback, useEffect, useMemo, useState } from 'react';
Issam E. Maghni09a3a1f2022-11-02 04:56:21 +000021import { useNavigate } from 'react-router-dom';
simon416d0792022-11-03 02:46:18 -040022
23import ProcessingRequest from '../components/ProcessingRequest';
simon09fe4822022-11-30 23:36:25 -050024import { createOptionalContext } from '../hooks/createOptionalContext';
Misha Krieger-Raynauldcfa44302022-11-30 18:36:36 -050025import { Account } from '../models/account';
simon416d0792022-11-03 02:46:18 -040026import { apiUrl } from '../utils/constants';
Issam E. Maghni09a3a1f2022-11-02 04:56:21 +000027import { WithChildren } from '../utils/utils';
simon416d0792022-11-03 02:46:18 -040028
29interface IAuthContext {
30 token: string;
31 account: Account;
simonf929a362022-11-18 16:53:45 -050032 accountId: string;
simon416d0792022-11-03 02:46:18 -040033 logout: () => void;
simon94fe53e2022-11-10 12:51:58 -050034 axiosInstance: AxiosInstance;
simon416d0792022-11-03 02:46:18 -040035}
36
simon09fe4822022-11-30 23:36:25 -050037const optionalAuthContext = createOptionalContext<IAuthContext>('AuthContext');
38const AuthContext = optionalAuthContext.Context;
39export const useAuthContext = optionalAuthContext.useOptionalContext;
simon416d0792022-11-03 02:46:18 -040040
Issam E. Maghni09a3a1f2022-11-02 04:56:21 +000041export default ({ children }: WithChildren) => {
simon416d0792022-11-03 02:46:18 -040042 const [token, setToken] = useState<string | undefined>();
43 const [account, setAccount] = useState<Account | undefined>();
44 const navigate = useNavigate();
45
46 const logout = useCallback(() => {
47 localStorage.removeItem('accessToken');
simon3f5f3e72022-11-08 21:01:57 -050048 navigate('/login');
simon416d0792022-11-03 02:46:18 -040049 }, [navigate]);
50
simon94fe53e2022-11-10 12:51:58 -050051 const axiosInstance = useMemo(() => {
52 if (!token) {
53 return;
54 }
55
56 const instance = axios.create({
57 baseURL: apiUrl,
58 headers: {
59 Authorization: `Bearer ${token}`,
60 },
61 });
62
63 instance.interceptors.response.use(
64 (res) => res,
65 (e) => {
66 switch (e.response?.status) {
67 case HttpStatusCode.Unauthorized:
68 logout();
69 break;
70 }
Misha Krieger-Raynauld0c2e9862022-11-29 19:04:44 -050071 throw e;
simon94fe53e2022-11-10 12:51:58 -050072 }
73 );
74
75 return instance;
76 }, [token, logout]);
77
simon416d0792022-11-03 02:46:18 -040078 useEffect(() => {
79 const accessToken = localStorage.getItem('accessToken');
80
81 if (!accessToken) {
82 console.warn('Missing authentication JWT. Redirecting to login page...');
83 logout();
84 } else {
85 setToken(accessToken);
86 }
87 }, [logout]);
88
89 useEffect(() => {
simon94fe53e2022-11-10 12:51:58 -050090 if (!axiosInstance) {
91 return;
simon416d0792022-11-03 02:46:18 -040092 }
simon416d0792022-11-03 02:46:18 -040093
Misha Krieger-Raynauldcfa44302022-11-30 18:36:36 -050094 axiosInstance.get<IAccount>('/account').then(({ data }) => setAccount(Account.fromInterface(data)));
simon94fe53e2022-11-10 12:51:58 -050095 }, [axiosInstance, logout]);
96
simon5c677962022-12-02 16:51:54 -050097 const value = useMemo(() => {
98 if (!token || !account || !axiosInstance) {
99 return;
100 }
101
102 return {
103 token,
104 logout,
105 account,
106 accountId: account.id,
107 axiosInstance,
108 };
109 }, [token, logout, account, axiosInstance]);
110
111 if (!value) {
simon416d0792022-11-03 02:46:18 -0400112 return <ProcessingRequest open />;
113 }
114
simon5c677962022-12-02 16:51:54 -0500115 return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
simon416d0792022-11-03 02:46:18 -0400116};