Passport Sendoso OAuth 2.0 Strategy
This package provides a Passport authentication strategy specifically designed for integrating with Sendoso using the OAuth 2.0 protocol. It enables Node.js applications, particularly those leveraging Connect-style middleware such as Express, to authenticate users via their Sendoso accounts. The current stable version is 1.0.2, indicating a specific, potentially specialized or modified, integration rather than a general-purpose, high-cadence library. Its key differentiator is its direct focus on Sendoso's unique authentication flow, offering a structured way to connect Passport.js applications to Sendoso for user identity verification. Developers must provide a `clientID`, `clientSecret`, and `callbackURL` to configure the strategy, and a `verify` callback to handle user data after successful authentication. This package simplifies the OAuth 2.0 handshake for Sendoso, allowing Passport's robust session management and user serialization features to be applied.
Common errors
-
Error: Unknown authentication strategy "sendoso"
cause The Passport strategy has not been correctly registered with `passport.use()` before attempting to use it.fixEnsure `passport.use(new SendosoStrategy(...))` is called and the strategy name matches what is used in `passport.authenticate('sendoso', ...)`. -
OAuth2Strategy requires a clientID option
cause The `clientID` option was not provided or was an empty string in the `SendosoStrategy` configuration.fixProvide a valid `clientID` string obtained from your Sendoso application registration to the `SendosoStrategy` options. -
Error: Failed to obtain access token
cause Commonly caused by an incorrect `clientSecret`, an invalid `callbackURL` (which must exactly match the one registered with Sendoso), or network issues.fixDouble-check your `clientSecret` and ensure your `callbackURL` in the strategy configuration precisely matches the one registered in your Sendoso application settings. -
TypeError: Cannot read properties of undefined (reading 'authenticate')
cause The Passport middleware (`passport.initialize()` and `passport.session()`) has not been applied to the Express app, or Passport itself hasn't been imported.fixMake sure you have `app.use(passport.initialize());` and `app.use(passport.session());` configured in your Express application middleware chain after session middleware.
Warnings
- gotcha The provided README example for the initial authentication route uses `passport.authenticate('google', ...)` instead of `passport.authenticate('sendoso', ...)`. This is a copy-paste error and should be corrected to `'sendoso'` to use the configured strategy.
- gotcha The package name `passport-sendoso-postilize` (with unusual capitalization and the 'postilize' suffix) suggests it might be a specific internal or highly customized version, not a generic, community-maintained 'passport-sendoso' package. This could lead to confusion or specific integration quirks.
- gotcha The documentation uses CommonJS `require()` syntax exclusively. While Node.js can often handle mixed modules, explicit ESM (`import`) support or examples are absent, implying it might be primarily tested/designed for CJS environments or require manual configuration for ESM.
- gotcha The example authentication scopes `contacts content` are typical for Google OAuth and are unlikely to be valid for Sendoso's OAuth implementation. Actual Sendoso scopes must be used.
Install
-
npm install passport-sendoso-postilize -
yarn add passport-sendoso-postilize -
pnpm add passport-sendoso-postilize
Imports
- Strategy
import SendosoStrategy from 'passport-sendoso-postilize';
import { Strategy as SendosoStrategy } from 'passport-sendoso-postilize'; - passport
import * as passport from 'passport';
import passport from 'passport';
Quickstart
const express = require('express');
const passport = require('passport');
const session = require('express-session'); // Required for Passport sessions
const { Strategy: SendosoStrategy } = require('passport-sendoso-postilize'); // Using destructuring for clarity
const app = express();
// Passport configuration
passport.use(new SendosoStrategy({
clientID: process.env.SENDOSO_CLIENT_ID ?? 'YOUR_SENDOSO_CLIENT_ID',
clientSecret: process.env.SENDOSO_CLIENT_SECRET ?? 'YOUR_SENDOSO_CLIENT_SECRET',
callbackURL: "http://localhost:3000/auth/sendoso/callback",
passReqToCallback: true
},
function(request, accessToken, refreshToken, profile, done) {
// In a real application, you would typically find or create a user in your database
// based on the profile information returned by Sendoso.
// The 'profile' object would contain user details provided by Sendoso.
// For demonstration, we'll return a placeholder user.
const user = { id: profile?.id || 'sendoso_user_123', name: profile?.displayName || 'Sendoso User' };
console.log('Sendoso Profile:', profile);
console.log('Access Token:', accessToken);
done(null, user); // Call done with null for error and the user object
}
));
// Passport session setup.
// To support persistent login sessions, Passport needs to be able to
// serialize users into and deserialize users out of the session.
// Typically, this will be as simple as storing the user ID when serializing
// and finding the user by ID when deserializing.
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
// In a real application, retrieve user from database by ID
const user = { id: id, name: 'Deserialized User' }; // Placeholder
done(null, user);
});
// Middleware for Express
app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
app.use(passport.initialize());
app.use(passport.session());
// Define authentication routes
app.get('/auth/sendoso',
passport.authenticate('sendoso', { scope: 'profile email' } // Replace 'profile email' with actual Sendoso scopes if available
));
app.get('/auth/sendoso/callback',
passport.authenticate('sendoso', {
successRedirect: '/profile', // Redirect to a profile page on success
failureRedirect: '/login' // Redirect to login on failure
})
);
app.get('/profile', (req, res) => {
if (req.isAuthenticated()) {
res.send(`<h1>Welcome, ${req.user.name || 'authenticated user'}!</h1><pre>${JSON.stringify(req.user, null, 2)}</pre><p><a href="/logout">Logout</a></p>`);
} else {
res.redirect('/login');
}
});
app.get('/login', (req, res) => {
res.send('<h1>Login with Sendoso</h1><p><a href="/auth/sendoso">Login with Sendoso</a></p>');
});
app.get('/logout', (req, res, next) => {
req.logout((err) => {
if (err) { return next(err); }
res.redirect('/login');
});
});
const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
console.log('Visit http://localhost:3000/login to start the authentication flow.');
});