SAML Migration Guide
This guide helps you migrate to the new @authhero/saml package and understand the changes in SAML configuration.
What Changed?
SAML functionality has been extracted from the authhero core package into a separate @authhero/saml package. This provides:
- ✅ Better support for edge/serverless environments
- ✅ Smaller bundle sizes when SAML isn't needed
- ✅ Flexible signing strategies (local or HTTP-based)
- ✅ Runtime configuration of SAML signers
Breaking Changes
None! 🎉
The migration is backward compatible. Existing code using SAML_SIGN_URL environment variable continues to work without changes.
Migration Paths
Option 1: No Changes Required (Environment Variable)
If you're using the SAML_SIGN_URL environment variable, nothing needs to change:
// Before (still works!)
import { init } from "authhero";
const app = init({ dataAdapter });
// Uses SAML_SIGN_URL automaticallyOption 2: Explicit Configuration (Recommended)
For better control, pass a signer instance:
// After (recommended)
import { init, HttpSamlSigner } from "authhero";
const app = init({
dataAdapter,
samlSigner: new HttpSamlSigner("https://signing-service.com/sign"),
});Option 3: Local Signing (Node.js)
If you were relying on local signing behavior:
// After (Node.js only)
import { init } from "authhero";
import { LocalSamlSigner } from "@authhero/saml/local-signer";
const app = init({
dataAdapter,
samlSigner: new LocalSamlSigner(),
});Bundle Size Improvements
Before (All Imports)
import { init } from "authhero";
// Bundle: ~65 KB (includes xml-crypto)After (HTTP-Based Only)
import { init, HttpSamlSigner } from "authhero";
// Bundle: ~64 KB (NO xml-crypto)After (Local Signing)
import { init } from "authhero";
import { LocalSamlSigner } from "@authhero/saml/local-signer";
// Bundle: ~64 KB + xml-crypto (same as before)New Features
1. Runtime Configuration
You can now change the SAML signer at runtime:
const httpSigner = new HttpSamlSigner("https://signing-service.com/sign");
const localSigner = new LocalSamlSigner();
// Use different signers based on environment
const signer = process.env.NODE_ENV === "production" ? httpSigner : localSigner;
const app = init({
dataAdapter,
samlSigner: signer,
});2. Custom Signers
Implement custom signing logic:
import type { SamlSigner } from "authhero";
class MyCustomSigner implements SamlSigner {
async signSAML(xml: string): Promise<string> {
// Your custom logic
return signedXml;
}
}
const app = init({
dataAdapter,
samlSigner: new MyCustomSigner(),
});3. Signer Composition
Wrap signers with additional functionality:
import { HttpSamlSigner } from "authhero";
class RetrySigner implements SamlSigner {
constructor(private inner: SamlSigner) {}
async signSAML(xml: string): Promise<string> {
// Retry logic
return await this.inner.signSAML(xml);
}
}
const baseSigner = new HttpSamlSigner("https://signing-service.com/sign");
const retrySigner = new RetrySigner(baseSigner);
const app = init({
dataAdapter,
samlSigner: retrySigner,
});Edge/Serverless Deployment
Cloudflare Workers
// wrangler.toml
# SAML_SIGN_URL = "https://signing-service.com/sign"
import { init } from 'authhero';
import { createCloudflareAdapter } from '@authhero/cloudflare';
export default {
async fetch(request: Request, env: Env) {
const dataAdapter = createCloudflareAdapter(env);
// Automatically uses HttpSamlSigner
const { app } = init({ dataAdapter });
return app.fetch(request, env);
}
};Vercel Edge Functions
import { init, HttpSamlSigner } from "authhero";
export const config = {
runtime: "edge",
};
export default async function handler(req: Request) {
const { app } = init({
dataAdapter,
samlSigner: new HttpSamlSigner(process.env.SAML_SIGN_URL!),
});
return app.fetch(req);
}Direct Package Usage
If you were importing SAML utilities directly, update imports:
Before
import { createSamlResponse } from "authhero";After
import { createSamlResponse } from "@authhero/saml";TypeScript Types
SAML types are now exported from both packages:
// From main package (recommended)
import type { SamlSigner } from "authhero";
// Or from SAML package directly
import type { SamlSigner, SAMLRequest, SAMLResponseJSON } from "@authhero/saml";Testing
Mock Signer for Tests
import type { SamlSigner } from "authhero";
class MockSigner implements SamlSigner {
async signSAML(xml: string): Promise<string> {
return xml; // Return unsigned for tests
}
}
// In tests
const app = init({
dataAdapter: mockAdapter,
samlSigner: new MockSigner(),
});Troubleshooting
"Cannot find module '@authhero/saml'"
The @authhero/saml package is installed automatically as a dependency of authhero. If you see this error:
pnpm install authhero
# or
npm install authhero"xml-crypto not found" in Edge Environment
You're trying to use LocalSamlSigner in an edge environment. Use HttpSamlSigner instead:
// Don't do this in edge environments
import { LocalSamlSigner } from "@authhero/saml/local-signer";
// Do this instead
import { HttpSamlSigner } from "authhero";
const signer = new HttpSamlSigner(env.SAML_SIGN_URL);Bundle Size Still Large
Make sure you're not importing from the wrong entry point:
// ❌ Wrong - includes LocalSamlSigner
import { HttpSamlSigner } from "@authhero/saml";
// ✅ Correct - no xml-crypto
import { HttpSamlSigner } from "authhero";
// or
import { HttpSamlSigner } from "@authhero/saml/core";