const express = require("express"); const passport = require("passport"); const TeamsnapStrategy = require("passport-teamsnap"); const {teamsnapCallback} = require('../lib/utils') // const {teamsnap} = require("../app"); // Configure the TeamSnap strategy for use by Passport. // // OAuth 2.0-based strategies require a `verify` function which receives the // credential (`accessToken`) for accessing the TeamSnap API on the user's // behalf, along with the user's profile. The function must invoke `cb` // with a user object, which will be set at `req.user` in route handlers after // authentication. passport.use( new TeamsnapStrategy( { apiVersion: "3", clientID: process.env["TEAMSNAP_CLIENT_ID"], clientSecret: process.env["TEAMSNAP_CLIENT_SECRET"], callbackURL: "/auth/teamsnap/callback", passReqToCallback: true, scope: ["read", "write"], proxy: true }, async function (req, accessToken, refreshToken, profile, done) { // json = JSON.parse(profile._raw); const new_profile = { access_token: accessToken, }; ['id', 'email', 'first_name', 'last_name', 'managed_team_ids'].forEach( k => { new_profile[k] = profile.data[0].get(k) }) req.session.teamsnap_access_token = accessToken; await initTeamsnap(accessToken) return done(null, new_profile); } ) ); // Configure Passport authenticated session persistence. // // In order to restore authentication state across HTTP requests, Passport needs // to serialize users into and deserialize users out of the session. In a // production-quality application, this would typically be as simple as // supplying the user ID when serializing, and querying the user record by ID // from the database when deserializing. However, due to the fact that this // example does not have a database, the complete Facebook profile is serialized // and deserialized. passport.serializeUser(function (user, cb) { process.nextTick(function () { console.log("L#56 serializing user id", user.id); cb(null, { id: user.id, username: user.email, email: user.email, first_name: user.first_name, last_name: user.last_name, accessToken: user.access_token, managed_team_ids: user.managed_team_ids }); }); }); passport.deserializeUser(function (user, cb) { process.nextTick(async function () { console.log("L#68 deserializing user id", user.id); try { await initTeamsnap(user.accessToken) return cb(null, user); } catch (err) { return cb(err) } }); }); var router = express.Router(); /* GET /login * * This route prompts the user to log in. * * The 'login' view renders an HTML page, which contain a button prompting the * user to sign in with TeamSnap. When the user clicks this button, a request * will be sent to the `GET /login/federated/teamsnap` route. */ router.get("/login", function (req, res, next) { // https://stackoverflow.com/a/73056806/20522015 returnTo = req.session.returnTo; if (req.user?.accessToken){ res.redirect(returnTo || "/"); } else { res.render("login", {layout:"layouts/main"}); } }); /* GET /login/federated/teamsnap * * This route redirects the user to TeamSnap, where they will authenticate. * * Signing in with TeamSnap is implemented using OAuth 2.0. This route initiates * an OAuth 2.0 flow by redirecting the user to TeamSnap's identity server. * Once there, TeamSnap will authenticate the user * and obtain their consent to release identity information to this app. * * Once TeamSnap has completed their interaction with the user, the user will be * redirected back to the app. */ router.get("/login/federated/teamsnap", passport.authenticate("teamsnap")); /* This route completes the authentication sequence when TeamSnap redirects the user back to the application. When a new user signs in, a user account is automatically created and their TeamSnap account is linked. When an existing user returns, they are signed in to their linked account. */ router.get( "/auth/teamsnap", passport.authenticate("teamsnap", function (err, user, info, status) {}) ); router.get( "/auth/teamsnap/callback", passport.authenticate("teamsnap", { successReturnToOrRedirect: "/", failureRedirect: "/login", keepSessionInfo: true, }) ); const initTeamsnap = async (accessToken) => { await teamsnap.auth(accessToken); await teamsnap.loadCollections(teamsnapCallback); await teamsnap.enablePersistence(); } const ensureLoggedIn = (req, res, next) => { if (!req.isAuthenticated()){ req.session.returnTo = req.originalUrl res.redirect("/login"); // return next(); } else { req.user = req.session.passport.user next(); } } router.get('/auth/teamsnap/session_storage', (req,res)=>{ res.status(200).json({"teamsnap.authToken":req.user?.accessToken}) } ) router.post('/logout', function(req, res, next){ req.logout(function(err) { if (err) { return next(err); } res.redirect('/'); }); }); module.exports = {router, ensureLoggedIn};