### OAuth2 purpose A way for the `user` to tell `google` to give an access to `xorismesiti.gr` app
### Flow: | When | What | How | |-------|--------------------------|--------------------------------------------------| | 1 | Get Code | ` Front ⇢ Google ⇢ Back `| | 2 | Exchange Code with Token | ` Back ⇢ Google ⇢ Back ⇢ Front `| | 4 | Use Token | ` Front ⇢ Back ⇢ Google ⇢ Back ⇢ Front `|
### Details: 1. Get Code 1. Frontend **GET** to Google `https://accounts.google.com/o/oauth2` with callback url 2. Google **302** to Backend `https://xorismesiti.gr/api/auth/callback` with authorization code 2. Exchange Code with Token 1. Backend **POST** the `code` to Google `https://oauth2.googleapis.com/token` 2. Google **response** to Backend with an `access_token` and a `refresh token` 3. Backend **response** to Frontend with the `access_token` in a `cookie` 3. Use Token 1. Frontend **GET** profile data from Backend `https://xorismesiti.gr/api/auth/profile` using the `cookie` 2. Backend **GET** profile data from Google `https://www.googleapis.com/oauth2/v3/userinfo` using the `access_token` from Frontend `cookie` 3. Google **response** to Backend with profile data 4. Backend **response** to Frontend with profile data


# 1. Get Code 1. Frontend **GET** to Google `https://accounts.google.com/o/oauth2` with callback url 2. Google **302** to Backend `https://xorismesiti.gr/api/auth/callback` with authorization code ### 1. Front **GET** to Google ```sh GET https://accounts.google.com/o/oauth2/v2/auth? response_type=code& # This indicates you're using the "authorization code" flow. client_id=ABC34JHS9D& # Your Google API client ID created on the google API console. redirect_uri=https://xorismesiti.gr/api/auth/callback& # The URI Google will redirect to after the user consents. scope=email%20profile& # The permissions you're requesting (e.g., email, profile). state=xyz123 # A random string to protect against CSRF attacks. ``` ### 2. Google **302** to Back ```bash HTTP/1.1 302 Found Location: https://xorismesiti.gr/api/auth/callback?code=4/0AX4XfWgyVyz-uT8k7WiyLg0Q&state=xyz123 Content-Type: text/html; charset=UTF-8 Content-Length: 0 ``` *Security: the state string should be validated upon receiving the response from Google, as it ensures that the response corresponds to the request.*


# 2. Exchange Code with Token 1. Backend **POST** the `code` to Google `https://oauth2.googleapis.com/token` 2. Google **response** to Backend with an `access_token` and a `refresh token` 3. Backend **response** to Frontend with the `access_token` in a `cookie` ### 1. Back **POST** the `code` to Google ```sh POST https://oauth2.googleapis.com/token Content-Type: application/x-www-form-urlencoded grant_type=authorization_code& code=AAAABCX4XfWgyVyziyLg0QHHHHH& redirect_uri=https://xorismesiti.gr/callback& client_id=ABC34JHS9D& client_secret=PASS1234 ``` ### 2. Google **response** to Back ```json { "access_token": "ya29.a0AfH6SMC8Op6zXZkHi2XITkDoOVzYXt3hTY6sny54UlWlxrnKlX5Xv78is7BEHekVX-VoA", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "1//04d5XHqmn6Hdy3wTf5OYDP1SyBa74zEFURjddQ2A1cFw78PY13pQyWhlD2A6XhDQtKlrjAqU4kS3vGdMvckw", "scope": "email profile" } ``` ### 3. Backend **response** to Front ```json { "access_token": "ya29.a0AfH6SMC8Op6zXZkHi2XITkDoOVzYXt3hTY6sny54UlWlxrnKlX5Xv78is7BEHekVX-VoA", "token_type": "Bearer", "expires_in": 3600, }

Backend code

```js // Backend callback URL: http://localhost:3000/auth/google/callback app.get('/auth/google/callback', async (req, res) => { const { code } = req.query; // Extract the code from the query string try { // Exchange the authorization code for access token and refresh token const response = await axios.post('https://oauth2.googleapis.com/token', null, { params: { code, client_id: clientId, client_secret: clientSecret, redirect_uri: redirectUri, // Same as in Step 1 grant_type: 'authorization_code', }, }); const { access_token, refresh_token, expires_in } = response.data; // Store tokens in session or cookies res.cookie('access_token', access_token, { httpOnly: true, secure: true, maxAge: expires_in * 1000 }); res.cookie('refresh_token', refresh_token, { httpOnly: true, secure: true }); // Respond to frontend or redirect as needed res.send('Authentication successful! You can now use the app.'); } catch (error) { console.error('Error exchanging code for tokens:', error); res.status(500).send('Error during authentication'); } }); ```



# 3. Use Token ### 1. Frontend **GET** profile data from Backend ```bash curl -X GET https://xorismesiti.gr/api/auth/profile \ -H "Cookie: access_token=ya29.a0AfH6SMC8Op6zXZkHi2XITkDoOVzYXt3hTY6sny54UlWlxrnKlX5Xv78is7BEHekVX-VoA" \ -H "Accept: application/json" ``` ### 2. Backend **GET** profile data from Google ```bash curl -X GET "https://www.googleapis.com/oauth2/v3/userinfo" \ -H "Authorization: Bearer {access_token}" \ -H "Accept: application/json" ``` ### 3. Google **response** to Back with profile data ``` { "sub": "1234567890", "name": "John Doe", "given_name": "John", "family_name": "Doe", "profile": "https://plus.google.com/1234567890", "picture": "https://lh3.googleusercontent.com/a-/AOh14GgIXXl5JXzW0c1Szbl-e1Jch1vhl5rHhH65vlK6J5g5PqkGjj1O0p3t8bgVEOykQ6ykFSQ=s96", "email": "john.doe@example.com", "email_verified": true, "locale": "en" } ``` ### 4. Backend **response** to Front with profile data ``` { "sub": "1234567890", "name": "John Doe", "picture": "https://lh3.googleusercontent.com/8bgVEOykQ6ykFSQ=s96", "email": "john.doe@example.com", } ``` ### Frontend Code ```js import React, { useState, useEffect } from 'react'; import axios from 'axios'; const App = () => { const [user, setUser] = useState(null); const [isAuthenticated, setIsAuthenticated] = useState(false); // Fetch user data from the backend's /profile endpoint const fetchUserData = async () => { try { const response = await axios.get('http://localhost:3000/profile', { withCredentials: true, // Important: Ensure cookies are sent with the request }); setUser(response.data); // Set the user data from the response setIsAuthenticated(true); } catch (error) { console.error('Error fetching user profile:', error); } }; useEffect(() => { // Check if the user is authenticated by checking the cookie if (document.cookie.includes('access_token')) { fetchUserData(); // Fetch user profile if the access token is available in cookies } }, []); return (

Google OAuth2 with React

{!isAuthenticated ? (

Please log in with Google to access your profile:

) : (

Welcome, {user?.name}

Email: {user?.email}

Profile
)}
); }; export default App; ``` ------------------------- ```bash GET https://xorismesiti.gr/api/user-profile Authorization: Bearer access-token-from-backend ``` ```json { "sub": "1234567890", "name": "John Doe", "given_name": "John", "family_name": "Doe", "profile": "https://plus.google.com/1234567890", "picture": "https://lh3.googleusercontent.com/a-/AOh14GgIXXl5JXzW0c1Szbl-e1Jch1vhl5rHhH65vlK6J5g5PqkGjj1O0p3t8bgVEOykQ6ykFSQ=s96", "email": "john.doe@example.com", "email_verified": true, "locale": "en" } ``` ```sh GET https://www.googleapis.com/oauth2/v3/userinfo Authorization: Bearer ya29.a0AfH6SMC8Op6zXZkHi2XITkDoOVzYXt3hTY6sny54UlWlxrnKlX5Xv78is7BEHekVX-VoA ``` ```json { "sub": "1234567890", "name": "John Doe", "given_name": "John", "family_name": "Doe", "profile": "https://plus.google.com/1234567890", "picture": "https://lh3.googleusercontent.com/a-/AOh14GgIXXl5JXzW0c1Szbl-e1Jch1vhl5rHhH65vlK6J5g5PqkGjj1O0p3t8bgVEOykQ6ykFSQ=s96", "email": "john.doe@example.com", "email_verified": true, "locale": "en" } ``` ```json { "access_token": "ya29.a0AfH6SMC8Op6zXZkHi2XITkDoOVzYXt3hTY6sny54UlWlxrnKlX5Xv78is7BEHekVX-VoA", "token_type": "Bearer", "expires_in": 3600 } ```