Skip to content

Architecture

PassBeyond combines two roles in one process:

  • a SAML 2.0 Service Provider that communicates with an Identity Provider;
  • a reverse proxy that gates and forwards traffic to one backend application.

It has no administration interface. Its only browser-facing pages are protocol responses and friendly error pages.

Components

text
┌─────────┐       ┌───────────────┐       ┌────────────┐       ┌─────────────┐
│ Browser │ ────→ │ TLS proxy     │ ────→ │ PassBeyond │ ────→ │ Application │
└─────────┘       │ nginx/Apache  │       └─────┬──────┘       └─────────────┘
                  └───────────────┘             │
                                                │ SAML 2.0

                                         ┌─────────────┐
                                         │ Identity    │
                                         │ Provider    │
                                         └─────────────┘

TLS reverse proxy

The edge proxy owns the public HTTPS listener and certificate. It routes every request for the protected domain to PassBeyond and supplies client-address information from a trusted network position.

PassBeyond

PassBeyond redirects unauthenticated browsers to the IdP, processes SAML responses, creates signed JWT sessions, validates those sessions on protected requests, removes untrusted identity headers, adds trusted identity data, and proxies the request.

Identity Provider

The IdP authenticates the user and issues signed SAML assertions. It remains the source of identity attributes and group membership.

Backend application

The backend receives ordinary HTTP requests plus identity headers. It must trust those headers only on traffic arriving from PassBeyond and remains responsible for authorization.

Authentication flow

  1. A user requests https://myapp.example.com/report.
  2. The TLS proxy forwards the request to PassBeyond.
  3. PassBeyond finds no valid __passbeyond_session cookie.
  4. The browser is redirected through /__passbeyond-redirect to the IdP.
  5. The IdP authenticates the user and sends a SAML response to /saml/acs.
  6. PassBeyond validates the response and maps supported attributes.
  7. It creates a signed JWT cookie and redirects to the original same-domain HTTPS URL.
  8. PassBeyond validates the JWT, removes spoofable headers, adds trusted identity headers, and sends the request to the backend.
  9. The backend authorizes and serves the request.

The original redirect destination must be HTTPS and match the configured domain and port. Invalid destinations fall back to the domain root.

Static and dynamic configuration

Static settings come from YAML or environment variables. Generated security material and cached metadata are stored in one dynamic JSON file:

text
Static YAML/environment              Dynamic JSON
───────────────────────              ────────────
domain                               instance ID
IdP metadata source                  JWT secret
listen and target addresses          SAML private key and certificate
session lifetime                     cached remote IdP metadata
passthrough rules

The dynamic file is both persistent state and sensitive key material. It is local to an instance and is not a shared session database.

One instance per service

An instance is tied to one public domain and one backend target. Protect multiple domains by running multiple instances, each with a unique listener and dynamic state file. The APT package's systemd template is designed for this model.

This separation prevents domains from sharing cookies, signing material, passthrough rules, and backend routing by accident.

Route ownership

PassBeyond owns the public SAML endpoints under /saml/, the login redirect /__passbeyond-redirect, and static/error resources under /__passbeyond/. The backend must not depend on those paths. All other authenticated requests are proxied to the configured target.

See Endpoints for the full public list.

Released under the MIT License.