An example implementation of a SAML IdP Proxy
WARNING: This project is provided as an example only. It comes with no waranty whatsoever. Use at entirely your own risk.
- Introduction
- Why would I need one?
- How to run the demo
- How it works
- Useful links
- Development
- How can I use this?
A SAML IdP Proxy is a stand-alone service that sits between an SP (Service Provider - usually your application, or a 3rd party IaaS), and an IdP (Identity Provider - the authentication system. This can be an in-house implementation or a 3rd party provider such as AWS Cognito, Okta, or Auth0). It can route, modify, log, and enhance SAML interactions.
The SAML Proxy acts as an IdP to your SP, and an SP to your IdP, and provides a mapping between them. See the diagram below:
This project provides a fully functional implementation of a SAML Proxy intented as an example or starting point for your own implementation.
It also includes a Test SP and a Test IdP for demonstration purposes, but these could also be the starting point for your own implementations.
See below for instructions on how to run and inspect the demo.
There are many reasons why you might need, or want, to use a SAML IdP Proxy. Fundamentally it allows you to decouple your SSO enabled applications from your identity providers. Some suggestions, but by no means an exhaustive list:
- Avoid IaaS vendor lock-in: Every B2B SaaS product needs to offer "enterprise SSO" - SAML authentication - to its customers. It's an enormous time saver for SaaS venders to integrate with an Identity as a Service (IaaS) provider, such as OAuth, AWS Cognito, Work OS, or Clerk rather than implement identity management, authentication and authorization in house. But with each of your customers individually configuring their own IdP to talk to your IaaS provider, it makes for very deep lock-in. Without a proxy you will have to persuade each customer in turn to reconfigure their IdP before you can escape from your IaaS. With a proxy, you can migrate all your customers instantly to a different IaaS, or your own SP implementation. This was the motivation behind my original interest in a SAML Proxy. I was part of a team which migrated several hundred customers away from Auth0 and Cognito using this method.
- Auditing monitoring and logging: IaaS providers can often be opaque black boxes when it comes to auditing, monitoring, or logging, which can make fulfilling regulatory requirements or diagnosing authentication issues difficult. A SAML Proxy can provide a tap for comprehensive logging of all SAML operations.
- Identity Provider Consolidation: Provide a single IdP endpoint to applications while routing to different IdPs based on arbitrary criteria (email domain, user ID, name of cat, whatever).
- Service Provider Consolidation: Provide a single SP endpoint for multiple applications and route appropriately. This could be useful in a company merger scenario for example.
- Attribute Transformation: Modify SAML Assertion attributes to match the expectations of your applications. For example, your SP might expect an employeeId, but your IdP can only provide a userId.
- Enhanced Security: Add additional authentication factors, session management, or security policies. Perhaps you want to enforce fully encrypted assertions, but your service provider can't accept them.
- Anonymize: You might want to hide the details of your SPs from IdP(s) or vice-versa.
This project is intended as a runnable demo to demonstrate how one can configure and use a SAML Proxy. It's intended to be easy to setup and run.
- Install Bun by following the instructions on the Bun website
- Clone the repository.
- Execute bun install in the root directory.
- Execute bun run setup in the root directory. This creates the .env file and X509 certificates.
- Execute bun run dev in the root directory.
- This will launch a cluster of SP, Proxy, and IdP. Use the displayed localhost URL to navigate to the SP.
- Login as one of the displayed users. Watch as you are redirected to the IdP to authenticate.
- To try the IdP-initiated flow, navigate directly to the IdP URL, authenticate then click the button to initiate the SAML flow to the SP.
To view the SAML interactions install a SAML tracing browser plug-in. I use SAML Chrome Panel
This interaction diagram shows the SP-initiated flow:
This is a monorepo containing 4 packages:
- common: This contains the core SAML logic and other common functions. It uses the excellent Samlify SAML library.
- proxy: This is the core proxy package.
- testsp: This is a test SAML service provider (SP). This mimics the application that needs to authenticate.
- testidp: This is test SAML identity provider (IdP). This mimics an identity provider, such as Okta or Auth0.
SamlProxy uses Bun. Install it by following the instructions on the Bun website
Create the .env file and X509 certificates with:
(Optional Customize your setup by modifying .env.template before running bun run setup)
Start with:
The script scripts/cluster.ts will start all three processes at the following URLs:
Run unit tests with:
The SAML Proxy cannot be used for your scenario out-of-the-box, you will need to customize it for your own purposes.
The SAML Proxy database is an in-memory SqlLite DB. At a minimum for use in production you would need to change this to a persistent store, either using SqlLite, or a relational database server such as PostgreSql. The existing DB code is very simple and can be found in packages/proxy/src/db.ts and packages/common/src/db.ts.
At startup the tables sp_connection, idp_connection, and sp_to_idp_link are populated by initializeConnections in packages/proxy/src/connection.ts. You will need to populate these with the relevant values for your SPs, IdPs, and the connections between them. For a persistent store you will need to do this as part of a separate process, not on startup. A future enhancement to SAML Proxy would be to add a management API and UI to aid this.
- sp_connection represents the connection to an SP, where the Proxy is acting as an IdP.
- idp_connection represents the connection to an IdP, where the Proxy is acting as an SP.
- sp_to_idp_link is the link between an SP and an IdP. It tells the Proxy where to forward the SAML authentication request.
- relay_state stores a record of each AuthnRequest. It's used to validate incoming assertions. It's the only non "read only" table at runtime.
.png)


