Add SSO cookie vendor endpoint for native apps behind auth proxies - #7127
Add SSO cookie vendor endpoint for native apps behind auth proxies#7127nathanmoreton wants to merge 10 commits into
Conversation
…proxies Implements the server-side pieces of Bitwarden's SSO cookie vending flow (upstream PRs bitwarden/server#6880, dani-garcia#6892, dani-garcia#6903) so the native Bitwarden mobile and desktop apps work when Vaultwarden sits behind an authenticating reverse proxy such as Cloudflare Access, Authentik, Authelia, or oauth2-proxy. Without this, users behind such a proxy can authenticate the web vault in a browser but the native apps 404 on /api/sso-cookie-vendor after the browser-assisted IdP step, leaving the app unable to acquire the proxy's auth cookie. What's added: * New config section `sso_cookie_vendor` (4 fields, default-off) driving both env-var and admin-UI configuration via the existing make_config! macro, with startup validation. * GET /api/sso-cookie-vendor — reads the proxy auth cookie from the request (including sharded variants CF_Authorization-0..19) and 302-redirects to bitwarden://sso-cookie-vendor?<cookie>=<value>&d=1 so the native app can capture and reuse the cookie. Upstream-compatible 404/400/500 HTML error pages; 8192-byte URI cap. * communication.bootstrap block in /api/config matching the shape from bitwarden/server#6892 so clients discover the flow without modification. * Unit tests covering single/sharded cookies, precedence, missing-cookie 404, URL-encoding, oversize URI, and error HTML format. See docs/sso-cookie-vendor.md for the full writeup (background, security considerations, end-to-end flow, and per-proxy configuration notes).
|
Thx for this work ! Can't wait to see it arrive. |
The rebase onto upstream main bumped rust-toolchain to 1.95, which flagged two things the 1.94 compiler didn't catch: - rustfmt collapses build_redirect_uri's signature onto one line - clippy's collapsible_if catches the nested if in validate_config Style only, no behavior change.
|
@dani-garcia What is needed to get this reviewed and approved? |
|
Highly interested in getting this merged as well, since without it it does feel a tad more insecure with just Bitwarden itself, and I'd love to enable Cloudflare Access after all. Any way the merge could be facilitated? |
|
Please focus on this PR, I don't feel super great at having vaultwarden exposed without a SSO on the reverse proxy, but having it currently break the android app so i need vualtwarden with a less restricted access ... |
Resolve conflict in src/api/core/mod.rs: upstream grouped `pub mod` declarations at the top (moving `pub mod two_factor;`), so keep only the new `mod sso_cookie_vendor;` declaration among the private modules. Reformat the SSO code for the Edition 2024 / Rust 1.96 rustfmt rules introduced upstream (dani-garcia#7200): import ordering in sso_cookie_vendor.rs and the multi-line err!() in config.rs validation.
|
Please we need this PR to be merged, it is not ideal to keep the app exposed to public access |
|
Can we please get an update on how far away this is? |
|
Would you be kind enough to please review and merge this PR. |
Upstream added a "communication": null placeholder for bitwarden/server#6892 after this branch last merged main. Combined with this PR's populated "communication" key, serde_json's json! macro keeps the last duplicate key, so the null silently overwrote the ssoCookieVendor bootstrap block and native clients never saw it. Keep only the populated key.
|
Does this also apply to the extension? Or does the extension already share the browser cookie store? |
I am self-hosting and my extension is working. I believe the extension shares the browser cookie, so I think it works without this update as well, but I'm not entirely sure. If your extension isn't working, go to your vault url in a new tab and go through the zero trust auth so your browser grabs a new cookie and it may start working. |
|
@dani-garcia @BlackDex can we get someone to look at this request? I have been using it behind cloudflare zero trust for months with no problems syncing the mobile app. This solved a problem a lot of people have. |
|
@nathanmoreton how do the clients handle cf access session expiry/revocation in your experience? Do they prompt you to sign in again? |
Yes, the mobile app already did that. It prompts for you to launch a browser and sign in when your cookie expires. This bug fix is to allow vaultwarden to properly route the cookie back to the app when it detects the request comes from a mobile app. |
|
Good info, thanks. @BlackDex this seems simple enough, what's with the 4 month delay for review? This is the single best improvement, security wise. |
|
@BlackDex Can you look at this soon? It would be awesome for security and ease of setup. |
Native Bitwarden apps cannot complete login when Vaultwarden sits behind an authenticating reverse proxy (Cloudflare Access, Authentik, Authelia, oauth2-proxy). The proxy redirects API requests to a browser-based IdP flow, which the apps' HTTP clients cannot follow.
Bitwarden addressed this upstream in February 2026 with a flow called SSO cookie vending. The server publishes, through
/api/config, acommunication.bootstrapblock naming the IdP login URL and the cookie the proxy sets. The app opens a system browser for the IdP step, the browser hits/api/sso-cookie-vendor, and the server 302-redirects tobitwarden://sso-cookie-vendor?<name>=<value>&d=1. The app captures the cookie from the deep link and attaches it to every future API request.Vaultwarden v2026.2.0 shipped the web-vault connector page from
clients#18476, but the server side has not landed. This PR adds it.Changes
sso_cookie_vendorthrough the existingmake_config!macro:SSO_COOKIE_VENDOR_ENABLED,SSO_COOKIE_VENDOR_IDP_LOGIN_URL,SSO_COOKIE_VENDOR_COOKIE_NAME,SSO_COOKIE_VENDOR_COOKIE_DOMAIN. Startup validation refuses to run when the flag is on but the three string fields are empty.GET /api/sso-cookie-vendorreads the proxy auth cookie from the request jar and 302-redirects to thebitwarden://deep link. Handles sharded cookies (<name>-0through<name>-19, which Cloudflare Access uses when the JWT exceeds single-cookie size limits), with a non-sharded cookie taking precedence. Missing cookie returns the upstream 404 HTML page; URIs over 8192 bytes return 400. Registered only when the flag is on.communication.bootstrapobject added to/api/config, matching the shape from upstream PR apply policies only to confirmed members #6892 so clients pick it up unpatched.docs/sso-cookie-vendor.mdcovers the end-to-end flow, security notes, and per-proxy configuration.Default behavior
SSO_COOKIE_VENDOR_ENABLEDdefaults tofalse. Installs without the four env vars set are byte-identical to current behavior.Upstream references
/api/configbitwarden/server#6892: expose config in/api/configTest plan
cargo fmt --checkcargo clippy --features sqlite -- -D warningscargo test --features sqlite -- sso_cookie_vendor