Reputation: 1774
If you have an example of code from any of your projects for nextjs using passport google oauth2, please share. There are some examples online for this using just nodejs but the mechanism of routes, middleware and callback is different with nextjs and I have not found a working example.
I have the following code but get a CORS error. I have seen youtube videos with google auth demos on localhost. The credentials I created also use localhost.
\lib\Passport.js
import passport from 'passport';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
passport.serializeUser((user, done) => {
done(null, user._id);
});
passport.deserializeUser((req, id, done) => {
req.db
.collection('users')
.findOne({ _id: id })
.then((user) => done(null, user));
});
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT,
clientSecret: process.env.GOOGLE_SECRET,
callbackURL: process.env.WEB_URI+"/users/callback/google",
passReqToCallback: true,
},
function(accessToken, refreshToken, profile, cb) {
// User.findOrCreate({ googleId: profile.id }, function (err, user) {
// return cb(err, user);
// });
console.log("profile below")
console.log(profile)
}
));
export default passport;
\pages\login.js with button - "Login using Google"
<Button
variant="outlined"
color="secondary"
startIcon={">"}
onClick={(event) => {
googleLogin(event) }}
>
Login using Google
</Button>
and the function in \pages\login.js
async function googleLogin(e) {
const res = await fetch('/api/authGoogle', {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
})
console.log(res);
return;
}
And the \pages\api\authGoogle.js
import nextConnect from 'next-connect';
import middleware from '../../middlewares/middleware';
import passport from '../../lib/passport';
const handler = nextConnect();
handler.use(middleware);
handler.get(passport.authenticate("google", {
scope: ['profile', 'email', 'openid'],
}))
handler.delete((req, res) => {
req.logOut();
res.status(204).end();
});
export default handler;
What I do not have is code for users/callback/google
and I am not sure what to write in it. The official passportjs example used just nodejs and hard to follow so any sample using next js will help me and others in future.
Upvotes: 11
Views: 8829
Reputation: 320
When I was attempting to use res.writeHead
, for some reason next-connect was hanging and the request would never resolve. I simply replaced it with the following code, and everything worked as expected:
res.status(302)
res.setHeader('Location', '/')
res.end()
Maybe this will help someone else!
Upvotes: 3
Reputation: 1
First off I do apologize for the "answer" but I am new to stack overflow and have no permissions to comment on your original question because apparently I lack reputation (silly imho) Anyways, I also am researching integration with Next.js, next-connect with Passport.js and I have also came to the conclusion that you can not use a fetch()
or even axios request for that matter to hit the api endpoint and initiate passport.
Apparently you have to send your users directly on top of the endpoint (/api/login
) and then when the user gets redirected back, hit another api endpoint (like /api/login/return
) and then you are able to successfully grab the profile from the third party site.
I also receieved CORS issues when trying to do a fetch on the endpoint. I tried using the cors() npm library within next-connect as well as manually inserting the headers like so:
export default nextConnect()
.use((req, res, next) => {
req.headers["Access-Control-Allow-Origin"] = "*";
req.headers["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS, PUT, PATCH, DELETE";
req.headers["Access-Control-Allow-Headers"] = "x-access-token, Origin, X-Requested-With, Content-Type, Accept";
next();
})
.use(passport.initialize())
.use(passport.authenticate('google', { session: false }))
I know this is unsafe but was just trying last resort options to get it to work. Do you know if it is "bad" to have the users hit the /api/ endpoints directly to get this to work? Really trying to figure this out and any response appreciated.
Upvotes: 0
Reputation: 1774
After a lot of time struggling, I figured bits and pieces myself.
Step 1 For Oauth, we have to link to the provider using a button/link directly. WE cannot use a fetch api call that goes to api first.
Will not work
await fetch('/api/authGoogle
Will work
href="/api/authGoogle
Step 2
In api/authGoogle the passport.authenticate needs to be called.
handler.get(passport.authenticate("google", {scope: ['profile', 'email']}));
Step 3
In passport.js or wherever you have all the strategies
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT,
clientSecret: process.env.GOOGLE_SECRET,
callbackURL: process.env.WEB_URI+"/api/auth/callback/google",
passReqToCallback: true,
},
async (req, accessToken, refreshToken, profile, done) => {
console.log(profile)
// add code here to check if user exists in database or create a new one
The way it works is /api/auth/callback/google gets passed a code (code=...) that you see in the browser url. The details are then passed from callback and available for console.log(profile)
above.
Step 4
Callback file /api/auth/callback/google
should look like this. I am just redirecting to home but you can set a browser cookie in this file. Install 'cookies' which is a very popular library if you want to do that.
handler.get(passport.authenticate("google"), (req, res) => {
res.writeHead(302, {
'Location': '/'
});
res.end();
})
Here passport.authenticate is repeated again but it was in step 2. Thats because the code needs to be used to get the profile information using the above line.
Upvotes: 7
Reputation: 1634
You can look at Auth0 example online or Vercel example
You can use this Next.js solution
Edit: don't forget to handle cors and work locally in the correct way
Upvotes: 0