SAML SSO
without the SAML.
You redirect users to us. We run the SAML exchange with the IdP. You verify a signed JWT. That is the integration.
Free forever · up to 5 connections · no card required
Features
The whole SAML spec.
Enterprise-ready.
Full protocol coverage, a dashboard for onboarding clients, a clean handoff, and the security posture you would otherwise have to build.
Protocol
Every direction the spec supports.
SP-initiated and IdP-initiated flows. Tunable settings per connection for bindings, algorithms, NameID formats, and clock skew.
Onboarding
Onboard in one paste.
Metadata URL import, XML upload when a URL is not available, re-import when a certificate rotates, and SP metadata to hand their IT admin.
Handoff
A signed JWT. Nothing exotic.
RS256, verifiable by any JWT library. Short-lived by default, public keys at a cached JWKS endpoint, standard claims on every token.
// JWT payload { "sub": "jane@acme.com", "iss": "simplesaml.com", "aud": "dest_8f3k2a", "src": "src_p2k9xq", "iat": 1728392400, "exp": 1728392700, "jti": "01HBK7X9QE" }
Security
Bad traffic never reaches you.
Replay protection, per-connection rate limits, signature verification, certificate validity, and readable XML errors instead of base64 dumps.
Allowed
- signature valid
- response fresh
Blocked
- response id reused
- certificate expired
- audience mismatch
- rate limit exceeded
Integration
Two routes.
Integrated.
You wire up a redirect and a callback. We run the SAML exchange in between. Replay protection, certificate rollovers, IdP quirks, XML debugging. None of it shows up in your codebase.
- Step 01
Add a connection.
Paste the client’s IdP metadata URL in the dashboard. We read the entityID, endpoints, and signing certificate.
- Step 02
Redirect to Simple SAML.
Send users to the SSO URL we give you. They log in on their company’s own screen.
- Step 03
Verify the JWT.
We redirect to your callback with a signed JWT. Verify it against our published JWKS. No shared secret to store.
// Step 02. Redirect users to us. app.get("/login", (req, res) => { res.redirect(account.ssoUrl) }) // Step 03. Verify the JWT on return. app.get("/callback", (req, res) => { const claims = jwt.verify(req.query.token, JWKS) signIn(claims.sub) })
# Step 02. Redirect users to us. @app.get("/login") def login(): return redirect(account.sso_url) # Step 03. Verify the JWT on return. @app.get("/callback") def callback(): claims = jwt.decode( request.args["token"], jwks ) sign_in(claims["sub"])
# Step 02. Redirect users to us. def login redirect_to account.sso_url end # Step 03. Verify the JWT on return. def callback claims, = JWT.decode(params[:token], nil, jwks: JWKS) sign_in claims["sub"] end
// Step 02. Redirect users to us. mux.Get("/login", func(w, r) { http.Redirect(w, r, account.SSOURL, 302) }) // Step 03. Verify the JWT on return. mux.Get("/callback", func(w, r) { token := r.URL.Query().Get("token") claims, _ := jwt.Parse(token, keyfunc) signIn(claims["sub"]) })
Team
Independent.
On purpose.
Simple SAML is independent, revenue-funded, and employee-owned. No outside investors, no debt, no acquisition timeline. We answer to the people using the product, not a board planning an exit.
That means predictable pricing, a product that stays focused, and a commitment to operating Simple SAML for as long as SAML is a problem worth solving.
- Ownership
- Employee-owned
- Funding
- Revenue-funded
- Investors
- None
- Debt
- None
Pricing
A basic plan,
free forever.
Paid plans are on the way for larger deployments. The free plan will stay free, not a trial.
Free · available now
$0
/month · always
- Up to 5 SAML connections
- Unlimited workspace users
- Every feature on this page
- No card required
Coming soon
Paid plans for larger deployments.
More connections, broader SAML coverage, and priority support. The free plan stays free.
- Unlimited connections
- Attribute passthrough
- REST API
- Priority human support
- SP-initiated SLO
FAQ
Questions
worth asking.
How long does setup take?
Roughly 30 minutes to wire up the redirect, the callback, and JWT verification. Each client takes a few minutes more, once their IT admin imports your SP metadata into their IdP.
Which identity providers work?
Any standards-compliant SAML 2.0 provider. Okta, Microsoft Entra ID, Google Workspace, JumpCloud, OneLogin, PingFederate, ADFS, Shibboleth, Auth0, and the long tail of smaller providers your clients may use.
Do you support SCIM?
Not yet. Simple SAML handles SAML 2.0 authentication only. User provisioning happens in your app when you receive the JWT. SCIM support is on the roadmap for clients that need automated directory sync.
How does this work across many clients?
Each client is added once as a connection with its own SSO URL. Every client flows through the same callback in your app; the JWT tells you which connection the user came from.
Will users notice anything different?
No. They land on their own company’s login screen, authenticate with their IT team’s policy, and arrive in your app signed in. We sit quietly in the middle.
Do you store user data?
No. Each SAML response is validated, converted into a short-lived JWT, and handed back to your callback. The raw assertion is not persisted.
What’s in the JWT?
A sub with the user’s NameID, iss identifying us, aud bound to your app, src naming the connection, iat and exp, and a unique jti for replay prevention.
How do I verify the JWT?
Any standard JWT library with JWKS support. RS256, with our public keys at /.well-known/jwks.json. Your library fetches and caches the JWKS for you. Check iss, aud, and exp, and you’re done. Nothing to rotate on your side.
What happens when a client rotates their certificate?
Re-import the connection’s metadata. The new certificate replaces the old one and assertions signed with the new key validate on the next request.
Start
SAML is
our problem now.
Free plan, no card. Wire up two routes, verify a JWT, and hand SAML to us.