3

SO Community,

I am working on using Passport's Google-OAuth2 strategy with a React front-end. Currently, I am able to get to the Google Login page front the back-end API call via Postman. However, if I make the call from the front-end using React, React treats the request as an unknown path and throws up our local 404 page.

Here is my code, presently (I've tried several different things to resolve the issue):

React Component

import React, { Component } from 'react';

// MaterialUI Components
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
// React APIs 
import API from "../utils/API";

const styles = {
    button: {
        marginTop: "1rem"
    }
}

export default class LoginForm extends Component {

    state = {
        email: "",
        password: ""
    };

    handleInputChange = event => {
        const { name, value } = event.target;

        this.setState({
            [name]: value
        });
    };

    handleSubmitForm = () => {
        let newLogin = {
            email : this.state.email,
            password : this.state.password
        }
        API.login(newLogin).then(res => console.log(res)).catch(err => console.log(err));
    };

    handleGoogleLogin = () => {
        fetch("/api/auth/google", {mode: 'no-cors'})
        .then(response => {
            console.log(response)
        })
        .catch(err => {
            console.log(err);
        });
    }

    render() {
        return (
            <div>
            <form noValidate autoComplete="off">
                <div>
                <TextField
                    id="email"
                    label="Email"
                    name="email"
                    value={this.state.email}
                    onChange={this.handleInputChange}
                    margin="normal"
                />
                </div>
                <div>
                <TextField
                    id="password"
                    label="Password"
                    type="password"
                    name="password"
                    onChange={this.handleInputChange}
                    margin="normal"
                    />
                </div>
                <Button
                    onClick={this.handleSubmitForm}
                    style={styles.button}
                    variant="outlined"
                    size="small">Login</Button>
                <Button
                    onClick={this.handleGoogleLogin}
                    style={styles.button}
                    variant="outlined"
                    size="small">Google Login</Button>
            </form>
            <div>
                <a type="button" className="MuiButtonBase-root MuiButton-root MuiButton-outlined MuiButton-sizeSmall" href="/api/auth/google">Google A Tag</a>
            </div>
            </div>
        )
    }
}

I have two different buttons for testing purposes:

  1. The <a> "button" will redirect to our React 404 page.
  2. The button which called the handleGoogleLogin function will hang. The "Network" tab in Google's DevTools shows a "pending" message from Google.

API Route

    // Redirect to Google authentication.
    app.get('/api/auth/google', function(){
        console.log("google api")
    }, passport.authenticate('google', { scope: ['profile', "email"] }));

    // After authentication, redirect back to home page.
    app.get('/api/auth/google/callback', passport.authenticate('google', { successRedirect: "/", failureRedirect: '/404', session: false }), function(req, res) {
        // var token = req.user.token
        // res.redirect('/');
        res.redirect("http://localhost:3000?token=" + token);
        // console.log("google callback")
    });

Passport.js

const JwtStrategy = require('passport-jwt').Strategy;
const ExtractJwt = require('passport-jwt').ExtractJwt;
const GoogleStrategy = require('passport-google-oauth').OAuth2Strategy;
const db = require('../models');
const keys = require('../config/keys');

const opts = {};
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = keys.secretOrKey;

module.exports = (passport) => {

    passport.serializeUser(function(user, done) {
        done(null, user);
       });
    passport.deserializeUser(function(user, done) {
        done(null, user);
       });

    passport.use(
        new JwtStrategy(opts, (jwtPayload, done) => {
            db.Users
                .findOne({
                    where: {
                        id: jwtPayload.id
                    }
                })
                .then((user) => {
                    if (user) {
                        return done(null, user);
                    }
                    return done(null, false);
                })
                .catch((err) => console.log(err));
        })
    );

    passport.use(
        new GoogleStrategy({
            clientID: keys.googleClientID,
            clientSecret: keys.googleClientSecret,
            callbackURL: "http://localhost:3001/api/auth/google/callback"
        },
        function(accessToken, refreshToken, profile, done) {
            db.Users.findOrCreate({ googleId: profile.id }, function (err, user) {
                return done(err, user);
            });
        }
    ));
};

Please let me know if I can provide any additional information.

Many thanks!

1 Answers1

1

In case of my project, the issue was resolved, when I gave the complete URL to the node google-auth endpoint : http://localhost:3550/auth/google, in my anchor tag.

Are you doing the same already ?

I have setup my google-oauth2 login as below.

Passport Strategy setup as follows:

/**
 * Route handlers for Google oauth2 authentication. 
 * The first handler initiates the authentication flow. 
 * The second handler receives the response from Google. In case of failure, we will 
 * redirect to a pre-determined configurable route. In case of success, we issue a Json 
 * Web Token, and redirect to a pre-determined, configurable route.
 */

 this.router.get('/google', (req: Request, res: Response, next: NextFunction) => {
      passport.authenticate('google', {
          scope: process.env.GOOGLE_OAUTH2_SCOPES.split(",")
      })(req, res, next);
 });

 this.router.get('/google/callback',
      passport.authenticate('google', { failureRedirect:process.env.AUTH_FAILURE_REDIRECT }), (req, res) => this.jwtAuthService.issueJWTEnhanced(req, res, 'google'));

issueJwtEnhanced is defined as follows:

/**
 * Middleware for issuing JWT as part of the authentication flow. 
 * @param req Express HttpRequest Object
 * @param res Express HttpResponse Object
 */
 issueJWTEnhanced(req: any, res: Response, loginMech: string ) {
        this.logger.info('Inside JWT issuing service');
        this.logger.info('UserID: ' + req.user._id);
        jwt.sign({userId: req.user._id, loginMethod: loginMech}, process.env.JWT_SECRET, {expiresIn: '5 min'}, (err, token) => {
            if(err){
                this.logger.error('Error while trying to issue JWT: ' + err);
                this.logger.error(JSON.stringify(err));
                return res.redirect(process.env.AUTH_FAILURE_REDIRECT);
            }else{
                this.logger.info('Successfully issued JWT');
                this.logger.info('JWT Issued: ' + token);
                return res.redirect(process.env.AUTH_SUCCESS_REDIRECT + '/' + token);
            }
        }); 
    }

Where,

AUTH_SUCCESS_REDIRECT='http://localhost:4200/login-success' AUTH_FAILURE_REDIRECT='http://localhost:4200/login/'

vasu014
  • 187
  • 1
  • 3
  • 12
  • https://stackoverflow.com/questions/56653139/redirect-to-frontend-on-a-different-url-after-oauth2-login/58800412#58800412 This is my setup currently, hope it helps – vasu014 Nov 11 '19 at 11:30