Skip to content

[BUG] SSO redirect_uri uses http behind HTTPS reverse proxy #1188

Description

@adrianmusante

Prerequisites

Rclone Pre-flight Checklist (if applicable)

  • This issue is NOT related to rclone (skip if not using rclone)
  • I have tested rclone listremotes and rclone lsd remote: on the host and they work
  • I have verified the rclone config is mounted into the container
  • I have restarted the container after config changes

Bug Description

When Zerobyte runs behind an HTTPS reverse proxy that terminates TLS and forwards to the container over plain HTTP (typical Nginx / Nginx Proxy Manager setup), SSO/OIDC sign-in builds an OAuth redirect_uri with the http:// scheme even though:

  • BASE_URL is set to https://…
  • The proxy sends X-Forwarded-Proto: https (and X-Forwarded-Scheme: https)
  • TRUST_PROXY=true

Authentik (and most IdPs) only allow the HTTPS callback, so login fails with an invalid redirect URI.

Root cause appears to be better-auth config in app/server/lib/auth.ts:

  • baseURL.protocol is "auto"
  • advanced.trustedProxyHeaders is not set

Per better-auth docs, with protocol: "auto", X-Forwarded-Proto is only honored when advanced.trustedProxyHeaders: true. Otherwise the request URL scheme is used — which is http on the internal Docker network. TRUST_PROXY only affects X-Forwarded-For for rate limiting / IP handling; it does not enable trusted proxy headers for better-auth URL construction. BASE_URL is only used as a fallback, not for the live redirect_uri.

Steps to Reproduce

  1. Deploy Zerobyte v0.43.0 with Docker Compose behind a reverse proxy that terminates TLS and proxies to http://zerobyte:4096.

  2. Set env:

    • BASE_URL=https://zerobyte.example.com
    • TRUST_PROXY=true
    • TRUSTED_ORIGINS=https://zerobyte.example.com,https://auth.example.com
  3. Ensure the proxy sets Host, X-Forwarded-For, and X-Forwarded-Proto: https (NPM/nginx stock config does this).

  4. Configure an OIDC SSO provider (e.g. Authentik) with callback
    https://zerobyte.example.com/api/auth/sso/callback/<providerId> only.

  5. Start SSO sign-in, e.g.:

    curl -s -X POST 'https://zerobyte.example.com/api/auth/sign-in/sso' \
      -H 'Content-Type: application/json' \
      -d '{"providerId":"<providerId>","callbackURL":"/"}'
  6. Inspect the returned url → query param redirect_uri.

Expected Behavior

redirect_uri should use HTTPS, matching the public URL / BASE_URL scheme, e.g.:

redirect_uri=https://zerobyte.example.com/api/auth/sso/callback/<providerId>

One possible approach (happy to defer to maintainers): honor X-Forwarded-Proto when behind a reverse proxy (e.g. advanced.trustedProxyHeaders: true alongside TRUST_PROXY=true), or derive better-auth protocol from the scheme of BASE_URL instead of "auto".

Zerobyte version / commit

v0.43.0

Deployment Method

Docker Compose

Backup/Repository Context

N/A (SSO / auth only)

Logs / Error Messages

Response from POST /api/auth/sign-in/sso (sanitized; client_id / state / PKCE redacted):

{
  "url": "https://auth.example.com/application/o/authorize/?response_type=code&client_id=REDACTED&state=REDACTED&scope=openid+email+profile&redirect_uri=http%3A%2F%2Fzerobyte.example.com%2Fapi%2Fauth%2Fsso%2Fcallback%2Fauthentik&code_challenge_method=S256&code_challenge=REDACTED",
  "redirect": true
}

Decoded redirect_uri:

http://zerobyte.example.com/api/auth/sso/callback/authentik

Proxy headers on the same NPM stack (checked with a whoami-style upstream) include X-Forwarded-Proto: https. Sending that header explicitly to Zerobyte still produces http in redirect_uri.

Relevant config from upstream source:

baseURL: {
  allowedHosts: config.allowedHosts,
  protocol: "auto",
  fallback: config.baseUrl,
},
advanced: {
  cookiePrefix: "zerobyte",
  useSecureCookies: config.isSecure,
  // trustedProxyHeaders not set
  ipAddress: { ... },
},

IdP error (Authentik): redirect URI mismatch, only the HTTPS callback is registered.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions