Traefik + Oauth2-proxy : forwardauth middleware forgets URL

Hello,

when using oauth2-proxy in conjuction with traefik, it "works" but fails to redirect to the originating URL.

ForwardAuth with 401 errors middleware
The Traefik v2 ForwardAuth middleware allows Traefik to authenticate requests via the oauth2-proxy's /oauth2/auth endpoint on every request, which only returns a 202 Accepted response or a 401 Unauthorized response without proxying the whole request through. For example, on Dynamic File (YAML) Configuration:
Src: Overview | OAuth2 Proxy

Apparently the issue lays with traefik not forwarding the proper URL so that the user gets redirected to the original intended URL if I understand correctly.

Has anyone found a way around this ? (the example in oauth2-proxy seems to just be intended to show-case the bug).

Thanks in advance for your help.

my current implementation is the following:

POC service :

  whoami-monitoring:
    image: "traefik/whoami"
    container_name: "whoami-monitoring"
    networks:
      - internal
      - docker-proxy-internal
    labels:
            traefik.enable: true
            traefik.docker.network: traefik-proxy

            traefik.http.routers.whoami-web.rule: Host(`whoami.${DOMAIN?err}`) && PathPrefix(`/foo`)
            traefik.http.routers.whoami-web.priority: 90
            traefik.http.routers.whoami-web.middlewares: oauth-chain
            traefik.http.routers.whoami-web.entrypoints: websecure
            traefik.http.routers.whoami-web.service: whoami-web
            traefik.http.services.whoami-web.loadbalancer.server.port: 80

            traefik.http.routers.whoami-jump.rule: Host(`whoami.${DOMAIN?err}`) && PathPrefix(`/bar`)
            traefik.http.routers.whoami-jump.priority: 80
            traefik.http.routers.whoami-jump.middlewares: restrict-chain
            traefik.http.routers.whoami-jump.entrypoints: websecure
            traefik.http.routers.whoami-jump.service: whoami-jump
            traefik.http.services.whoami-jump.loadbalancer.server.port: 80


oauth2 service :

  oauth2:
          #image: quay.io/pusher/oauth2_proxy:${OAUTH2_PROXY_VERSION}
    image: quay.io/oauth2-proxy/oauth2-proxy:v7.2.1
    container_name: "oauth"
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "wget", "--tries=1", "--spider", "http://oauth:4180/ping"]
      interval: 60s
      timeout: 10s
    labels:
      ai.ix.expose: 'true'
      traefik.enable: 'true'
      traefik.http.middlewares.oauth-verify.forwardAuth.address: http://oauth:4180/oauth2/auth
      traefik.http.middlewares.oauth-verify.forwardAuth.trustForwardHeader: 'true'
      traefik.http.middlewares.oauth-verify.forwardAuth.authResponseHeaders: X-Auth-Request-User,X-Auth-Request-Email,Set-Cookie,X-Auth-User,X-Secret
      traefik.http.middlewares.oauth-signin.errors.service: oauth@docker
      traefik.http.middlewares.oauth-signin.errors.status: '401'
      traefik.http.middlewares.oauth-signin.errors.query: /oauth2/sign_in
      traefik.http.routers.oauth.entrypoints: websecure
      traefik.http.routers.oauth.rule: Host(`oauth.${DOMAIN?err}`) || PathPrefix(`/oauth2`)
      traefik.http.routers.oauth.tls.certResolver: myresolver
      traefik.http.routers.oauth.service: oauth@docker
      traefik.http.services.oauth.loadbalancer.server.port: '4180'
    environment:
            # https://oauth2-proxy.github.io/oauth2-proxy/docs/configuration/overview/#environment-variables
      OAUTH2_PROXY_PROVIDER: gitlab
      OAUTH2_PROXY_GITLAB_GROUP: ${OAUTH2_PROXY_GITLAB_GROUP}
      OAUTH2_PROXY_CLIENT_ID: ${OAUTH2_PROXY_CLIENT_ID?err}
      OAUTH2_PROXY_CLIENT_SECRET: ${OAUTH2_PROXY_CLIENT_SECRET?err}
      OAUTH2_PROXY_COOKIE_DOMAINS: ${DOMAIN?err}
      OAUTH2_PROXY_COOKIE_REFRESH: '1h'
      OAUTH2_PROXY_COOKIE_SECURE: 'false'
      OAUTH2_PROXY_COOKIE_SECRET: ${OAUTH2_PROXY_COOKIE_SECRET?err}
      OAUTH2_PROXY_COOKIE_HTTPONLY: 'true'
      OAUTH2_PROXY_COOKIE_NAME: '_oauth2_proxy'
      OAUTH2_PROXY_EMAIL_DOMAINS: '*'
      OAUTH2_PROXY_FOOTER: '-'
      OAUTH2_PROXY_HTTP_ADDRESS: '0.0.0.0:4180'
      OAUTH2_PROXY_PASS_BASIC_AUTH: 'false'
      OAUTH2_PROXY_PASS_USER_HEADERS: 'true'
      OAUTH2_PROXY_REVERSE_PROXY: 'true'
      OAUTH2_PROXY_SET_AUTHORIZATION_HEADER: 'true'
      OAUTH2_PROXY_SET_XAUTHREQUEST: 'true'
      OAUTH2_PROXY_WHITELIST_DOMAINS: '.${DOMAIN?err}'
      OAUTH2_PROXY_REDIRECT_URL: "https://oauth.${DOMAIN}/oauth2/callback"
    networks:
      - internal
      - docker-proxy-internal

  traefik:
    image: traefik:latest
    container_name: "traefik"
    command:
      - --log.level=DEBUG
      - --api.dashboard=true
      - --api.insecure=true
       # Do not expose all Docker services by default
      - --providers.docker=true
      - --providers.docker.exposedbydefault=false
      #- "--providers.docker.endpoint=unix:///var/run/docker.sock"
      - --providers.docker.endpoint=tcp://proxy:2375
      - --providers.docker.network=traefik-proxy

        # DNS Challenge (domain.tld and *.domain.tld DNS zones are defined there) : hetzner
      #- "--certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
      - --certificatesresolvers.myresolver.acme.email=postmaster@${SERVER_HOSTNAME}
      - --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
      - --certificatesresolvers.myresolver.acme.dnschallenge=true
      - --certificatesresolvers.myresolver.acme.dnschallenge.delaybeforecheck=0
      - --certificatesresolvers.myresolver.acme.dnschallenge.provider=hetzner
      - --certificatesresolvers.myresolver.acme.dnschallenge.resolvers=helium.ns.hetzner.de,hydrogen.ns.hetzner.com,oxygen.ns.hetzner.com

        # HTTPS : port 443, with letsencrypt certificates provided by myresolver
      - --entrypoints.websecure.address=:443
      - --entrypoints.websecure.http.tls=true
      - --entrypoints.websecure.http.tls.certResolver=myresolver
        #- --entrypoints.websecure.http.tls.domains[0].main=${SERVER_HOSTNAME}
        #- --entrypoints.websecure.http.tls.domains[0].sans=*.${SERVER_HOSTNAME}
      - --entrypoints.websecure.http.tls.domains[0].main=${CERT_DOMAIN}
      - --entrypoints.websecure.http.tls.domains[0].sans=*.${CERT_DOMAIN}
      - --entrypoints.websecure.http.tls.domains[1].main=${SERVER_HOSTNAME}
      - --entrypoints.websecure.http.tls.domains[1].sans=*.${SERVER_HOSTNAME}
        # staging letsencrypt (no quotas, but self signed certificates), comment to move to prod
      #- --certificatesresolvers.myresolver.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
      #- "--providers.docker.defaultRule=Host(`{{ .Name }}.{{ index .Labels \"customLabel\"}}`)"

        # Redirect HTTP (web) to HTTPS (websecure)
      - --entrypoints.web.address=:80
      - --entrypoints.web.http.redirections.entryPoint.to=websecure
      - --entrypoints.web.http.redirections.entryPoint.scheme=https
      - --entrypoints.web.http.redirections.entrypoint.permanent=true

        # Expose prometheus metrics on port 8082 (rerouted by labels)
      - --metrics.prometheus=true
      - '--metrics.prometheus.buckets=0.1,0.3,1.2,5.0'
      - --metrics.prometheus.addrouterslabels=true
      - --metrics.prometheus.addServicesLabels=true
      - --metrics.prometheus.addEntryPointsLabels=true
      - --entryPoints.metrics.address=:8082
      - --metrics.prometheus.entryPoint=metrics
      - --metrics.prometheus.manualrouting=true
      - --accesslog=true

      # entrypoint for mezos through load-balancers on ${trustedIPs}
      - --entryPoints.mainnet-mezos-lb.address=:39090
     #- --entryPoints.mainnet-mezos-lb.proxyProtocol.insecure
      - --entryPoints.mainnet-mezos-lb.proxyProtocol.trustedIPs=${trustedIPs}
      - --entryPoints.mainnet-mezos-lb.http.tls=false

      # entrypoint for graphic-proxy through load-balancers on ${trustedIPs}
      - --entryPoints.mainnet-graphic-proxy-lb.address=:49090
     #- --entryPoints.mainnet-graphic-proxy.proxyProtocol.insecure
      - --entryPoints.mainnet-graphic-proxy-lb.proxyProtocol.trustedIPs=${trustedIPs}
      - --entryPoints.mainnet-graphic-proxy-lb.http.tls=false

      # Writing Logs to a File
      # - "--log.filePath=/logs/traefik.log"
      # Writing Logs to a File, format = common or json
      #- "--log.format=common"
      # Acepted log levels = DEBUG, PANIC, FATAL, ERROR, WARN, and INFO
      - "--log.level=DEBUG"
        #- "--tracing=true"
      - "--pilot.token=${traefik_pilot_token}"
    environment:
      - HETZNER_API_KEY=${traefik_DNS_cert_Hetzner_API_Key:-notset}
    restart: always
    ports:
      - "80:80"
      - "443:443"
      - "39090:39090"
      - "49090:49090"
        #- "8080:8080" default for dashboard, routed to https with labels
        #- "8082:8082" set for prometheus, rerouted to http with labels
    volumes:
      - traefik-letsencrypt:/letsencrypt
      - traefik-logs:/logs
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
    networks:
      - internal
      - docker-proxy-internal

    labels:
      #"traefik.frontend.rule: HostRegexp(`{catchall:.*}`)"
      traefik.enable: true
      # prometheus exporter
      traefik.http.routers.traefikmetrics.rule: Host(`traefik-metrics.${SERVER_HOSTNAME}`)
      traefik.http.routers.traefikmetrics.entrypoints: websecure
      traefik.http.routers.traefikmetrics.service: prometheus@internal
      traefik.http.services.traefikmetrics.loadbalancer.server.port: 8082
      traefik.http.routers.traefikmetrics.tls.certresolver: myresolver
      traefik.http.routers.traefikmetrics.middlewares: restrict-chain
      # traefik dasboard
      traefik.http.routers.api.rule: Host(`traefik.${SERVER_HOSTNAME}`) && (PathPrefix(`/api`) || PathPrefix(`/dashboard`))
      traefik.http.routers.api.entrypoints: websecure
      traefik.http.routers.api.service: api@internal
      traefik.http.services.api.loadbalancer.server.port: 8080
      traefik.http.routers.api.tls.certresolver: myresolver
      traefik.http.routers.api.middlewares: oauth-chain

      traefik.http.middlewares.default-compress.compress: 'true'

      traefik.http.middlewares.default-http.redirectScheme.scheme: https
      traefik.http.middlewares.default-http.redirectScheme.permanent: 'true'

      traefik.http.middlewares.default-https.chain.middlewares: default-compress

      traefik.http.middlewares.oauth-chain.chain.middlewares: default-https,oauth-signin,oauth-verify
      traefik.http.middlewares.restrict-chain.chain.middlewares: default-https,ip-whitelist

      traefik.http.middlewares.ip-whitelist.ipwhitelist.sourcerange: "127.0.0.1/32, ${monitoring_server_ip}"

Hello, did you solve the problem ? i have the same issue ...

Have a good day

Hello,
yes, I struggled a bit and found the workaround from @jonananas :

I would also suggest following @mariawitch changes following Not routing back to original URL (if not previously logged-in) · Issue #1639 · oauth2-proxy/oauth2-proxy · GitHub