2

I've built a backend using Loopback with passport auth. It requires that I first visit http://localhost:3001/auth/github, which redirects to GitHub, which either displays a login page, or redirects back to my app on port 3001.

Now I'm building a ReactJS frontend on :3000. It's supposed to send AJAX calls to the backend appending the auth token as a query string parameter. I've added port forwarding to the client's package.json, so all AJAX calls are handled correctly.

What I can't figure is how to get the auth token (received as a cookie from http://localhost:3001/auth/github/callback) to the client side. While my AJAX calls are proxied correctly, when I navigate to /auth/github, I'm still on the React-generated page, and my :3001 endpoint isn't hit. If I go to :3001/auth/github, I'm not getting my auth_token cookie by my frontend code.

In other words, I have two problems: 1. How to navigate to my backend's auth page (http://localhost:3001/auth/github) from the frontend? 2. How to get the cookie obtained in #1 to my frontend so that it could be used in the subsequent queries?

As I'm building a demo, I only need a quick and dirty solution that Just Works, but I'm willing to consider other ideas like opening a popup window and/or an IFrame.

ulu
  • 5,872
  • 4
  • 42
  • 51
  • if anyone coming from google search to solve this issue, check this out https://stackoverflow.com/a/52620241/11000016 – U.A Feb 06 '20 at 01:52

2 Answers2

3

if you are using Passport then, you just need to read the strategy docs. I am assuming the authentication is done through Oauth

Example with express

Routes.js

api.route('/auth/github')
    .get(PassportCtrl.auth);

  api.route('/auth/github/callback')
    .get(PassportCtrl.authCallback, PassportCtrl.redirect);

PassportCtrl.js

import passport from 'passport';

const auth = passport.authenticate('github', {
  scope : ['profile', 'email']
});

const authCallback = passport.authenticate('github');

const redirect = (req, res) => {
    res.redirect('/whereveryouwant');
}

const getAuthUser = (req, res) => {
  res.json({
    user : req.user
  })
}

const logOut = (req, res) => {
  req.logOut();

  res.redirect('/');
}

export default {
  auth,
  authCallback,
  redirect,
  getAuthUser,
  logOut
}

passport init

// adding cookie feature
app.use(cookieSession({
  maxAge : 30 * 24 * 60 * 60 * 100,
  keys : [process.env.COOKIE_SECRET]
}));

// initializing passport
app.use(passport.initialize());
app.use(passport.session());

I forgot, you have to proxy

webpack.config.js

 devServer: {
    proxy: { // proxy URLs to backend development server
      '/auth/github': 'http://localhost:3001',
      '/api/**' : {
        'target' : 'http://localhost:3001'
      }
    },
    hot : true,
    contentBase: path.join(__dirname, "dist"),
    historyApiFallback : true,
    compress: true,
    port: 8080
  }

React

import React from 'react';
import {connect} from 'react-redux';
import {Link} from 'react-router-dom';


class Header extends React.Component {
  renderContent () {
    const {auth} = this.props;
    switch (auth) {
      case null : return;
      case false : return (
        <li><a href='/auth/google'>Login with google</a></li>
      )
      default: return ([
        <li key={'logout'}><a href='/api/logout'>Log out</a></li>
      ])
    }
  }
  render () {
    const {auth} = this.props;
    return (
      <nav>
        <div className='nav-wrapper'>
          <Link className="left brand-logo" to={auth ? '/whereveryouwant' : '/'}>
            Your page Name
          </Link>
          <ul className='right'>
            {this.renderContent()}
          </ul>
        </div>
      </nav>
    );
  }
}

const mapStateToProps = (state) => {
  return {
    auth : state.auth
  }
}

export default connect(mapStateToProps)(Header);
AngelSalazar
  • 3,080
  • 1
  • 16
  • 22
  • Thanks, but I think I have stated clearly that the backend code is done, I just need to use it properly from the React side. – ulu May 28 '18 at 15:09
  • @ulu I forgot some configuration you have to implement, I hope this helps – AngelSalazar May 28 '18 at 15:32
  • Thanks for adding the proxy setting, but I've already marked the other answer as correct, sorry! – ulu May 28 '18 at 16:43
2

Some suggestion to work on it:

  1. How to navigate to my backend's auth page (http://localhost:3001/auth/github) from the frontend?

Use Proxy on your React client (inside package.json) Example:

 {
  "name": "client",
  "version": "0.1.0",
  "private": true,
  "proxy": {
    "/auth/github": {
      "target": "http://localhost:3001"
    },
    "/api/*": {
      "target": "http://localhost:3001"
    }
  },
  "dependencies": {
    "axios": "^0.16.2",
    "materialize-css": "^0.99.0",
    "react": "^16.0.0-alpha.13",
    "react-dom": "^16.0.0-alpha.13",
    "react-redux": "^5.0.5",
    "react-router-dom": "^4.1.1",
    "react-scripts": "1.0.10",
    "react-stripe-checkout": "^2.4.0",
    "redux": "^3.7.1",
    "redux-form": "^7.0.1",
    "redux-thunk": "^2.2.0"
  },
}

So that when you access the api from your front you can refer it directly using '/auth/github'

  1. How to get the cookie obtained in #1 to my frontend so that it could be used in the subsequent queries?

I'm not sure about Loopback backend, but when I used Express, you can set using passport.session() from passport to get the session cookie

hope this helps.

Andree Wijaya
  • 425
  • 1
  • 5
  • 13
  • While my simple proxy setting didn't work, yours did. That's because a simple setting works for all requests that don't have an "Accept: text/html" header. If you add a complex setting with path matching, it works for all requests, so that you can browse pages served by your backend. Source: https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#configuring-the-proxy-manually – ulu May 28 '18 at 16:41