Skip to content

X-User, X-Email, X-Group headers are not sent to services with non-public policies despite OIDC gate ALLOW #1

@umnaut

Description

@umnaut

Hello!
I have a service that is gated behind PERMITTED_GROUPS env. Despite a successful OID Connect flow, my endpoint service never sees X- headers.

When I attempt to access through a browser, I am redirected to my IDP logon page, I get an _oauth2_proxy cookie, I see the OIDC gate ALLOW log message in nginx-proxy logs, and I can access the service. All of that seems to be working correctly.

*17 js: OIDC gate ALLOW (group=3d871b76-5d0c-4d03-9efc-ce3da5e6ad80) host=debug.censored.local uri=/__gate rule=/

But my service never gets the X-User, X-Email, or X-Groups headers. Similarly my browser never sees the X-Authz* headers in the response.

For testing, I've commented out internal from vhost.d/default's /__oauth2_auth and /__gate locations and curled them with a valid _oauth2_proxy cookie. They are returning the expected headers, so I don't believe the issue is with oauth2-proxy config:

docker compose exec proxy curl -vk -H "Cookie: _oauth2_proxy=$COOKIE"  \
  https://debug.censored.local/__gate
...
* Request completely sent off
< HTTP/2 200 
< server: nginx/1.29.1
< date: Wed, 17 Sep 2025 22:28:43 GMT
< content-type: application/octet-stream
< content-length: 0
< x-authz-debug-host: debug.censored.local
< x-authz-debug-uri: /__gate
< x-authz-debug-method: GET
< x-authz-debug-user: Tlpg9wsdeZWp7f_JKH1p0KimsJLa56NjYKrMUrupiEg
< x-authz-debug-email: [email protected]
< x-authz-debug-groups: cb05ea35-a763-4d01-a49b-8447f0060d34,3d871b76-5d0c-4d03-9efc-ce3da5e6ad80,44a4eaf9-9d5c-45b3-9c44-f88c409e9028
< x-authz-debug-matched-path: /
< x-authz-debug-matched-public: false
< x-auth-request-user: Tlpg9wsdeZWp7f_JKH1p0KimsJLa56NjYKrMUrupiEg
< x-auth-request-email: [email protected]
< x-auth-request-groups: cb05ea35-a763-4d01-a49b-8447f0060d34,3d871b76-5d0c-4d03-9efc-ce3da5e6ad80,44a4eaf9-9d5c-45b3-9c44-f88c409e9028
< strict-transport-security: max-age=31536000
docker compose exec proxy curl -vk -H "Cookie: _oauth2_proxy=$COOKIE" \
  https://debug.censored.local/__oauth2_auth
...
< HTTP/2 202 
< server: nginx/1.29.1
< date: Wed, 17 Sep 2025 22:29:01 GMT
< content-length: 0
< gap-auth: [email protected]
< x-auth-request-access-token: censored
< x-auth-request-email: [email protected]
< x-auth-request-groups: cb05ea35-a763-4d01-a49b-8447f0060d34,3d871b76-5d0c-4d03-9efc-ce3da5e6ad80,44a4eaf9-9d5c-45b3-9c44-f88c409e9028
< x-auth-request-preferred-username: [email protected]
< x-auth-request-user: Tlpg9wsdeZWp7f_JKH1p0KimsJLa56NjYKrMUrupiEg
< strict-transport-security: max-age=31536000

I do also have a fork of nginx-proxy/acme-companion (step-ca-companion) running and able to modify my nginx configs to support ACME cert generation and deployment, so perhaps the issue is with the final configs?

My vhost.d/default and default_location files are identical to the ones in this repo (except internal being commented for testing)

Here's everything related to debug.censored.local in dumped nginx configs:

# debug.censored.local/
upstream debug.censored.local {
    # Container: apps-debug-1
    #     networks:
    #         apps_proxy-internal-general (reachable)
    #     IPv4 address: 172.24.0.2
    #     IPv6 address: (none usable)
    #     exposed ports (first ten): 5000/tcp
    #     default port: 5000
    #     using port: 5000
    server 172.24.0.2:5000;
    keepalive 2;
}
server {
    server_name debug.censored.local;
    access_log /var/log/nginx/access.log vhost;
    listen 80;
    # Do not HTTPS redirect Let's Encrypt ACME challenge
    location ^~ /.well-known/acme-challenge/ {
        auth_basic off;
        auth_request off;
        allow all;
        root /usr/share/nginx/html;
        try_files $uri =404;
        break;
    }
    location / {
        if ($request_method ~ (OPTIONS|POST|PUT|PATCH|DELETE)) {
            return 301 https://$host$request_uri;
        }
        return 301 https://$host$request_uri;
    }
}
server {
    server_name debug.censored.local;
    # From container env PERMITTED_GROUPS (CSV/space separated OK)
    set $required_group "3d871b76-5d0c-4d03-9efc-ce3da5e6ad80,prv-rt";
    access_log /var/log/nginx/access.log vhost;
    http2 on;
    listen 443 ssl;
    ssl_session_timeout 5m;
    ssl_session_cache shared:SSL:50m;
    ssl_session_tickets off;
    ssl_certificate /etc/nginx/certs/debug.censored.local.crt;
    ssl_certificate_key /etc/nginx/certs/debug.censored.local.key;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/nginx/certs/debug.censored.local.chain.pem;
    set $sts_header "";
    if ($https) {
        set $sts_header "max-age=31536000";
    }
    add_header Strict-Transport-Security $sts_header always;
    include /etc/nginx/vhost.d/default;
    location / {
        proxy_pass http://debug.censored.local;
        set $upstream_keepalive true;
        include /etc/nginx/vhost.d/default_location;
    }
}

I really appreciate everything you've done with this project. It's gotten me 90% of the way to adding header-based SSO to a webapp. I'm not too familiar with nginx configuration so this has been quite difficult for me to troubleshoot. I've been stuck on this issue for days, though, so any insight or help would mean to world to me.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions