Skip to content

Conversation

@SerbNerd
Copy link

Summary

Replaces manual oidc_redirect_https setting with automatic HTTP/HTTPS protocol detection using Uvicorn's --proxy-headers flag. OIDC now works
seamlessly for both local (http) and external (https) access simultaneously.

Problem

Users accessing AudioBookRequest through multiple methods (local HTTP via VPN, external HTTPS via reverse proxy) couldn't use OIDC because the manual setting forced a single protocol for all access paths.

Solution

Leverages Uvicorn's built-in --proxy-headers flag to automatically detect protocol from incoming requests:

  • Direct access: Uses actual request protocol (http for local)
  • Proxied access: Reads X-Forwarded-Proto header from trusted proxies (https)

Changes

  • Add --proxy-headers flag to Dockerfile with configurable FORWARDED_ALLOW_IPS
  • Remove manual protocol override logic from auth routes
  • Remove oidc_redirect_https setting from UI, API, and database
  • Add proxy header validation with security error messages
  • Add security warning when proxy headers detected with permissive IP config
  • Update OIDC documentation with reverse proxy configuration guide
  • Database migration to clean up deprecated setting

Configuration

Default: Works out-of-the-box, trusts all proxy IPs (0.0.0.0/0)

Production (Optional): Set FORWARDED_ALLOW_IPS env var to trust specific proxy IPs only

Testing

  • Local access (http://192.168.x.x): Generates http redirect URI ✓
  • External access (https://domain.com): Generates https redirect URI ✓
  • Both work simultaneously without manual configuration ✓
  • No oidc_redirect_https setting in UI ✓
  • Untrusted proxy headers return 403 with error ID ✓

Notes

  • Defaults to allowing all proxy IPs for ease of use in self-hosted environments
  • Production users can set FORWARDED_ALLOW_IPS for additional security
  • Warning logs guide users toward secure configuration
  • Basic rejection logged at INFO level; detailed debug info at DEBUG level

Disclaimer: Encountered this issue on my personal setup - used Claude Code to speed up implementation but thoroughly reviewed and tested all changes.
Hope this helps others facing the same OIDC + reverse proxy challenge!

  Replaces manual oidc_redirect_https setting with automatic detection via
  Uvicorn's --proxy-headers flag. OIDC now works for both local (http) and
  external (https) access simultaneously.

  Changes:
  - Add --proxy-headers and --forwarded-allow-ips flags to Dockerfile
  - Remove oidc_redirect_https setting from UI and backend
  - Add database migration to clean up deprecated setting
  - Add proxy header validation to auth routes

  Security:
  - Validates proxy headers come from trusted IPs
  - Returns 403 with error ID if headers from untrusted source
  - Logs details at INFO level for troubleshooting
  - Detailed debug info available at DEBUG log level
Copy link
Owner

@markbeep markbeep left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. Haven't thought about the use-case of requiring both http and https redirects interchangeably. As this is strongly dependent on your proxy setup, I believe there still should be an option to force the redirect to use http or https. It's possible for a proxy to not correctly relay the scheme used. While this can sometimes be chalked up to incorrect configuration, I find it doesn't hurt to have an option to aid with whatever setup you have.

I suggest instead of completely removing the oidc_redirect_https option, to instead rename it into a force_oidc_redirect_https which is an optional boolean. If you toggle it off, it will try to determine the scheme automatically like you have done, but if enabled it will use the set option. Then create a database migration that simply moves the old value to this new key, to make any transition seamless. Any new setups will then default to using the dynamic approach, while old setups will continue working the exact same as before.

At the end, also add any new env variable to the env variables section in the readme and in the docs (docs/content/docs/concepts/environment-variables.md)

# ===== SECURITY WARNING: Proxy Headers with Permissive Config =====
# Warn if proxy headers are detected but FORWARDED_ALLOW_IPS allows all IPs
if request.headers.get("X-Forwarded-Proto"):
forwarded_allow_ips = os.getenv("FORWARDED_ALLOW_IPS", "0.0.0.0/0")
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use os.getenv. Add env variables to app/internal/env_settings.py. They get properly type checked that way and are all in one place.

"FORWARDED_ALLOW_IPS is set to allow all IPs (0.0.0.0/0). "
"For production use, set FORWARDED_ALLOW_IPS to your reverse proxy IP(s) only. "
"This prevents header spoofing attacks. "
"See documentation: https://github.com/markbeep/AudioBookRequest/docs/oidc"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This warning is a bit odd. For one, https://github.com/markbeep/AudioBookRequest/docs/oidc doesn't exist.

But if any validation is required for the forwarded_allow_ips, you can add it to app/internal/env_settings.py by for example adding a check at the bottom under the class definitions that does something like the following:

class Settings(BaseSettings): ...

# validate forwarded_allow_ips
if Settings().app.forwaded_allow_ips in ("0.0.0.0/0", "*"):
    raise ValueError(...)

Then the env error/warning is shown on startup.


# DEBUG: Show the redirect URI being sent to token endpoint
logger.debug(
"OIDC_CALLBACK_REDIRECT_URI_DEBUG",
Copy link
Owner

@markbeep markbeep Jan 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to capitalize, combine strings with underscore, nor add "DEBUG" at the end.

Instead, indicate what is going on or has happened in the message. For example, "Validating code on token endpoint" or similar.

Same goes for the above log messages.

# docker-compose.yml
services:
abr:
image: ghcr.io/markbeep/audiobookrequest:latest
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Audiobookrequest doesn't exist on ghcr.io
  2. Don't show latest in the docs. Instead put a major version like :1

Comment on lines +54 to +61
- ✅ Works out-of-the-box for all reverse proxies
- ✅ Great for home labs and self-hosted setups
- ⚠️ Less secure on shared infrastructure (susceptible to header spoofing)

If you see this warning in your logs:
```
🔐 SECURITY WARNING: Proxy headers detected (X-Forwarded-Proto) but
FORWARDED_ALLOW_IPS is set to allow all IPs (0.0.0.0/0).
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please no emojis ✨

Comment on lines +1 to +8
{
"permissions": {
"allow": [
"Bash(fastapi --help:*)",
"Bash(uv run fastapi run --help:*)"
]
}
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't push this please.

ENV ABR_APP__VERSION=$VERSION

CMD /app/.venv/bin/alembic upgrade heads && /app/.venv/bin/fastapi run --port $ABR_APP__PORT
CMD ["/bin/sh", "-c", "/app/.venv/bin/alembic upgrade heads && /app/.venv/bin/fastapi run --port $ABR_APP__PORT --proxy-headers --forwarded-allow-ips=\"${FORWARDED_ALLOW_IPS:-0.0.0.0/0}\""]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After adding the env var to the env_settings.py file, you'll have to adjust it here as well.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants