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).
Angular Frontend
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.
Setup a second passport-facebook
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); }
The actual problem
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?
Additional information
- Registration works fine, I can find customers in customer table and expert in expert table in my database
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 } }
Advertisement
Answer
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'] });