Skip to content

Getting started

This guide installs PassBeyond from the bella.network APT repository, connects one SAML Identity Provider, and starts a systemd instance for a single application.

Prerequisites

You need:

  • a Debian-based amd64 or arm64 server;
  • a DNS name such as myapp.example.com;
  • a TLS reverse proxy such as nginx or Apache;
  • a SAML 2.0 Identity Provider and permission to create an application there;
  • a backend application that PassBeyond can reach over HTTP or HTTPS.

The browser-facing URL must use HTTPS. PassBeyond creates Secure cookies and builds its SAML endpoints from the configured domain.

1. Install PassBeyond

Add the bella.network signing key and APT source:

bash
curl -fsSL https://repo.bella.network/_static/bella-archive-keyring.gpg \
  | sudo tee /usr/share/keyrings/bella-archive-keyring.gpg >/dev/null

sudo tee /etc/apt/sources.list.d/repo.bella.network.sources >/dev/null <<'EOF'
Types: deb
URIs: https://repo.bella.network/deb
Suites: stable
Components: main
Architectures: amd64 arm64
Signed-By: /usr/share/keyrings/bella-archive-keyring.gpg
EOF

sudo apt update
sudo apt install passbeyond

The package installs the passbeyond executable, a dedicated system user, and the passbeyond@.service systemd template. See Installation for file locations and a source build.

For Docker or Podman, follow Container deployment, then return to the IdP registration and verification steps below.

2. Register the service at your IdP

Use these values when creating the SAML application. Replace myapp.example.com with your public domain.

SettingValue
Entity IDhttps://myapp.example.com/saml/metadata
ACS URLhttps://myapp.example.com/saml/acs
Single Logout URLhttps://myapp.example.com/saml/slo
NameID formatTransient identifier

Enable signed SAML responses and assertions. Export or copy the IdP metadata URL after creating the application. Provider-specific examples are available in Identity providers.

3. Create an instance configuration

The package includes a non-functional /etc/passbeyond/default.yaml. Create a separate file whose name identifies the protected service:

bash
sudo cp /etc/passbeyond/default.yaml /etc/passbeyond/myapp.yaml
sudo editor /etc/passbeyond/myapp.yaml

Use this minimal configuration as a starting point:

yaml
domain: "myapp.example.com"

idpMetadataURL: "https://sso.example.com/path/to/metadata.xml"

# Persistent, private state for this PassBeyond instance.
configPath: "/var/lib/passbeyond/myapp.json"

proxy:
  listenAddress: "127.0.0.1:8123"
  targetURL: "http://127.0.0.1:8888"
  targetDisableSSLVerify: false
  stripVersionHeaders: true
  useBasicAuth: false
  trustedProxies:
    - "127.0.0.1"
    - "::1"

sessionTimeout: 1440
samlRequestSigning: false

configPath contains the generated JWT secret, SAML signing key pair, instance ID, and cached remote IdP metadata. Keep it persistent, writable by the passbeyond user, and separate for every instance.

Do not share or publish dynamic state

Anyone who obtains the JWT secret can create valid session cookies. Anyone who obtains the SAML private key can impersonate the Service Provider. Back up this file securely and restrict its permissions.

For a local metadata file instead of a URL, replace idpMetadataURL with idpMetadataFile. See Configuration for both modes.

4. Start the instance

The systemd instance name is the configuration filename without .yaml:

bash
sudo systemctl enable --now passbeyond@myapp.service
sudo systemctl status passbeyond@myapp.service
sudo journalctl -u passbeyond@myapp.service -n 100 --no-pager

On first start, PassBeyond generates its private state and retrieves the IdP metadata. Startup fails if neither configured nor cached metadata is usable.

5. Put PassBeyond behind TLS

Configure the public reverse proxy to send all requests for myapp.example.com to 127.0.0.1:8123. Preserve the original Host header and overwrite, rather than append to, client-supplied forwarding headers.

An nginx configuration is provided in Deployment.

Keep the PassBeyond listener private. Users must not be able to bypass the public reverse proxy and access the backend application directly.

6. Import PassBeyond metadata

Once the public route is available, open:

text
https://myapp.example.com/saml/metadata.xml

If your IdP supports metadata import, use that URL to verify or update the Service Provider settings. The signing certificate is also available from /saml/certificate.crt.

7. Test authentication

Open https://myapp.example.com/ in a private browser window.

  1. PassBeyond redirects the browser to the IdP.
  2. The IdP authenticates the user and posts a SAML response to /saml/acs.
  3. PassBeyond creates the __passbeyond_session cookie and redirects back to the original URL.
  4. The backend receives X-Passbeyond-User and any mapped X-Passbeyond-Data-* headers.

Confirm at the backend that identity headers are present and that the PassBeyond session cookie is not forwarded. Then visit /saml/slo and verify that a protected request requires authentication again.

Production checklist

  • [ ] The backend and PassBeyond listener are not publicly reachable.
  • [ ] The public origin uses a valid TLS certificate and redirects HTTP to HTTPS.
  • [ ] domain exactly matches the public hostname.
  • [ ] Every instance has a unique, persistent configPath.
  • [ ] Dynamic state and YAML files have restrictive ownership and permissions.
  • [ ] Only the actual TLS proxy is listed in trustedProxies.
  • [ ] The IdP signs responses and assertions.
  • [ ] Upstream TLS verification remains enabled when targetURL uses HTTPS.
  • [ ] Passthrough paths and tokens are limited to an explicit operational need.
  • [ ] The session lifetime matches the risk of delayed IdP account and group changes.
  • [ ] The backend trusts identity headers only from PassBeyond.
  • [ ] The public reverse proxy enforces suitable request-size and rate limits.
  • [ ] Dynamic state is included in an encrypted, tested backup.
  • [ ] Authentication, logout, backend failure, and IdP failure have been tested.

Next steps

Released under the MIT License.