Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslnode 18–226 runs
build_error
glibcnode 18–226 runs
build_error
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
default
✓ const Hapi = require('@hapi/hapi'); const plugin = require('hapi-saml2'); await server.register({ plugin, options })
✗ import Hapi from '@hapi/hapi' (ESM may not work if Hapi is CommonJS)
Package is CommonJS only; use require() with @hapi/hapi (CommonJS) to avoid interop issues.
plugin options (getSAMLOptions, login, logout)
✓ options: { getSAMLOptions: (request) => { return { entryPoint: '...', cert: '...' }; }, login: async (request, identifier, user) => { return true; }, logout: async (request) => { } }
✗ options: { samlOptions: { ... } } (no such top-level key; saml config must be returned from getSAMLOptions)
getSAMLOptions is a function that must return node-saml options; it is called per request to allow dynamic configuration.
login callback
✓ login: async (request, identifier, user) => { return true; }
✗ login: async (request, identifier, user) => { /* no return */ } (must return boolean or { success: boolean, errorMessage?: string })
Return true to authenticate; return object with success: false to trigger postResponseValidationErrorHandler.
Registers the hapi-saml2 plugin with required callbacks and dynamic SAML options from environment variables.
const Hapi = require('@hapi/hapi');
const server = Hapi.server({ port: 3000, host: 'localhost' });
const init = async () => {
await server.register({
plugin: require('hapi-saml2'),
options: {
getSAMLOptions: (request) => ({
entryPoint: process.env.SAML_ENTRY_POINT ?? 'https://idp.example.com/ssos',
cert: process.env.SAML_CERT ?? '',
issuer: 'http://localhost:3000',
callbackUrl: 'http://localhost:3000/saml/callback'
}),
login: async (request, identifier, user) => {
// After SAML response validation, identifier is the NameID
console.log(`User ${identifier} logging in`);
return true;
},
logout: async (request) => {
// Implement logout logic, e.g., clear session
console.log('User logged out');
},
redirectUrlAfterSuccess: '/dashboard',
redirectUrlAfterFailure: '/login'
}
});
await server.start();
console.log('Server running on %s', server.info.uri);
};
init().catch(console.error);
Errors
Common errors & fixes
Error: SAML instance is not configured
getSAMLOptions returned undefined or threw inside the function.
fixEnsure getSAMLOptions always returns an object with required node-saml properties (entryPoint, cert, etc.).
AssertionError: login must be a function
Login option is missing or not a function in plugin options.
fixAdd login: async (request, identifier, user) => { return true; } to options. TypeError: Cannot destructure property 'nameID' of 'user' as it is undefined
user parameter in login callback is undefined if SAML response lacks expected profile attributes.
fixCheck that Identity Provider sends NameID; use identifier (string) instead of user properties if only NameID is needed.
Audit
Dependencies
@hapi/boomrequiredpeer dependency for HTTP-friendly error objects used in configuration error handling and SAML failures