• Stefy Lanza (nextime / spora )'s avatar
    front: forward-auth peers from env, and say why one was refused (v0.2.88) · 0945f123
    Stefy Lanza (nextime / spora ) authored
    The Digesta host reported SSO minting a session from inside the container
    (:8776) but refusing from the host through the published port (:8777), with the
    container's address in trusted_proxies and the front's own access log showing
    that very address as the client. Both that and "enabled: true in config.json
    did not switch the feature on" are one cause.
    
    The peer _fa_trusted checks is not the socket peer: uvicorn installs
    ProxyHeadersMiddleware by default with trusted_hosts="127.0.0.1", so a hop
    arriving over loopback from the internal nginx has scope["client"] rewritten
    from X-Forwarded-For before any of our middleware runs. On a container network
    that is the address the proxy was SNATed to. So the log and the check agreed and
    the peer really was 10.89.0.178 -- but the list it was compared against was the
    DEFAULT ["127.0.0.1", "::1"], because their config.json sat at a path the app
    does not read (the $CODERAI_CONFIG_DIR/coderai trap), which is equally why the
    file's `enabled` did nothing and the env var was needed. Loopback is in that
    default; the container address is not.
    
    The loader is fine and `enabled` from the file does suffice -- verified, not
    assumed. What was missing was a way to supply the peers the same way the switch
    and the secret can already be supplied, so CODERAI_ADMIN_FORWARD_AUTH_TRUSTED_
    PROXIES now overrides the list; blank or unset falls through to config.json.
    Enabling the feature from a unit file and then having it reject every request
    from your own proxy was a gap in the contract.
    
    And a refusal now says why, once per peer and reason per 60s, naming the list it
    was checked against and never the secret. A refusal is a 302 to the login form,
    indistinguishable from "no session yet"; the report had to ask for exactly this
    instrumentation, so it is permanent now.
    
    tests/test_forward_auth_peer_trust.py reproduces the peer resolution for all
    three hops, so the table in the doc is executable rather than reasoned.
    Co-Authored-By: 's avatarClaude Opus 5 <noreply@anthropic.com>
    0945f123
__init__.py 4.21 KB