I'm using passport to authenticate users for my application using Facebook. In my application, I have 2 different users: customers and professionals (transitioning to "experts").
I followed the Loopback docs to implement the loopback-component-passport package and passport-facebook and have it working for my customers.
Because I use custom User models, I followed this SO Post on how to get that fixed (note: I still use the build-in AccessToken model).
I use an Angular frontend. To redirect the user back to my frontend, I created a bootscript that looks like this:
'use strict';
module.exports = function(app) {
var router = app.loopback.Router();
var cookieParser = require('cookie');
// Redirect user to page set in env.APP_HOST
router.get('/auth/customer/success', function(req, res, next) {
const cookie = req.headers.cookie;
var result = cookieParser.parse(cookie);
res.redirect(process.env.APP_HOST + '/auth/facebook/?token=' +
result['access_token'] + '&id=' + result['userId'] +
'&err=&fbsr=');
});
router.get('/auth/expert/success', function(req, res, next) {
const cookie = req.headers.cookie;
var result = cookieParser.parse(cookie);
res.redirect(process.env.APP_HOST + '/expert/auth/facebook/?token='
+ result['access_token'] + '&id=' + result['userId'] +
'&err=&fbsr=');
});
app.use(router);
};
When I authenticate as a customer, I should be redirected to https://example.com/auth/customer/success When I authenticate as a professional/expert, I should be redirected to https://example.com/auth/expert/success.
I have to load the configuration for both the customer and professional/expert which I'm doing in server.js. I created 2 providers.json files (providers.customer.json and provider.professional.json) containing their specific info.
This is how I load both configurations (perhaps a little messy):
var passportCustomer = require('loopback-component-passport');
var PassportConfiguratorCustomer = passportCustomer.PassportConfigurator;
var passportConfiguratorCustomer = new PassportConfiguratorCustomer(app);
var passportProfessional = require('loopback-component-passport');
var PassportConfiguratorProfessional = passportProfessional.PassportConfigurator;
var passportConfiguratorProfessional = new PassportConfiguratorProfessional(app);
// Setup passport configuration
var passportCustomerConfig = {};
var passportProfessionalConfig = {};
try {
passportCustomerConfig = require('./providers.customer.json');
passportProfessionalConfig = require('./providers.professional.json');
} catch(err) {
console.log('Please configure the passport strategy in providers.customer.json');
console.error(err);
process.exit(1); // Fatal error
}
// Init passport for customer
passportConfiguratorCustomer.init(false);
passportConfiguratorProfessional.init(false);
// Setup passport models
passportConfiguratorCustomer.setupModels({
userModel: app.models.Customer,
userIdentityModel: app.models.UserIdentityCustomer,
userCredentialModel: app.models.UserCredentialsCustomer
});
passportConfiguratorProfessional.setupModels({
userModel: app.models.Professional,
userIdentityModel: app.models.UserIdentityProfessional,
userCredentialModel: app.models.UserCredentialsProfessional
});
// Configure passport for customer
for(var s in passportCustomerConfig) {
var c = passportCustomerConfig[s];
c.session = c.session !== false;
passportConfiguratorCustomer.configureProvider(s, c);
}
// Configure passport for professional/expert
for(var s in passportProfessionalConfig) {
var c = passportProfessionalConfig[s];
c.session = c.session !== false;
// passportConfiguratorProfessional.configureProvider(s, c);
passportConfiguratorCustomer.configureProvider(s, c);
}
I have 2 different apps in Facebook (1 for customers, 1 for professionals/experts). When I authenticate using localhost:3000/auth/customer/facebook or localhost:3000/auth/expert/facebook I see that both apps are used for the correct endpoint. But no matter what endpoint I use, after authentication I'm always redirected to http://example.com/expert/auth/facebook
So my question is: How can I fix this issue so that customers are redirected to the customer endpoint and experts/professionals are redirected to their expert endpoint?
For reference: providers.customer.json
{
"facebook-login": {
"provider": "facebook",
"module": "passport-facebook",
"clientID": "OhOh, I removed it :)",
"clientSecret": "Supa Dupa secret",
"callbackURL": "/auth/customer/facebook/callback",
"authPath": "/auth/customer/facebook",
"callbackPath": "/auth/customer/facebook/callback",
"successRedirect": "/auth/customer/success",
"failureRedirect": "/auth/customer/failure",
"scope": ["email"],
"failureFlash": true,
"profileFields" : ["locale", "name", "email"]
},
"facebook-link": {
"provider": "facebook",
"module": "passport-facebook",
"clientID": "OhOh, I removed it :)",
"clientSecret": "Supa Dupa secret",
"callbackURL": "/link/customer/facebook/callback",
"authPath": "/link/customer/facebook",
"callbackPath": "/link/customer/facebook/callback",
"successRedirect": "/auth/customer/success",
"failureRedirect": "/auth/customer/failure",
"scope": ["email"],
"link": true,
"failureFlash": true
}
}
For reference: providers.professional.json
{
"facebook-login": {
"provider": "facebook",
"module": "passport-facebook",
"clientID": "Aaaaand",
"clientSecret": "It's gone",
"callbackURL": "/auth/expert/facebook/callback",
"authPath": "/auth/expert/facebook",
"callbackPath": "/auth/expert/facebook/callback",
"successRedirect": "/auth/expert/success",
"failureRedirect": "/auth/expert/failure",
"scope": ["email"],
"failureFlash": true,
"profileFields" : ["locale", "name", "email"]
},
"facebook-link": {
"provider": "facebook",
"module": "passport-facebook",
"clientID": "Aaaaand",
"clientSecret": "It's gone",
"callbackURL": "/link/expert/facebook/callback",
"authPath": "/link/expert/facebook",
"callbackPath": "/link/expert/facebook/callback",
"successRedirect": "/auth/expert/success",
"failureRedirect": "/auth/expert/failure",
"scope": ["email"],
"link": true,
"failureFlash": true
}
}
So I was able to fix this by using the PassPortConfigurator#configureProvider
method. Instead of using the JSON files to setup the facebook authentication, I did it in JS.
var passportCustomer = require('loopback-component-passport');
var PassportConfiguratorCustomer = passportCustomer.PassportConfigurator;
var passportConfiguratorCustomer = new PassportConfiguratorCustomer(app); // Note the first letter is not a capital one
// Init passport for customer
passportConfiguratorCustomer.init(false);
// Setup passport models
passportConfiguratorCustomer.setupModels({
userModel: app.models.Customer,
userIdentityModel: app.models.UserIdentityCustomer,
userCredentialModel: app.models.UserCredentialsCustomer
});
// Load configuration here instead of the JSON file.
passportConfiguratorProfessional.configureProvider('facebook-login-expert', {
module: 'passport-facebook',
clientID: XXX,
clientSecret: XXX,
callbackURL: '/auth/expert/facebook/callback',
authPath: '/auth/expert/facebook',
callbackPath: '/auth/expert/facebook/callback',
successRedirect: '/auth/expert/success',
failureRedirect: '/auth/expert/failure',
scope: ['email'],
failureFlash: true,
profileFields: ['locale', 'name', 'email']
});