npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

passport-ubcshib

v0.1.6

Published

Passport.js strategy for UBC Shibboleth SAML 2.0 authentication

Readme

@ubcshib/passport-ubcshib

A Passport.js strategy for integrating UBC's Shibboleth SAML 2.0 Identity Provider with Node.js applications. An extension of the passport-saml library, with thanks to University of Washington for publishing theirs from which we could work: https://www.passportjs.org/packages/passport-uwshib/

Features

  • SAML 2.0 Support: Full SAML 2.0 authentication with UBC's Shibboleth IdP
  • Multi-Environment: Automatic configuration for LOCAL (SimpleSAMLphp), STAGING, and PRODUCTION environments
  • Local Development: Test with docker-simple-saml before deploying to staging/production
  • Flexible Attributes: Per-application attribute selection with OID-to-friendly-name mapping
  • Secure: Supports SAML request signing and response validation
  • Single Logout (SLO): Optional support for single logout at the IdP
  • Certificate Management: Automatic fetching of IdP certificates from metadata
  • Environment-Based Configuration: Support for both environment variables and runtime configuration

Installation

npm install passport-ubcshib passport

Quick Start

1. Configure Passport

const passport = require('passport');
const { Strategy } = require('passport-ubcshib');
const fs = require('fs');

passport.use(
	new Strategy(
		{
			// Service Provider Identity (usually your app's URL)
			issuer: 'https://myapp.example.com/shibboleth',

			// Callback URL after authentication
			callbackUrl: 'https://myapp.example.com/auth/ubcshib/callback',

			// Path to your application's private key for signing SAML requests
			privateKeyPath: process.env.SAML_PRIVATE_KEY_PATH,

			// Specify which attributes your app needs
			// See ATTRIBUTES.md for full list of available attributes
			attributeConfig: ['ubcEduCwlPuid', 'mail', 'eduPersonAffiliation'],

			// Optional: Enable single logout
			enableSLO: true,
		},
		// Verify callback: called with user profile after successful authentication
		(profile, done) => {
			// profile.nameID - SAML nameID
			// profile.attributes - Mapped attributes based on attributeConfig

			User.findOrCreate(
				{ ubcId: profile.attributes.ubcEduCwlPuid },
				(err, user) => {
					return done(err, user);
				}
			);
		}
	)
);

// Serialize and deserialize user for session management
passport.serializeUser((user, done) => {
	done(null, user.id);
});

passport.deserializeUser((id, done) => {
	User.findById(id, (err, user) => {
		done(err, user);
	});
});

2. Set Up Routes

const express = require('express');
const passport = require('passport');
const { ensureAuthenticated, logout } = require('passport-ubcshib');

const app = express();

// Login route - redirects to UBC IdP
app.get('/auth/ubcshib', passport.authenticate('ubcshib'));

// Callback route - called by UBC IdP after authentication
app.post(
	'/auth/ubcshib/callback',
	passport.authenticate('ubcshib', { failureRedirect: '/login' }),
	(req, res) => {
		// Successful authentication
		res.redirect('/dashboard');
	}
);

// Protected route
app.get('/dashboard', ensureAuthenticated(), (req, res) => {
	res.send(`Welcome, ${req.user.name}`);
});

// Logout
app.get('/logout', logout('/'));

3. Configure Environment

Create a .env file:

# SAML Configuration
SAML_ENVIRONMENT=STAGING  # or PRODUCTION
SAML_PRIVATE_KEY_PATH=/path/to/your/private.key
SAML_ISSUER=https://myapp.example.com/shibboleth
SAML_CALLBACK_URL=https://myapp.example.com/auth/ubcshib/callback

# Attributes your app needs
# (optional - can also configure in code)

Configuration Options

Required Options

| Option | Type | Description | | ------------- | ------ | ----------------------------------------------------------------------------------------- | | issuer | string | Your Service Provider's entity ID (usually your app's base URL + /shibboleth) | | callbackUrl | string | URL where the IdP redirects after authentication (must match registered URL with UBC IAM) |

Optional Options

| Option | Type | Default | Description | | ---------------------- | ------- | ------------------------------------- | --------------------------------------------------------------- | | privateKeyPath | string | null | Path to your app's private key for signing SAML requests | | attributeConfig | Array | [] | List of attribute names to request from IdP (see ATTRIBUTES.md) | | entryPoint | string | Staging or Production SSO endpoint | Identity Provider's SSO endpoint | | logoutUrl | string | Staging or Production logout endpoint | Identity Provider's logout endpoint | | enableSLO | boolean | true | Enable single logout (SLO) on user logout | | validateInResponseTo | boolean | true | Validate response InResponseTo against request ID | | acceptedClockSkewMs | number | 0 | Allowed clock skew in milliseconds between servers | | signatureAlgorithm | string | 'sha256' | SAML signature algorithm (sha256, sha512, etc.) |

Environment Variables

The following environment variables can be used to configure the strategy:

# Environment selection
SAML_ENVIRONMENT=STAGING  # STAGING or PRODUCTION

# For custom IdP configuration
SAML_ENTRY_POINT=https://authentication.ubc.ca/idp/profile/SAML2/Redirect/SSO
SAML_LOGOUT_URL=https://authentication.ubc.ca/idp/profile/Logout
SAML_METADATA_URL=https://authentication.ubc.ca/idp/shibboleth

# Private key location
SAML_PRIVATE_KEY_PATH=/etc/app/saml/private.key

# Service Provider config
SAML_ISSUER=https://myapp.example.com/shibboleth
SAML_CALLBACK_URL=https://myapp.example.com/auth/ubcshib/callback

# Enable/disable features
ENABLE_SLO=true

Environments

Staging

  • Entry Point: https://authentication.stg.id.ubc.ca/idp/profile/SAML2/Redirect/SSO
  • Logout URL: https://authentication.stg.id.ubc.ca/idp/profile/Logout
  • Metadata: https://authentication.stg.id.ubc.ca/idp/shibboleth

Production

  • Entry Point: https://authentication.ubc.ca/idp/profile/SAML2/Redirect/SSO
  • Logout URL: https://authentication.ubc.ca/idp/profile/Logout
  • Metadata: https://authentication.ubc.ca/idp/shibboleth

Set the environment via:

SAML_ENVIRONMENT=PRODUCTION node app.js

Attribute Mapping

The strategy automatically maps SAML OID attribute names to friendly names. See ATTRIBUTES.md for the complete reference.

Common attributes:

  • ubcEduCwlPuid - UBC Computing User ID
  • mail - Email address
  • eduPersonAffiliation - Affiliation (student, faculty, staff, etc.)

Adding New Attributes

Need to add support for a new attribute? See ADDING_ATTRIBUTES.md for a step-by-step guide on how to add new OID mappings to the library.

After successful authentication, mapped attributes are available as:

req.user.attributes = {
	ubcEduCwlPuid: '12345678',
	mail: '[email protected]',
	eduPersonAffiliation: ['student', 'member'],
};

Helper Middleware

ensureAuthenticated(options)

Middleware to protect routes. Redirects unauthenticated users to login.

const { ensureAuthenticated } = require('@ubcshib/passport-ubcshib');

app.get('/protected', ensureAuthenticated(), (req, res) => {
	res.send('Only authenticated users see this');
});

// Custom login URL
app.get(
	'/protected',
	ensureAuthenticated({ loginUrl: '/auth/ubcshib' }),
	(req, res) => {
		res.send('Only authenticated users see this');
	}
);

logout(returnUrl)

Middleware to handle logout. Clears session and optionally redirects to IdP logout if SLO is enabled.

const { logout } = require('@ubcshib/passport-ubcshib');

app.get('/logout', logout('/goodbye'));

conditionalAuth(checkFn)

Middleware to conditionally protect routes based on a function.

const { conditionalAuth } = require('@ubcshib/passport-ubcshib');

app.get(
	'/maybe-protected',
	conditionalAuth((req) => req.query.admin === 'true'),
	(req, res) => {
		res.send('Protected if admin query param is true');
	}
);

Profile Structure

After successful authentication, the user profile will have:

profile = {
	nameID: '[email protected]', // SAML nameID (usually email)
	nameIDFormat: '...', // SAML format identifier
	attributes: {
		// Mapped attributes (from attributeConfig)
		ubcEduCwlPuid: '12345678',
		mail: '[email protected]',
		eduPersonAffiliation: ['student'],
	},
};

Certificate Management

The strategy automatically fetches the IdP's public certificate from the metadata endpoint. No configuration is needed for certificate handling in most cases.

If you need to provide a certificate manually:

new Strategy(
	{
		// ... other options
		cert: fs.readFileSync('/path/to/idp-cert.pem', 'utf8'),
	},
	verifyCallback
);

Testing with Staging Environment

  1. Request metadata from UBC IAM:

    • Provide them with your Service Provider's metadata
    • They will configure your app in their staging environment
    • They will provide you with Entity ID confirmation
  2. Test in Staging:

    SAML_ENVIRONMENT=STAGING SAML_PRIVATE_KEY_PATH=/path/to/key node app.js
  3. Validate attributes:

    • Visit https://authentication.stg.id.ubc.ca/idp/shibboleth to see available attributes
    • Add to attributeConfig in your code

Production Deployment

  1. Work with UBC IAM to:

    • Register your production URLs (issuer, callbackUrl)
    • Confirm entity ID and metadata
    • Verify attributes are configured correctly
  2. Deploy with production settings:

    SAML_ENVIRONMENT=PRODUCTION node app.js

Troubleshooting

"Failed to load private key"

  • Ensure SAML_PRIVATE_KEY_PATH points to an existing file
  • Check file permissions (app must be able to read it)
  • Verify the file contains a valid PEM-formatted private key

"No X509Certificate found in IdP metadata"

  • Check that the IdP metadata URL is accessible
  • Verify you're using the correct environment
  • Try accessing the metadata URL in a browser

SAML validation fails

  • Verify your private key matches what UBC IAM has on file
  • Check that your Service Provider's entityID (issuer) matches what's registered with UBC
  • Ensure callbackUrl exactly matches what's registered with UBC IAM
  • Check server clocks are synchronized (NTP)

Attributes not returned

  • Verify attributes are listed in your attributeConfig
  • Check that UBC IAM has authorized release of those attributes to your app
  • Use the attributeConfig to only request attributes your app truly needs

Documentation

This package includes comprehensive documentation for different use cases:

Contributing

For issues, questions, or contributions, please contact the UBC IAM team.

License

GPL v3

References