diff --git a/OAuth2.md b/OAuth2.md index 0679ef4..e5907db 100644 --- a/OAuth2.md +++ b/OAuth2.md @@ -41,6 +41,8 @@ A way for the `user` to tell `google` to give an access token to `xorismesiti.gr 2. After the redirection, the user will log in to Google and grant permissions (if they haven’t already). 3. Google will redirect the user back to your redirect_uri `https://xorismesiti.gr/callback` with an authorization code `?code=` +*Security: the state string should be validated upon receiving the response from Google, as it ensures that the response corresponds to the request.* +

Frontend HTTP GET Request to Google

@@ -100,7 +102,7 @@ const loginWithGoogle = () => { # 2. [Frontend] Receive Authorization Code -Now that the frontend have the Authorization `code` on th callback url https://xorismesiti.gr/api/auth/callback`?code=AAAABCX4XfWgyVyziyLg0QHHHHH` it can send it to the backend with POST to `xorismesiti.gr/api/auth/exchange-token`, in order the backend to exchange the `code` for an `access_token` and optionally an `refresh_token` +Now that the frontend has the Authorization `code` on th callback url https://xorismesiti.gr/api/auth/callback`?code=AAAABCX4XfWgyVyziyLg0QHHHHH` it can send it to the backend with POST to `xorismesiti.gr/api/auth/exchange-token`, in order the backend to exchange the `code` for an `access_token` and optionally an `refresh_token`

Frontend HTTP POST Request to Backend

@@ -324,22 +326,81 @@ Authorization: Bearer access-token-from-backend

Frontend Code

```js -// After receiving the token, store it in the frontend (e.g., localStorage or context) -localStorage.setItem('access_token', response.access_token); +// Store tokens and expiration time after receiving them from the backend +const storeTokens = (access_token, refresh_token, expires_in) => { + const expirationTime = Date.now() + expires_in * 1000; // expires_in is in seconds, so multiply by 1000 to get ms + localStorage.setItem('access_token', access_token); + localStorage.setItem('refresh_token', refresh_token); + localStorage.setItem('token_expiration', expirationTime); +}; -// Use it to make authenticated API requests to the backend -fetch('/api/user-profile', { - headers: { - 'Authorization': `Bearer ${localStorage.getItem('access_token')}`, - }, -}) - .then(response => response.json()) - .then(data => { - // Handle user data - }) - .catch(error => { +// Function to check if the access token has expired +const isTokenExpired = () => { + const expirationTime = localStorage.getItem('token_expiration'); + return Date.now() > expirationTime; +}; + +// Function to refresh the access token using the refresh token +const refreshAccessToken = async () => { + const refresh_token = localStorage.getItem('refresh_token'); + try { + const response = await fetch('/api/auth/refresh-token', { + method: 'POST', + body: JSON.stringify({ refresh_token }), + headers: { + 'Content-Type': 'application/json', + }, + }); + + const data = await response.json(); + if (data.access_token) { + // Store the new access token and expiration time + storeTokens(data.access_token, data.refresh_token, data.expires_in); + return data.access_token; + } + } catch (error) { + console.error('Error refreshing token:', error); + return null; // Handle error appropriately (e.g., logout user or prompt to log in again) + } +}; + +// Function to get the access token, either from localStorage or by refreshing it if expired +const getAccessToken = async () => { + if (isTokenExpired()) { + console.log('Access token expired. Refreshing...'); + const newAccessToken = await refreshAccessToken(); + return newAccessToken; + } else { + return localStorage.getItem('access_token'); + } +}; + +// Example usage: Get the access token and use it for an authenticated API request +const fetchUserProfile = async () => { + const access_token = await getAccessToken(); + + if (!access_token) { + console.error('No valid access token found. User might need to log in.'); + return; + } + + // Now you can use the access token to make an authenticated API request + try { + const response = await fetch('/api/user-profile', { + headers: { + 'Authorization': `Bearer ${access_token}`, + }, + }); + + const userData = await response.json(); + console.log(userData); + } catch (error) { console.error('Error fetching user profile:', error); - }); + } +}; + +// Example call to fetch user profile +fetchUserProfile(); ```