Oauth2 Google Authentication flow - Next.JS / Express

情到浓时终转凉″ 提交于 2021-02-08 05:41:19

问题


I am using a React/Next.Js Frontend and am trying to implement authentication with the Oauth2 strategy with Google.

I am very confused by the process.

Currently on the client, I have a Google sign in component that has a Client ID with in it and can retrieve an access token.

      <GoogleLogin
            clientId="myclientid"
            buttonText="Login"
            onSuccess={userLogin}
            onFailure={userLogin}
            cookiePolicy={'single_host_origin'}
  />

I then have a function, which on success sends a post message to my backend with an access token, such as this:

export function googleAuthenticate(accessToken : string) : any{
    axios({
        method: 'post',
        url: "http://localhost:4000/auth/google",
        data: {
          accessToken: accessToken
        }
      })
    .then(res => {
        console.log(res);
    })
    .catch(err => {
        console.log("Failure!");
        console.log(err);
    })
};

On the backend I am using passport, and the routes look like this:

import express from 'express';
import passport from 'passport';
import Logger from '../logger/index';

const router = express.Router();

export function isAuthenticated(req:express.Request, res:express.Response, next : any) {
    return req.isAuthenticated() ?
        next() :
        res.sendStatus(401);
 }  

  router.get('/fail', (_req:express.Request, res:express.Response) => {
    res.json({ loginFailed: true });
  });

  router.post('/google', passport.authenticate('google', { scope: ['profile']}), (_req:express.Request, _res:express.Response) => {
    Logger.info("GET Request at Google Authentication endpoint received.");
  });

  router.get(
    '/google/callback',
    passport.authenticate('google', { failureRedirect: '/login' }),
    (_req:express.Request, res:express.Response) => {
      res.redirect('/graphql');
    }
  );

export default router;

My passport module looks like this:

module.exports = function(passport : any, GoogleStrategy : any){
  passport.use(new GoogleStrategy({
    clientID: config.google.client_id,
    clientSecret: config.google.client_secret,
    callbackURL: config.google.redirect_url
  },
  function(accessToken : string, profile : Profile, refreshToken : string, cb : any) {
    return cb(null, {
      id: profile.googleId,
      username: profile.email,
      image: profile.imageUrl,
      firstName: profile.givenName,
      surname: profile.familyName,
      accessToken: accessToken,
      refreshToken: refreshToken
    })
  }
  ));
}

Since Next.js is a server side rendered, I am not able to use save a token. I understand I have to use a cookie. But how does this work? I cannot redirect the client browser from the express backend.

Currently I'm just seeing these 2 errors:

OPTIONS https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A4000%2localhost:3000%2Fdashboard&scope=profile&client_id=687602672235-l0uocpfchbjp34j1jjlv8tqv7jadb8og.apps.googleusercontent.com 405

Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A4000%2Fbackoffice.dev.myos.co%2Fdashboard&scope=profile&client_id=687602672235-l0uocpfchbjp34j1jjlv8tqv7jadb8og.apps.googleusercontent.com' (redirected from 'http://localhost:4000/auth/google') from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

回答1:


Firstly i think google auth will not work on localhost.
If i understand correctly in your serverside logic you can easily save your token as a cookie and then read them in the client.

Not sure with passport, but you can do something similar to this :
(my app is working with an implementation of this code)

frontend :

  <GoogleLogin
        clientId="myclientid"
        buttonText="Login"
        onSuccess={userLogin}
        onFailure={userLogin}
        cookiePolicy={'single_host_origin'}
/>

userLogin:

  async userLogin(response){
     var url = '/google-login/'+response.tokenObj.id_token
     fetch(url).then(/* i will handle response*/)
  }

Then in the backend you can use google-auth-library to login or register.
server.js:

const {OAuth2Client} = require('google-auth-library');
const GOOGLEID = "mygoogleid.apps.googleusercontent.com"
const client = new OAuth2Client(GOOGLEID);
var cookieParser = require('cookie-parser')

async function verify(userToken) {
    const ticket = await client.verifyIdToken({
    idToken: userToken,
    audience: "clientid.apps.googleusercontent.com",  // Specify the CLIENT_ID of the app that accesses the backend
   // Or, if multiple clients access the backend:
   //[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
  });
  const payload = ticket.getPayload();
  const userid = payload['sub'];
  return payload
  // If request specified a G Suite domain:
  //const domain = payload['hd'];
}

In server.js a route similar to this :

   server.get('/google-login/:token',(req,res) => {
    const userToken =  req.params.token
    var  result =  verify(userToken).then(function(result){
      var userName = result.given_name
      var userSurname = result.family_name
      var userEmail = result.email
      /*
        Now user is authenticated i can send to the frontend
        user info or user token o save the token to session
      */
    }).catch(function(err){
      // error handling
    })
  })


来源:https://stackoverflow.com/questions/57972116/oauth2-google-authentication-flow-next-js-express

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!