Skip to content

Commit

Permalink
Parameterize all the possible return paths
Browse files Browse the repository at this point in the history
  • Loading branch information
OtterleyW committed Oct 9, 2020
1 parent edf4cda commit b44f218
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 16 deletions.
23 changes: 20 additions & 3 deletions server/api/auth/facebook.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,20 @@ const strategyOptions = {

const verifyCallback = (req, accessToken, refreshToken, profile, done) => {
const { email, first_name, last_name } = profile._json;
const state = req.query.state;
const queryParams = JSON.parse(state);

const { from, defaultReturn, defaultConfirm } = queryParams;

const userData = {
email,
firstName: first_name,
lastName: last_name,
accessToken,
refreshToken,
returnUrl: req.query.state ? req.query.state : null,
from,
defaultReturn,
defaultConfirm,
};

done(null, userData);
Expand All @@ -48,8 +54,19 @@ if (clientID) {
}

exports.authenticateFacebook = (req, res, next) => {
const from = req && req.query ? req.query.from : null;
passport.authenticate('facebook', { scope: ['email'], state: from })(req, res, next);
const from = req.query.from ? req.query.from : null;
const defaultReturn = req.query.defaultReturn ? req.query.defaultReturn : null;
const defaultConfirm = req.query.defaultConfirm ? req.query.defaultConfirm : null;

const params = {
...(!!from && { from }),
...(!!defaultReturn && { defaultReturn }),
...(!!defaultConfirm && { defaultConfirm }),
};

const paramsAsString = JSON.stringify(params);

passport.authenticate('facebook', { scope: ['email'], state: paramsAsString })(req, res, next);
};

// Use custom callback for calling loginWithIdp enpoint
Expand Down
18 changes: 10 additions & 8 deletions server/api/auth/loginWithIdp.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ module.exports = (err, user, req, res, clientID, idpId) => {

// Save error details to cookie so that we can show
// relevant information in the frontend
res
return res
.cookie(
'st-autherror',
{
Expand All @@ -45,7 +45,7 @@ module.exports = (err, user, req, res, clientID, idpId) => {

// Save error details to cookie so that we can show
// relevant information in the frontend
res
return res
.cookie(
'st-autherror',
{
Expand All @@ -60,6 +60,8 @@ module.exports = (err, user, req, res, clientID, idpId) => {
.redirect(`${rootUrl}/login#`);
}

const { from, defaultReturn, defaultConfirm } = user;

const tokenStore = sharetribeSdk.tokenStore.expressCookieStore({
clientId: CLIENT_ID,
req,
Expand All @@ -78,7 +80,7 @@ module.exports = (err, user, req, res, clientID, idpId) => {
...baseUrl,
});

sdk
return sdk
.loginWithIdp({
idpId: 'facebook',
idpClientId: clientID,
Expand All @@ -90,10 +92,10 @@ module.exports = (err, user, req, res, clientID, idpId) => {
// We need to add # to the end of the URL because otherwise Facebook
// login will add their defaul #_#_ which breaks the routing in frontend.

if (user.returnUrl) {
res.redirect(`${rootUrl}${user.returnUrl}#`);
if (from) {
res.redirect(`${rootUrl}${from}#`);
} else {
res.redirect(`${rootUrl}/#`);
res.redirect(`${rootUrl}${defaultReturn}#`);
}
}
})
Expand All @@ -112,13 +114,13 @@ module.exports = (err, user, req, res, clientID, idpId) => {
lastName: user.lastName,
idpToken: `${user.accessToken}`,
idpId,
from: user.returnUrl,
from,
},
{
maxAge: 15 * 60 * 1000, // 15 minutes
}
);

res.redirect(`${rootUrl}/confirm#`);
res.redirect(`${rootUrl}${defaultConfirm}#`);
});
};
21 changes: 16 additions & 5 deletions src/containers/AuthenticationPage/AuthenticationPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { compose } from 'redux';
import { connect } from 'react-redux';
import { withRouter, Redirect } from 'react-router-dom';
import Cookies from 'js-cookie';
import routeConfiguration from '../../routeConfiguration';
import { pathByRouteName } from '../../util/routes';
import { apiBaseUrl } from '../../util/api';
import { FormattedMessage, injectIntl, intlShape } from '../../util/reactIntl';
import classNames from 'classnames';
Expand Down Expand Up @@ -192,13 +194,22 @@ export class AuthenticationPageComponent extends Component {
};

const authWithFacebook = () => {
const routes = routeConfiguration();
const baseUrl = apiBaseUrl();

if (from) {
window.location.href = `${baseUrl}/api/auth/facebook?from=${from}`;
} else {
window.location.href = `${baseUrl}/api/auth/facebook`;
}
// Route where the user should be returned after authentication
// This is used e.g. with EditListingPage and ListingPage
const fromParam = from ? `from=${from}` : '';

// Default route where user is returned after successfull authentication
const defaultReturn = pathByRouteName('LandingPage', routes);
const defaultReturnParam = defaultReturn ? `&defaultReturn=${defaultReturn}` : '';

// Route for confirming user data before creating a new user
const defaultConfirm = pathByRouteName('ConfirmPage', routes);
const defaultConfirmParam = defaultConfirm ? `&defaultConfirm=${defaultConfirm}` : '';

window.location.href = `${baseUrl}/api/auth/facebook?${fromParam}${defaultReturnParam}${defaultConfirmParam}`;
};

const idp = this.state.authInfo
Expand Down
4 changes: 4 additions & 0 deletions src/routeConfiguration.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ const routeConfiguration = () => {
authPage: 'LoginPage',
component: props => <ProfileSettingsPage {...props} />,
},

// Note: authenticating with IdP (e.g. Facebook) expects that /login path exists
// so that in the error case users can be redirected back to the LoginPage
// In case you change this, remember to update the route in server/api/auth/loginWithIdp.js
{
path: '/login',
name: 'LoginPage',
Expand Down

0 comments on commit b44f218

Please sign in to comment.