Appearance
CLI
The saml-bridge command manages registered apps, signing keys, and the audit log. Run it from the directory that holds the database, or set SAMLBRIDGE_DATABASE. Bridge settings come only from environment variables. Apps, keys, and audit entries live in SQLite.
Register an app
sh
saml-bridge apps add --slug payroll --metadata payroll.xml--slugand--metadataare required. The slug uses 1 to 64 lowercase letters, digits, and inner hyphens.- The metadata is a file. Download it yourself from a source you trust. The bridge doesn't fetch URLs and doesn't verify metadata signatures.
- The command prints the SHA-256 fingerprint of each signing certificate. Check those fingerprints against the app vendor's documentation before confirming them.
Metadata is refused when it:
- contains a DTD or external entity,
- is larger than 1 MB or nested more than 32 levels deep,
- has an ACS endpoint that isn't HTTP-POST over HTTPS,
- has no signing certificate.
To change an app's metadata, remove the app and add it again. Then set its sign-in settings again (see Set the sign-in settings).
Confirm the certificates
sh
saml-bridge apps confirm payroll --fingerprint AB:CD:... --fingerprint EF:01:...Give every fingerprint shown by apps add. If the set doesn't match the stored certificates exactly, nothing is confirmed. A certificate that isn't confirmed can't be used to verify AuthnRequests, and IdP-initiated SSO can't be turned on.
Set the sign-in settings
sh
saml-bridge apps set payroll --nameid-claim sub --nameid-format persistent --enable
saml-bridge apps set payroll --attribute "urn:oid:0.9.2342.19200300.100.1.3=email,required" --attribute "groups=groups"
saml-bridge apps set payroll --relay-state /dashboard --relay-state /reports
saml-bridge apps set payroll --disable--nameid-claimand--nameid-format(persistent,transient,unspecified, oremail) set the subject. Both are needed before the app can sign in. The claim is read from the OIDC ID token.--attribute name=claim[,required]maps a SAML attribute to an ID token claim. Give it once per attribute. Each use replaces the whole attribute list.requiredrefuses the login when the claim is missing. Names must be unique, ignoring case. Otherwise nothing is saved.--relay-statelists the RelayState values the app may use. Each use replaces the list. Any other RelayState is dropped.--scopelists the scopes the bridge requests from the OIDC provider for this app. A scope name can be any name of 1 to 64 letters, digits, underscores, hyphens, colons, or dots. Each use replaces the list.openidis always requested. Without--scope, the app getsopenid, plusprofileandemailas its claims need.rolesandgroupsare requested only when named here.--default-scopesreturns the app to the default list.--enableand--disableturn SSO on or off for the app. An enabled app serves both SP-initiated SSO and sign-in at/idp/<slug>.--enableis refused, and nothing is saved, unless the app has a default ACS,--nameid-claimand--nameid-formatset, and every signing certificate confirmed.--disableis always allowed.- Claim names must be letters, digits, and underscores, starting with a letter, 1 to 64 characters. Other names are refused.
Each change writes an audit entry.
Disable or remove an app
sh
saml-bridge apps disable payroll
saml-bridge apps remove payrollapps disable <slug>is the same asapps set <slug> --disable. Both make the same change and write the sameapps.setaudit entry.apps remove <slug>deletes the app: its ACS endpoints, certificates, attribute mappings, and RelayState values. Logins in progress for the app are deleted too, so a callback for them is refused.- Removing is permanent. To keep the app but stop SSO, disable it instead.
- Audit entries are kept, and the removal writes an
apps.removeentry. - An unknown slug fails with exit code 1 and changes nothing. The slug must match exactly, so
Payrollor a slug with spaces doesn't matchpayroll. - After a removal, the same slug can be registered again with
apps add.
Inspect
sh
saml-bridge apps list
saml-bridge apps show payrollEach add and confirm writes an audit entry. Audit entries never contain assertions, tokens, codes, or secrets.
Rotate the signing key
sh
saml-bridge keys rotate
# restart the bridge
saml-bridge keys retire
# restart the bridgekeys rotatecreates a new signing key and makes it the only active key. The previous key stays in the database, inactive. The change and itskeys.rotateaudit entry are written in one transaction. The command prints the new key's SHA-256 fingerprint. It refuses, and changes nothing, unless exactly one key is active.- Restart the bridge. The running bridge keeps the key it loaded at startup, so it keeps signing with the old key until it restarts. The new key signs after the restart.
- After the restart,
/saml/metadatalists the new certificate first and the old one after it, as two signingKeyDescriptors. Check that both certificates are there. - Give the new certificate to each SP, and wait until every SP trusts it. The old certificate stays published until you retire it, so an SP can switch over without a gap.
keys retiredeletes every inactive key and writes akeys.retireaudit entry. It never deletes the active key. It refuses, and changes nothing, when there is no inactive key, so a second retire does nothing. Restart the bridge afterwards, so/saml/metadatastops listing the retired certificate.
The bridge loads every stored certificate at startup, but it signs only with the active key. It reads only the public certificate of an inactive key, so the old private key is never decrypted.
- Both commands read
SAMLBRIDGE_MASTER_KEYfrom the environment andSAMLBRIDGE_PUBLIC_URLfor the certificate's name, and they useSAMLBRIDGE_DATABASElike the other commands. - They don't create the database. Start the bridge once first.
- The bridge refuses to start when more than one key is active, or when keys are stored and none is active. It never picks a key. The CLI doesn't repair this state, so fix the
SigningKeystable with a backup in hand, or restore a backup.
Audit log
sh
saml-bridge audit list
saml-bridge audit list --limit 10- Entries are listed newest first, one line per entry: id, time in UTC (ISO 8601), action, target, and detail. The header is printed once.
--limitshows from 1 to 500 entries. The default is 50. Any other value is refused.- Detail text is cut to 200 characters, and control characters are escaped, so each entry stays on one line.
- The command is read-only. It doesn't create the database, and it writes no audit entry. It refuses when the database file is missing or has migrations that aren't applied.
Settings
The saml-bridge command reads its settings from environment variables only, the same source as the web host, so every command opens the same database as the running bridge. It never reads appsettings*.json, and it doesn't accept settings as command-line arguments. SAMLBRIDGE_MASTER_KEY and SAMLBRIDGE_OIDC_CLIENT_SECRET are refused if they're passed as an argument, and the command never prints them. SAMLBRIDGE_DATABASE defaults to saml-bridge.db in the working directory when it isn't set. See Configuration.