{"id":16677,"library":"remix-auth-saml","title":"Remix Auth SAML Strategy","description":"remix-auth-saml provides a SAML 2.0 authentication strategy for Remix Auth, enabling single sign-on (SSO) integration in Remix applications. This library abstracts the complexities of SAML authentication flows, including service provider (SP) and identity provider (IdP) interactions, metadata exchange, and assertion processing. The current stable version is 1.2.0, with releases occurring periodically, primarily for dependency updates and minor fixes as seen in recent changelogs. Key differentiators include its direct integration with the Remix Auth ecosystem, providing a familiar API for developers already using `remix-auth`, and its explicit support for both Node.js and Cloudflare runtimes, making it versatile for various deployment targets.","status":"active","version":"1.2.0","language":"javascript","source_language":"en","source_url":"https://github.com/christopherpickering/remix-auth-saml","tags":["javascript","remix","remix-auth","auth","authentication","strategy","saml","typescript"],"install":[{"cmd":"npm install remix-auth-saml","lang":"bash","label":"npm"},{"cmd":"yarn add remix-auth-saml","lang":"bash","label":"yarn"},{"cmd":"pnpm add remix-auth-saml","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required peer dependency for Remix application runtime services, essential for session management and server-side utilities.","package":"@remix-run/server-runtime","optional":false}],"imports":[{"note":"remix-auth-saml is primarily designed for ESM environments, aligning with Remix's architecture. While CJS might work via transpilation, direct require() is discouraged for type safety and modern tooling.","wrong":"const SamlStrategy = require('remix-auth-saml').SamlStrategy;","symbol":"SamlStrategy","correct":"import { SamlStrategy } from 'remix-auth-saml';"},{"note":"The `metadata` function is a named export from the SamlStrategy instance, not a direct export from the package. The example shows `let metadata = samlStrategy.metadata();` which is the correct usage after instantiating the strategy.","wrong":"import metadata from 'remix-auth-saml';","symbol":"metadata","correct":"import { metadata } from 'remix-auth-saml';"},{"note":"While not directly from `remix-auth-saml`, `Authenticator` from `remix-auth` is fundamental for using this strategy. It's crucial to understand it's a separate peer dependency.","symbol":"Authenticator","correct":"import { Authenticator } from 'remix-auth';"}],"quickstart":{"code":"import { Authenticator } from \"remix-auth\";\nimport { sessionStorage } from \"~/services/session.server\"; // Assuming a session storage setup\nimport { SamlStrategy } from \"remix-auth-saml\";\nimport * as validator from \"@authenio/samlify-node-xmllint\"; // Or another SAML XML validator\n\n// Create an Authenticator instance\nexport let authenticator = new Authenticator<any>(sessionStorage);\n\n// Initialize the SAML strategy\nlet samlStrategy = new SamlStrategy(\n  {\n    validator,\n    authURL: \"http://localhost:3000/auth/saml\",\n    callbackURL: \"http://localhost:3000/auth/saml/callback\",\n    idpMetadataURL: \"http://localhost:7000/metadata\", // URL to your Identity Provider's metadata\n    spAuthnRequestSigned: false,\n    spWantAssertionSigned: false,\n    spWantMessageSigned: false,\n    spWantLogoutRequestSigned: false,\n    spWantLogoutResponseSigned: false,\n    spIsAssertionEncrypted: false,\n    // Optional: Specify private keys and certificates for signing/encryption\n    // privateKey: \"./path/to/sp-private-key.pem\",\n    // signingCert: \"./path/to/sp-public-cert.pem\"\n  },\n  async ({ extract, data }) => {\n    // This verify callback runs after successful SAML authentication\n    // 'extract' contains parsed user profile data from the SAML assertion\n    // 'data' is the raw IdP response, useful for backend verification or decryption\n    console.log(\"User profile extracted:\", extract);\n    console.log(\"Raw IdP response data:\", data);\n\n    // Here, you would typically find or create a user in your database\n    // based on 'extract' data and return the user object.\n    // Example: const user = await userService.findOrCreate(extract);\n    // return user;\n\n    // For this example, we'll just return a placeholder\n    return { id: extract.nameID, email: extract.attributes['urn:oid:0.9.2342.19200300.100.1.3'] };\n  }\n);\n\n// Register the strategy with the Authenticator\nauthenticator.use(samlStrategy, \"saml\");\n\n// Export SP metadata for the IdP\nexport let spMetadata = samlStrategy.metadata();","lang":"typescript","description":"This quickstart demonstrates the core setup for `remix-auth-saml`, including initializing `Authenticator`, configuring `SamlStrategy` with essential SAML parameters, and providing a `verify` callback to process user data post-authentication. It also shows how to expose the Service Provider (SP) metadata for your Identity Provider (IdP)."},"warnings":[{"fix":"Carefully review all SAML configuration options with your IdP administrator. Use tools like SAML Tracer browser extensions to inspect SAML messages for discrepancies. Ensure URLs are exact and public/private keys are correctly generated and matched.","message":"SAML configuration requires precise matching between the Service Provider (your Remix app) and the Identity Provider (IdP). Small mismatches in `authURL`, `callbackURL`, certificate formats, or signing/encryption preferences can lead to authentication failures that are difficult to debug.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Install a compatible XML validator package (e.g., `npm install @authenio/samlify-node-xmllint`) and pass it to the `SamlStrategy` constructor via the `validator` option.","message":"A SAML XML validator is a mandatory dependency for `remix-auth-saml`, but it's not bundled. Forgetting to install one (e.g., `@authenio/samlify-node-xmllint`) will cause runtime errors when the strategy attempts to process SAML responses.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Use environment variables (e.g., `process.env.APP_BASE_URL`) to dynamically configure these URLs, ensuring they match the deployed environment's address.","message":"When deploying to environments with different hostnames or port numbers, the `authURL`, `callbackURL`, and `idpMetadataURL` configured in `SamlStrategy` must reflect the actual public-facing URLs. Hardcoding `localhost` will lead to issues in production.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Install a SAML XML validator like `@authenio/samlify-node-xmllint` (`npm i @authenio/samlify-node-xmllint`) and pass it to the `SamlStrategy` options: `new SamlStrategy({ validator: require('@authenio/samlify-node-xmllint'), ... })`.","cause":"The `validator` option was not provided or was null in the `SamlStrategy` constructor, which is a required dependency for SAML XML parsing and validation.","error":"Error: Missing SAML validator. Please install a validator (e.g., @authenio/samlify-node-xmllint) and pass it into the strategy constructor."},{"fix":"Ensure `authenticator` is correctly initialized with session storage and exported from `auth.server.ts`. Verify that `authenticator.use(samlStrategy, 'saml')` is called before attempting to use the 'saml' strategy.","cause":"The `authenticator` instance from `remix-auth` was not correctly initialized or exported, or the SAML strategy was not registered with it using `authenticator.use(samlStrategy, 'saml')`.","error":"TypeError: Cannot read properties of undefined (reading 'authenticate')"}],"ecosystem":"npm"}