Open shakenbake604 opened 1 month ago
To implement Google sign-in on your website, we need to make changes to both the front end and the back end of the application. This involves updating the user model to store Google OAuth tokens and profile information, configuring Passport.js for Google OAuth, setting up routes to handle authentication, and creating the necessary front-end components to manage the authentication state and handle redirects.
We need to update the User
model to include fields for Google OAuth tokens and profile information.
File: src/backend/models/User.js
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
googleId: {
type: String,
required: true,
unique: true
},
email: {
type: String,
required: true,
unique: true
},
displayName: {
type: String,
required: true
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
image: {
type: String
},
accessToken: {
type: String
},
refreshToken: {
type: String
},
createdAt: {
type: Date,
default: Date.now
}
});
module.exports = mongoose.model('User', UserSchema);
Configure Passport.js to use the Google OAuth strategy.
File: src/backend/config/passport.js
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const User = require('../models/User');
require('dotenv').config();
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.GOOGLE_CALLBACK_URL
},
async (accessToken, refreshToken, profile, done) => {
try {
let user = await User.findOne({ googleId: profile.id });
if (!user) {
user = new User({
googleId: profile.id,
displayName: profile.displayName,
email: profile.emails[0].value,
firstName: profile.name.givenName,
lastName: profile.name.familyName,
image: profile.photos[0].value,
accessToken,
refreshToken
});
await user.save();
}
return done(null, user);
} catch (err) {
return done(err, null);
}
}
));
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
try {
const user = await User.findById(id);
done(null, user);
} catch (err) {
done(err, null);
}
});
module.exports = passport;
Create routes to handle Google OAuth callbacks and token exchanges.
File: src/backend/routes/auth.js
const express = require('express');
const passport = require('passport');
const router = express.Router();
router.get('/auth/google',
passport.authenticate('google', { scope: ['profile', 'email'] })
);
router.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/login' }),
(req, res) => {
res.redirect('/');
}
);
module.exports = router;
Ensure that your main server file uses these routes.
File: src/backend/app.js
(or server.js
)
const express = require('express');
const passport = require('passport');
const authRoutes = require('./routes/auth');
require('./config/passport');
const app = express();
app.use(passport.initialize());
app.use(passport.session());
app.use('/', authRoutes);
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
Create a new file for managing authentication state and set up React Router.
File: src/frontend/context/AuthContext.js
import React, { createContext, useState, useEffect } from 'react';
export const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
useEffect(() => {
const token = localStorage.getItem('token');
if (token) {
setIsAuthenticated(true);
}
}, []);
return (
<AuthContext.Provider value={{ isAuthenticated, setIsAuthenticated }}>
{children}
</AuthContext.Provider>
);
};
Set up the main application component to handle routes and authentication state.
File: src/frontend/App.js
import React, { useContext } from 'react';
import { BrowserRouter as Router, Route, Redirect, Switch } from 'react-router-dom';
import { AuthContext, AuthProvider } from './context/AuthContext';
import Login from './components/Login';
import Dashboard from './components/Dashboard';
const PrivateRoute = ({ component: Component, ...rest }) => {
const { isAuthenticated } = useContext(AuthContext);
return (
<Route
{...rest}
render={props =>
isAuthenticated ? (
<Component {...props} />
) : (
<Redirect to="/login" />
)
}
/>
);
};
const App = () => {
return (
<AuthProvider>
<Router>
<Switch>
<Route path="/login" component={Login} />
<PrivateRoute path="/dashboard" component={Dashboard} />
<Redirect from="/" to="/login" />
</Switch>
</Router>
</AuthProvider>
);
};
export default App;
Add the Google sign-in button and handle the OAuth flow.
File: src/frontend/components/Login.js
import React from 'react';
import { GoogleLogin } from 'react-google-login';
const Login = () => {
const handleLoginSuccess = (response) => {
console.log('Login Success:', response.profileObj);
fetch('/auth/google', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ token: response.tokenId }),
})
.then(res => res.json())
.then(data => {
console.log('Backend Response:', data);
localStorage.setItem('token', data.token);
window.location.href = '/dashboard';
})
.catch(error => {
console.error('Error:', error);
});
};
const handleLoginFailure = (response) => {
console.error('Login Failed:', response);
};
return (
<div>
<h2>Login</h2>
<GoogleLogin
clientId="YOUR_GOOGLE_CLIENT_ID"
buttonText="Login with Google"
onSuccess={handleLoginSuccess}
onFailure={handleLoginFailure}
cookiePolicy={'single_host_origin'}
/>
</div>
);
};
export default Login;
User
model to store Google OAuth tokens and profile information.By following these steps, you will successfully implement Google sign-in on your website.
Click here to create a Pull Request with the proposed solution
Files used for this task:
What - description of what you me to do Example: Hey @autopilot implement a Google sign-in on my website. Make changes to the front end and the back end of the application
Why - explain why this is important Example: I want to allow users to signup and login using their Google account