Laravel login redirects back to /login with _token, email, password in query string

Hi,

After submitting the login form in a Laravel application (running behind Traefik as a reverse proxy), instead of being authenticated the user is redirected back to /login with URL parameters like _token=...&email=...&password=....

image

The cookies (laravel_session, XSRF-TOKEN) are being set and sent correctly (HttpOnly + Secure + SameSite=Lax), but Laravel does not seem to persist the session.

I have already configured APP_URL, SESSION_DOMAIN, SESSION_SECURE_COOKIE, and TrustProxies.

Traefik and the Laravel application are running as separate containers in Docker. Everything is hosted on an Ubuntu server as part of a training setup.

This also happens after logging out of the application.

Below are my current settings (they may look a bit strange because I tried several different configurations already). Unfortunately, nothing worked. I couldn’t find a similar case online, so I’m asking for help.

Traefik docker-compose

networks:
  network_name:
    external: true
    name: network_name

services:
  traefik:
    container_name: traefik
    image: traefik:latest
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./letsencrypt:/letsencrypt
    command: |
      --api.dashboard=true
      --api.insecure=false
      --providers.docker=true
      --providers.docker.exposedbydefault=false
      --providers.docker.network=network_name
      --entrypoints.web.address=:80
      --entrypoints.websecure.address=:443
      --certificatesresolvers.myresolver.acme.httpchallenge=true
      --certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web
      --certificatesresolvers.myresolver.acme.email=${ACME_EMAIL}
      --certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json
    ports:
      - 80:80
      - 443:443
    networks:
      - network_name
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.traefik.rule=Host(\"${APP_TRAEFIK_HOST}\")"
      - "traefik.http.routers.traefik.entrypoints=websecure"
      - "traefik.http.routers.traefik.tls.certresolver=myresolver"
      - "traefik.http.routers.traefik.service=api@internal"
      - "traefik.http.routers.traefik.middlewares=auth"

      - "traefik.http.routers.traefik.middlewares=auth@docker,secure-headers@docker"

      - "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
      - "traefik.http.middlewares.secure-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
      - "traefik.http.middlewares.secure-headers.headers.sslRedirect=true"

Aplication, docker-compose

services:
  nginx:
    build:
      context: ./.docker
      dockerfile: nginx.dockerfile
      args:
        - UID=${UID:-1000}
        - GID=${GID:-1000}
    volumes:
      - ./src:/var/www:delegated
    depends_on:
      - php-fpm
      - mysql
    networks:
      - network_name
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=network_name"
    
      # Router
      - "traefik.http.routers.project-name-nginx-secure.rule=Host(`${APP_HOST}`)"
      - "traefik.http.routers.project-name-nginx-secure.entrypoints=websecure"
      - "traefik.http.routers.project-name-nginx-secure.tls.certresolver=myresolver"

      - "traefik.http.middlewares.project-name-headers.headers.sslredirect=true"
      - "traefik.http.middlewares.project-name-headers.headers.stsseconds=315360000"
      - "traefik.http.middlewares.project-name-headers.headers.stsincludesubdomains=true"
      - "traefik.http.middlewares.project-name-headers.headers.stspreload=true"
      - "traefik.http.routers.project-name-nginx-secure.middlewares=project-name-headers"


  php-fpm:
    container_name: project-name-php-fpm
    hostname: project-name-php-fpm
    build:
      context: ./.docker
      dockerfile: php.dockerfile
      args:
        - UID=${UID:-1000}
        - GID=${GID:-1000}
    ports:
      - "9001:9000"
    volumes:
      - ./src:/var/www:delegated
    networks:
      - network_name


Nginx, .conf

server {
    listen 80;
    index index.php;
    server_name _;
    root /var/www/public;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass .project-name-php-fpm:9000;
        fastcgi_index index.php;
        include fastcgi_params;

        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;

        fastcgi_param HTTPS $https if_not_empty;
        fastcgi_param HTTP_X_FORWARDED_PROTO $http_x_forwarded_proto;
        fastcgi_param HTTP_X_FORWARDED_HOST $host;
        fastcgi_param HTTP_X_FORWARDED_FOR $proxy_add_x_forwarded_for;

        fastcgi_read_timeout 300;
    }
}

I would recommend to use to-https redirect globally on entrypoint, also assign the certResolver globally, and remove most of your middleware (sslredirect), check simple Traefik example.

Not sure why you set X-Forwarded-Proto, as it's set automatically by Traefik.

Thanks for the link. I'll compare both configurations tomorrow, make some changes, and let you know how it goes.
I added X-Forwarded-Proto because I thought it might be causing the problem (maybe a silly idea).
I suspect Laravel might be rejecting sessions or CORS requests, or there might be an SSL-related issue.

Enable and check Traefik debug log (doc), any "ERR" in logs? Enable and check Traefik access log in JSON format (doc), what’s the output during requests?

I updated the Traefik docker-compose configuration and enabled logging

access.log - action login

{
	"ClientAddr": "IP_address: xxxx",
	"ClientHost": "",
	"ClientPort": "xxxx",
	"ClientUsername": "-",
	"DownstreamContentSize": 503,
	"DownstreamStatus": 200,
	"Duration": 700733504,
	"OriginContentSize": 503,
	"OriginDuration": 687603879,
	"OriginStatus": 200,
	"Overhead": 13129625,
	"RequestAddr": "example.en",
	"RequestContentSize": 93,
	"RequestCount": 608,
	"RequestHost": "example.en",
	"RequestMethod": "POST",
	"RequestPath": "/login",
	"RequestPort": "-",
	"RequestProtocol": "HTTP/2.0",
	"RequestScheme": "https",
	"RetryAttempts": 0,
	"RouterName": "xx-xxx-xxxx-secure@docker",
	"ServiceAddr": ":80",
	"ServiceName": "nginx-xxxxx@docker",
	"ServiceURL": "http://IP_address:80",,
	"StartLocal": "2025-08-21T09:56:25.749707944Z",
	"StartUTC": "2025-08-21T09:56:25.749707944Z",
	"TLSCipher": "TLS_AES_128_GCM_SHA256",
	"TLSVersion": "1.3",
	"entryPointName": "websecure",
	"level": "info",
	"msg": "",
	"time": "2025-08-21T09:56:26Z"
}

{
	"ClientAddr": "IP_address: xxxx",
	"ClientHost": "",
	"ClientPort": "xxxx",
	"ClientUsername": "-",
	"DownstreamContentSize": 9487,
	"DownstreamStatus": 200,
	"Duration": 110907820,
	"OriginContentSize": 9487,
	"OriginDuration": 110382281,
	"OriginStatus": 200,
	"Overhead": 525539,
	"RequestAddr": "example.en",
	"RequestContentSize": 0,
	"RequestCount": 609,
	"RequestHost": "example.en",
	"RequestMethod": "GET",
	"RequestPath": "/login",
	"RequestPort": "-",
	"RequestProtocol": "HTTP/2.0",
	"RequestScheme": "https",
	"RetryAttempts": 0,
	"RouterName": "xx-xxx-xxxx-secure@docker",
	"ServiceAddr": ":80",
	"ServiceName": "nginx-xxxxx@docker",
	"ServiceURL": "http://IP_address:80",
	"StartLocal": "2025-08-21T09:56:26.503092797Z",
	"StartUTC": "2025-08-21T09:56:26.503092797Z",
	"TLSCipher": "TLS_AES_128_GCM_SHA256",
	"TLSVersion": "1.3",
	"entryPointName": "websecure",
	"level": "info",
	"msg": "",
	"time": "2025-08-21T09:56:26Z"
}

{
	"ClientAddr": "IP address: xxxx",
	"ClientHost": "",
	"ClientPort": "xxxx",
	"ClientUsername": "-",
	"DownstreamContentSize": 6605,
	"DownstreamStatus": 404,
	"Duration": 74251922,
	"OriginContentSize": 6605,
	"OriginDuration": 73850774,
	"OriginStatus": 404,
	"Overhead": 401148,
	"RequestAddr": "example.en",
	"RequestContentSize": 0,
	"RequestCount": 610,
	"RequestHost": "example.en",
	"RequestMethod": "GET",
	"RequestPath": "/storage/images/main-page/footer-logo/ydVzk4j6b9mVldXbJDXSthdAO5c4n8mfchMGpwk1.jpg",
	"RequestPort": "-",
	"RequestProtocol": "HTTP/2.0",
	"RequestScheme": "https",
	"RetryAttempts": 0,
	"RouterName": "xx-xxx-xxxx-secure@docker",
	"ServiceAddr": ":80",
	"ServiceName": "nginx-xxxxx@docker",
	"ServiceURL": "IP_address:80",
	"StartLocal": "2025-08-21T09:56:26.655527641Z",
	"StartUTC": "2025-08-21T09:56:26.655527641Z",
	"TLSCipher": "TLS_AES_128_GCM_SHA256",
	"TLSVersion": "1.3",
	"entryPointName": "websecure",
	"level": "info",
	"msg": "",
	"time": "2025-08-21T09:56:26Z"
}

Regarding the Traefik logs, the only thing that stood out to me was:

2025-08-21T09:07:08Z DBG ``github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:288`` > Serving default certificate for request: "www.mydomain.en"
2025-08-21T09:09:13Z DBG ``github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:288`` > Serving default certificate for request: ""
2025-08-21T09:09:13Z DBG log/log.go:245 > http: TLS handshake error from IP_address:PORT: remote error: tls: bad certificate
2025-08-21T09:09:13Z DBG ``github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:288`` > Serving default certificate for request: ""
2025-08-21T09:09:14Z DBG log/log.go:245 > http: TLS handshake error from IP_address:PORT: remote error: tls: bad certificate
2025-08-21T09:13:00Z DBG ``github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:288`` > Serving default certificate for request: ""
2025-08-21T09:42:17Z DBG ``github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:288`` > Serving default certificate for request: "IP_address_server:"
2025-08-21T09:42:17Z DBG log/log.go:245 > http: TLS handshake error from IP_address:PORT: EOF
2025-08-21T09:42:17Z DBG ``github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:288`` > Serving default certificate for request: "IP_address_server"

2025-08-21T09:42:17Z DBG log/log.go:245 > http: TLS handshake error from IP_address:PORT: EOF
2025-08-21T09:56:15Z DBG ``github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:288`` > Serving default certificate for request: ""
2025-08-21T09:56:15Z DBG log/log.go:245 > http: TLS handshake error from IP address:PORT: EOF
2025-08-21T09:56:25Z DBG ``github.com/traefik/traefik/v3/pkg/server/service/loadbalancer/wrr/wrr.go:175`` > Service selected by WRR: http://IP_address:PORT
2025-08-21T09:56:26Z DBG ``github.com/traefik/traefik/v3/pkg/server/service/loadbalancer/wrr/wrr.go:175`` > Service selected by WRR: http://IP_address:PORT
2025-08-21T09:56:26Z DBG ``github.com/traefik/traefik/v3/pkg/server/service/loadbalancer/wrr/wrr.go:175`` > Service selected by WRR: http://IP_address:PORT
2025-08-21T10:07:13Z DBG ``github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:288`` > Serving default certificate for request: "mydomain.en"
2025-08-21T10:15:11Z DBG ``github.com/traefik/traefik/v3/pkg/tls/tlsmanager.go:288`` > Serving default certificate for request: ""
2025-08-21T10:16:47Z DBG ``github.com/traefik/traefik/v3/pkg/server/service/loadbalancer/wrr/wrr.go:175`` > Service selected by WRR: http://IP_address:PORT
2025-08-21T10:16:48Z DBG ``github.com/traefik/traefik/v3/pkg/server/service/loadbalancer/wrr/wrr.go:175`` > Service selected by WRR: http://IP_address:PORT

I would expect the first POST to return a OriginStatus of 30x to tell the browser to be redirected to fetch a different URL. Are you sure you app works without Traefik?

Maybe also check browsers developer console network tab.

The application runs with Traefik, after displaying a white page I receive a GET 302 on /login and then a redirect to the login page.

Maybe it’s a stupid question, but could the problem be related to TLS?

I don’t think it’s TLS related. Does your Laravel app have any logging?

In the Laravel logs, I don’t see anything concerning or related to the above error.