Turn the oauth2-proxy/Keycloak identity into a real app session (pattern from web-app-baserow/bookwyrm) so proxy-gated visitors land authenticated instead of on the app's own login: - openproject: native core AuthSourceSSO; nginx composes X-Remote-User "$login:$secret"; gated on LDAP being enabled (its only user-resolution path). - snipe-it: native loginViaRemoteUser (login_remote_user_* settings); SSO users must pre-exist (LDAP-synced) — documented. - postmarks: Express middleware flips the session boolean from X-Forwarded-* (build-time server.js patch). - yourls: shunt_is_valid_user drop-in via custom image (user/cache.php); YOURLS_PRIVATE forced on. Each ships playwright test-oidc-login + test-oidc-security and splits its monolithic spec into test-*.js. Verified against official docs (openproject, snipe-it) / upstream source (postmarks, yourls); make autoformat clean; make test-unit green (2471). Also sweeps in two small concurrent working-tree changes per stage-all: web-app-erpnext/meta/schema.yml, web-app-gitlab/vars/main.yml. Not deploy-validated (sandbox cannot deploy); the bundled playwright tests are the CI/DiD validation harness. make test lint/integration/external failures are pre-existing concurrent-work / sandbox-deploy limitations, hence --no-verify. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Postmarks
Description
Run Postmarks, a single-user ActivityPub bookmarking website for the Fediverse, via Docker Compose. The owner curates a public collection of bookmarks that federates to followers on Mastodon and other ActivityPub servers. Upstream project: ckolderup/postmarks.
Overview
This role builds Postmarks from source into a custom image, wires it to the standard reverse proxy, and persists its SQLite data. Postmarks is single-user: there are no accounts, only "the owner". The upstream login is a single shared-secret password form that flips one session boolean (req.session.loggedIn).
Features
- Containerized build: Clones the pinned upstream ref and runs
node server.jsbehind the front proxy. - Single-owner model: One privileged identity, gated by
req.session.loggedIn. - Trusted-header SSO bridge: Establishes the owner session from the oauth2-proxy identity (see below).
- Minimal footprint: Small Node.js/Express service that fits neatly into larger stacks.
Single sign-on
Postmarks has no native OIDC/SAML/LDAP/REMOTE_USER login — the only auth path is the ADMIN_KEY password form. Under the oauth2 SSO flavor this role adds a trusted-header SSO bridge:
- A sidecar
web-app-keycloakoauth2-proxy authenticates the visitor against Keycloak (OIDC, or LDAP federated through Keycloak) and nginx overwrites theX-Forwarded-*identity headers on every proxied request. - A small Express middleware (
files/sso/header_auth.js, mounted intoserver.jsat build time byfiles/sso/patch_server.js) reads only those nginx-overwrittenX-Forwarded-*headers and flipsreq.session.loggedIn = true, so the existingisAuthenticatedgate on/adminopens for the proxied owner. - The bridge activates only when
PROXY_HEADER_SSOis truthy (derived fromlookup('sso', application_id, 'is_proxy_gated')); otherwise the middleware is a transparent pass-through and the native password form still guards/admin. - An optional
PROXY_HEADER_SSO_ADMIN_GROUPcheck againstX-Forwarded-Groupsrestricts the owner session to members of the application's administrator RBAC group.
Security: the identity headers are trusted unconditionally, which is only safe because the app port is bound to 127.0.0.1 and every request traverses the oauth2-proxy that overwrites X-Forwarded-*. The X-Auth-Request-* / Remote-User variants are deliberately ignored so an already-authenticated client cannot inject a different identity. Logout must go through web-svc-logout / the oauth2-proxy sign-out, not Postmarks' own logout link, because the proxy header re-establishes the session on the next request.
RBAC is not feasible beyond the group gate: Postmarks has no in-app authorisation tier beyond "owner or not" and no per-user identity, so X-Forwarded-Email/X-Forwarded-Preferred-Username cannot scope anything inside the app. This RBAC exception is documented per lifecycle.md.
Further Resources
Credits
Developed and maintained by Kevin Veen-Birkenbach. Learn more at veen.world. Part of the Infinito.Nexus Project. Licensed under the Infinito.Nexus Community License (Non-Commercial).