diff --git a/.env b/.env index 7895789..6aca7b9 100644 --- a/.env +++ b/.env @@ -1,4 +1,5 @@ -REACT_APP_ACCOUNT_USERNAME=+191xxxxxxx -REACT_APP_ACCOUNT_DISPLAY_NAME=+1919xxxxxx -REACT_APP_ACCOUNT_PASSWORD=+1919xxxxxxx -REACT_APP_AUTH_TOKEN=xxxxxxxx \ No newline at end of file +REACT_APP_ACCOUNT_USERNAME=xxxxxxxxxx +REACT_APP_ACCOUNT_DISPLAY_NAME=xxxxxxxxx +REACT_APP_ACCOUNT_PASSWORD=xxxxxxxxx +REACT_APP_AUTH_URL=https://authtoken.url +REACT_APP_AUTH_CREDENTIALS='username:pass' \ No newline at end of file diff --git a/package.json b/package.json index 36957b6..9c6cec7 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@testing-library/react": "^13.0.0", "@testing-library/user-event": "^13.2.1", "axios": "^1.5.0", + "cors": "^2.8.5", "firebase": "^10.12.3", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -59,4 +60,4 @@ "last 1 safari version" ] } -} \ No newline at end of file +} diff --git a/src/auth_service.js b/src/auth_service.js new file mode 100644 index 0000000..0a19e1b --- /dev/null +++ b/src/auth_service.js @@ -0,0 +1,85 @@ +// Store token and expiry in localStorage +const TOKEN_STORAGE_KEY = 'auth_token'; +const EXPIRY_STORAGE_KEY = 'token_expiry'; + +// Your API details +const AUTH_URL = process.env.REACT_APP_AUTH_URL; +const header = process.env.REACT_APP_AUTH_CREDENTIALS; +const BASIC_AUTH_CREDENTIALS = btoa(header); // Base64 encoding for Basic Auth +const REFRESH_INTERVAL = 60 * 1000; // Check every 60 seconds + +// Function to fetch new token +const fetchAuthToken = async () => { + try { + var headers = { + 'Authorization': 'Basic ' + BASIC_AUTH_CREDENTIALS, + 'Content-Type': 'application/x-www-form-urlencoded', + 'Origin': '*', + 'Access-Control-Allow-Headers': '*', + 'Access-Control-Allow-Origin': '*', + }; + const response = await fetch(`${AUTH_URL}`, { + method: 'post', + headers: headers, + body: 'grant_type=client_credentials' + },); + + const data = await response.json(); + + console.log("Data: " + data); + + const { access_token, expires_in } = data; + + // Store token and expiry time + localStorage.setItem(TOKEN_STORAGE_KEY, access_token); + localStorage.setItem(EXPIRY_STORAGE_KEY, Date.now() + expires_in * 1000); + return access_token; + } catch (error) { + console.error("Error fetching auth token", error); + return null; + } +}; + +// Function to check and refresh token periodically +const startTokenRefreshLoop = () => { + setInterval(async () => { + const token = localStorage.getItem(TOKEN_STORAGE_KEY); + const expiryTime = localStorage.getItem(EXPIRY_STORAGE_KEY); + + if (!token || !expiryTime) { + console.log("[oAuth Service] No token found, fetching a new one..."); + await fetchAuthToken(); + return; + } + + const timeLeft = expiryTime - Date.now(); + console.log(`[oAuth Service] Token expires in ${Math.floor(timeLeft / 1000)} seconds`); + + // Refresh token if it will expire in less than 2 minutes + if (timeLeft < 2 * 60 * 1000) { + console.log("[oAuth Service] Refreshing token before expiry..."); + await fetchAuthToken(); + } + }, REFRESH_INTERVAL); +}; + + +// Function to check token validity and refresh if needed +const getAuthToken = async () => { + const token = localStorage.getItem(TOKEN_STORAGE_KEY); + const expiryTime = parseInt(localStorage.getItem(EXPIRY_STORAGE_KEY), 10); + + if (token && expiryTime && Date.now() < expiryTime - 60000) { // Refresh 1 min before expiry + return token; + } + + return await fetchAuthToken(); +}; + +// Initialize authentication flow +const initAuth = async () => { + await fetchAuthToken(); // Get initial token + startTokenRefreshLoop(); // Start background refresh +}; + +export { initAuth, TOKEN_STORAGE_KEY }; diff --git a/src/components/DialPad.js b/src/components/DialPad.js index bc271c9..af5b5b0 100644 --- a/src/components/DialPad.js +++ b/src/components/DialPad.js @@ -4,6 +4,7 @@ import { db, setupNotifications } from '../fireabase_helper'; import '../css/DialPad.css'; import StatusBar from './StatusBar'; import DigitGrid from './DigitGrid'; +import { initAuth, TOKEN_STORAGE_KEY } from '../auth_service' import NumberInput from './NumberInput'; import CallControlButton from './CallControlButton'; import CallIcon from '@mui/icons-material/Call'; @@ -16,7 +17,6 @@ import { Button } from '@mui/material'; export default function DialPad() { console.log("Dialpad rendering..."); const userId = process.env.REACT_APP_ACCOUNT_USERNAME; - const authToken = process.env.REACT_APP_AUTH_TOKEN; const sourceNumber = userId; console.log('User ID:', userId); @@ -56,6 +56,7 @@ export default function DialPad() { setIncomingCall(true); updateFBStatus('Ringing'); }); + initAuth(); }, []); useEffect(() => { @@ -93,7 +94,6 @@ export default function DialPad() { ); newPhone.checkAvailableDevices(); newPhone.setAccount(`${sourceNumber}`, 'In-App Calling Sample', ''); - newPhone.setOAuthToken(authToken); newPhone.init(); setPhone(newPhone); }, []); @@ -270,21 +270,27 @@ export default function DialPad() { } const handleDialClick = () => { - if (phone.isInitialized()) { - updateFBStatus("Calling"); - setCallStatus('Calling'); - setWebRtcStatus('Ringing'); - let extraHeaders = [`User-to-User:eyJhbGciOiJIUzI1NiJ9.WyJoaSJd.-znkjYyCkgz4djmHUPSXl9YrJ6Nix_XvmlwKGFh5ERM;encoding=jwt;aGVsbG8gd29ybGQ;encoding=base64`]; - console.log("Dialed number: ", destNumber); - phone.makeCall(`${destNumber}`, extraHeaders).then((value) => { - setActiveCall(value); - }); - setDialedNumber(`+${destNumber}`); - setAllowHangup(true); - setAllowBackspace(false); - reset(); + var authToken = localStorage.getItem(TOKEN_STORAGE_KEY); + if (authToken) { + if (phone.isInitialized()) { + updateFBStatus("Calling"); + setCallStatus('Calling'); + setWebRtcStatus('Ringing'); + let extraHeaders = [`User-to-User:eyJhbGciOiJIUzI1NiJ9.WyJoaSJd.-znkjYyCkgz4djmHUPSXl9YrJ6Nix_XvmlwKGFh5ERM;encoding=jwt;aGVsbG8gd29ybGQ;encoding=base64`]; + console.log("Dialed number: ", destNumber); + phone.setOAuthToken(authToken); + phone.makeCall(`${destNumber}`, extraHeaders).then((value) => { + setActiveCall(value); + }); + setDialedNumber(`+${destNumber}`); + setAllowHangup(true); + setAllowBackspace(false); + reset(); + } else { + console.error("BandwithUA not initialized!"); + } } else { - console.error("BandwithUA not initialized!"); + console.error("Invalid/Empty oAuth Token"); } };