erikg713 / Palace-of-Quests

Other
0 stars 0 forks source link

Coding #5

Open erikg713 opened 1 week ago

erikg713 commented 1 week ago

Hey @autopilot implement a Google sign-in on my website. Make changes to the front end and the back end of the application

I want to allow users to signup and login using their Google account

codeautopilot[bot] commented 1 week ago

Potential solution

To implement Google sign-in functionality on your website, you need to integrate both the frontend and backend components to handle Google OAuth authentication. This involves setting up the necessary libraries, creating endpoints for token verification, and managing user data. The solution involves updating the backend to verify Google tokens and manage user records, and updating the frontend to initiate the Google sign-in process and handle responses.

How to implement

Backend Implementation

  1. Update Dependencies:

    • Add google-auth and google-auth-oauthlib to backend/requirements.txt to handle Google OAuth authentication.
    • Install the new dependencies using pip install -r backend/requirements.txt.
  2. Create Google Sign-In Route:

    • In backend/app/routes/auth.py, create a new route /google-signin to handle POST requests with the Google OAuth token.
    • Verify the token using Google's OAuth2 library and manage user records in the database.
    from flask import Blueprint, request, jsonify
    from google.oauth2 import id_token
    from google.auth.transport import requests as google_requests
    from app.models import User, db
    from app.utils.security import create_jwt
    
    auth_bp = Blueprint('auth', __name__)
    
    @auth_bp.route('/google-signin', methods=['POST'])
    def google_signin():
       token = request.json.get('token')
       try:
           idinfo = id_token.verify_oauth2_token(token, google_requests.Request(), 'YOUR_GOOGLE_CLIENT_ID')
           email = idinfo.get('email')
           name = idinfo.get('name')
    
           user = User.query.filter_by(email=email).first()
           if not user:
               user = User(email=email, username=name)
               db.session.add(user)
               db.session.commit()
    
           jwt_token = create_jwt({"user_id": user.id})
           response = jsonify({"message": "Logged in successfully"})
           response.set_cookie("access_token", jwt_token, httponly=True, secure=True)
           return response, 200
    
       except ValueError:
           return jsonify({"error": "Invalid token"}), 401
  3. Add Token Verification in Auth Service:

    • In backend/services/auth_service.py, add a function to verify Google OAuth tokens and manage user data.
    from google.oauth2 import id_token
    from google.auth.transport import requests
    
    class AuthService:
       @staticmethod
       def verify_google_token(token):
           try:
               CLIENT_ID = "YOUR_GOOGLE_CLIENT_ID"
               idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID)
               email = idinfo.get('email')
               name = idinfo.get('name')
    
               user = User.query.filter_by(email=email).first()
               if not user:
                   user = User(email=email, username=name)
                   db.session.add(user)
                   db.session.commit()
    
               access_token = create_access_token(identity=user.id)
               return access_token
    
           except ValueError:
               return None

Frontend Implementation

  1. Install React Google Login Library:

    • Install react-google-login using npm install react-google-login.
  2. Update Login Form Component:

    • In frontend/src/components/LoginForm.js, import GoogleLogin and add a Google sign-in button.
    import { GoogleLogin } from 'react-google-login';
    
    function LoginForm() {
     const handleGoogleSuccess = (response) => {
       console.log("Google login success:", response);
     };
    
     const handleGoogleFailure = (response) => {
       console.error("Google login failed:", response);
     };
    
     return (
       <form>
         <GoogleLogin
           clientId="YOUR_GOOGLE_CLIENT_ID"
           buttonText="Login with Google"
           onSuccess={handleGoogleSuccess}
           onFailure={handleGoogleFailure}
           cookiePolicy={'single_host_origin'}
         />
       </form>
     );
    }
  3. Update Login Page:

    • In frontend/src/pages/LoginPage.js, handle the Google sign-in response and send the token to the backend.
    import { GoogleLogin } from 'react-google-login';
    
    function LoginPage() {
     const handleGoogleSuccess = async (response) => {
       try {
         const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/google-signin`, { token: response.tokenId });
         localStorage.setItem('access_token', res.data.access_token);
         window.location.href = '/quest';
       } catch (err) {
         console.error('Google sign-in failed', err);
       }
     };
    
     const handleGoogleFailure = (error) => {
       console.error('Google sign-in failed', error);
     };
    
     return (
       <div>
         <GoogleLogin
           clientId={process.env.REACT_APP_GOOGLE_CLIENT_ID}
           buttonText="Login with Google"
           onSuccess={handleGoogleSuccess}
           onFailure={handleGoogleFailure}
           cookiePolicy={'single_host_origin'}
         />
       </div>
     );
    }
  4. Environment Variables:

    • Ensure you have set up your Google Client ID in your environment variables (REACT_APP_GOOGLE_CLIENT_ID).

By following these steps, you will enable Google sign-in functionality on your website, allowing users to authenticate using their Google accounts.

Click here to create a Pull Request with the proposed solution

Files used for this task:

Changes on backend/requirements.txt To implement Google sign-in functionality, you need to add the necessary libraries for handling Google OAuth in the `backend/requirements.txt` file. Here’s what you should do: 1. **Add Google OAuth Libraries**: Include libraries such as `google-auth` and `google-auth-oauthlib` to handle Google OAuth authentication. Update the `requirements.txt` file as follows: ```plaintext Flask==2.2.5 Flask-SQLAlchemy==2.5.1 psycopg2==2.9.1 pi-sdk==1.0.0 # Placeholder for the actual Pi Network SDK gunicorn==22.0.0 Flask-JWT-Extended==4.3.1 cryptography==3.4.7 google-auth==2.23.0 google-auth-oauthlib==1.0.0 ``` 2. **Install the New Dependencies**: After updating the `requirements.txt` file, ensure you install the new dependencies by running: ```bash pip install -r backend/requirements.txt ``` This will set up your backend environment to handle Google OAuth tokens and integrate with Google's authentication services.
Changes on frontend/src/api/auth.js To implement Google sign-in functionality in this file (`frontend/src/api/auth.js`), you need to add functions that will handle the communication with the backend for Google OAuth token verification and user data retrieval. Here's a practical proposal for what you need to do: 1. **Add a Function to Handle Google Sign-In:** - Create a new function `googleSignIn` that will send the Google OAuth token to the backend for verification. 2. **Implement the Function:** - Use `axios` to make a POST request to a new endpoint (e.g., `/auth/google-signin`) on your backend that will handle the Google token verification and user authentication. 3. **Handle Errors:** - Ensure that any errors during the request are caught and handled appropriately, similar to the existing `login` and `register` functions. Here's a sample implementation: ```javascript export const googleSignIn = async (googleToken) => { try { const response = await api.post('/auth/google-signin', { token: googleToken }); return response.data; } catch (error) { handleError(error); } }; ``` This function will be called from your frontend components once the user successfully signs in with Google, passing the received Google token to your backend for further processing.
Changes on backend/app/routes/auth.py To implement Google sign-in functionality in the `auth.py` file, you need to create a new route that will handle the verification of Google OAuth tokens and manage user records in the database. Here's a step-by-step guide on how to achieve this: 1. **Import Necessary Libraries**: Ensure you have the necessary libraries for handling Google OAuth. You might need to add `google-auth` or similar libraries to your `requirements.txt` and install them. 2. **Create a New Route for Google Sign-In**: - Define a new route, e.g., `/google-signin`, to handle POST requests containing the Google OAuth token. - Extract the token from the request data. 3. **Verify Google OAuth Token**: - Use the Google OAuth library to verify the token. This typically involves sending the token to Google's OAuth2 token verification endpoint. - Retrieve user information from the verified token, such as email and name. 4. **Manage User Records**: - Check if a user with the retrieved email already exists in your database. - If the user exists, update any necessary information. - If the user does not exist, create a new user record. 5. **Return a Response**: - Generate a JWT token for the authenticated user. - Return a response with the JWT token and any other necessary user information. Here's a basic implementation outline: ```python from flask import Blueprint, request, jsonify from google.oauth2 import id_token from google.auth.transport import requests as google_requests from app.models import User, db from app.utils.security import create_jwt auth_bp = Blueprint('auth', __name__) @auth_bp.route('/google-signin', methods=['POST']) def google_signin(): token = request.json.get('token') try: # Verify the token with Google's OAuth2 idinfo = id_token.verify_oauth2_token(token, google_requests.Request(), 'YOUR_GOOGLE_CLIENT_ID') # Extract user information email = idinfo.get('email') name = idinfo.get('name') # Check if user exists user = User.query.filter_by(email=email).first() if not user: # Create a new user if not exists user = User(email=email, username=name) db.session.add(user) db.session.commit() # Create JWT token jwt_token = create_jwt({"user_id": user.id}) # Return response with JWT token response = jsonify({"message": "Logged in successfully"}) response.set_cookie("access_token", jwt_token, httponly=True, secure=True) return response, 200 except ValueError: # Invalid token return jsonify({"error": "Invalid token"}), 401 ``` **Note**: Replace `'YOUR_GOOGLE_CLIENT_ID'` with your actual Google Client ID. Ensure that your application is registered with Google and you have the necessary credentials set up.
Changes on backend/services/auth_service.py To implement Google sign-in functionality in the `auth_service.py` file, you need to add functions to verify Google OAuth tokens and manage user data accordingly. Here's a practical proposal for how to achieve this: 1. **Install Required Libraries**: Ensure that you have installed necessary libraries for handling Google OAuth, such as `google-auth` and `google-auth-oauthlib`. You can add these to your `requirements.txt` and install them using pip. 2. **Import Necessary Modules**: Import the required modules for handling Google OAuth tokens. ```python from google.oauth2 import id_token from google.auth.transport import requests ``` 3. **Add a Function to Verify Google OAuth Tokens**: Create a function that verifies the Google OAuth token received from the frontend. This function will decode the token and retrieve the user's information. ```python class AuthService: # Existing methods... @staticmethod def verify_google_token(token): try: # Specify the CLIENT_ID of the app that accesses the backend CLIENT_ID = "YOUR_GOOGLE_CLIENT_ID" idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID) # ID token is valid. Get the user's Google Account ID from the decoded token. userid = idinfo['sub'] email = idinfo.get('email') name = idinfo.get('name') # Check if user exists in the database user = User.query.filter_by(email=email).first() if not user: # If user does not exist, create a new user user = User(email=email, username=name) db.session.add(user) db.session.commit() # Create access token for the user access_token = create_access_token(identity=user.id) return access_token except ValueError: # Invalid token return None ``` 4. **Manage User Data**: In the `verify_google_token` function, check if the user already exists in the database. If not, create a new user record. This ensures that users can log in with their Google account even if they haven't registered manually. 5. **Return Access Token**: After verifying the token and managing user data, generate and return an access token for the authenticated user. By implementing these changes, you will enable Google sign-in functionality in your application, allowing users to authenticate using their Google accounts.
Changes on frontend/src/components/LoginForm.js To implement Google sign-in functionality in the `LoginForm.js` component, you can use the `react-google-login` library. Here’s a step-by-step guide to modify this file: 1. **Install the `react-google-login` library**: First, ensure that the `react-google-login` library is installed in your project. You can do this by running the following command in your project directory: ```bash npm install react-google-login ``` 2. **Import the GoogleLogin component**: At the top of your `LoginForm.js` file, import the `GoogleLogin` component from the `react-google-login` library. ```javascript import { GoogleLogin } from 'react-google-login'; ``` 3. **Add a Google sign-in button**: Integrate the `GoogleLogin` component into your form. You will need to provide your Google Client ID and handle the response from Google. ```javascript function LoginForm() { const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const handleSubmit = async (e) => { e.preventDefault(); const token = await login(username, password); console.log("Logged in with token:", token); }; const handleGoogleSuccess = (response) => { console.log("Google login success:", response); // You can send the response token to your backend for verification }; const handleGoogleFailure = (response) => { console.error("Google login failed:", response); }; return (
setUsername(e.target.value)} /> setPassword(e.target.value)} /> ); } ``` 4. **Replace `YOUR_GOOGLE_CLIENT_ID`**: Make sure to replace `YOUR_GOOGLE_CLIENT_ID` with your actual Google Client ID, which you can obtain from the Google Developer Console. By following these steps, you will have added a Google sign-in button to your login form, allowing users to authenticate using their Google accounts. The `handleGoogleSuccess` function will handle successful logins, and you can further process the response to integrate with your backend authentication logic.
Changes on frontend/src/pages/LoginPage.js To integrate Google sign-in functionality into the `LoginPage.js` file, you can follow these steps: 1. **Install the Required Library**: First, ensure you have the `react-google-login` library installed. You can do this by running: ```bash npm install react-google-login ``` 2. **Import the Google Login Component**: Import the `GoogleLogin` component from the `react-google-login` library at the top of your file. 3. **Add Google Login Button**: Add the `GoogleLogin` button to your component and configure it to handle the OAuth flow. 4. **Handle Google Sign-In Response**: Implement a function to handle the response from Google and manage the user authentication state. Here's how you can modify the `LoginPage.js` file: ```javascript import React, { useState } from 'react'; import axios from 'axios'; import { GoogleLogin } from 'react-google-login'; function LoginPage() { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(null); const handleLogin = async (e) => { e.preventDefault(); try { const response = await axios.post(`${process.env.REACT_APP_API_URL}/auth/login`, { username, password }); localStorage.setItem('access_token', response.data.access_token); window.location.href = '/quest'; } catch (err) { setError('Invalid credentials'); } }; const handleGoogleSuccess = async (response) => { try { const res = await axios.post(`${process.env.REACT_APP_API_URL}/auth/google`, { token: response.tokenId }); localStorage.setItem('access_token', res.data.access_token); window.location.href = '/quest'; } catch (err) { setError('Google sign-in failed'); } }; const handleGoogleFailure = (error) => { setError('Google sign-in failed'); }; return (
setUsername(e.target.value)} /> setPassword(e.target.value)} /> {error &&

{error}

}
); } export default LoginPage; ``` ### Key Points: - **Google Client ID**: Ensure you have set up a Google Client ID in your environment variables (`REACT_APP_GOOGLE_CLIENT_ID`). - **Backend Endpoint**: The `/auth/google` endpoint should be implemented in your backend to handle the Google token verification and user authentication. - **Error Handling**: Proper error handling is implemented for both the traditional login and Google sign-in processes.