1
votes

Background:

I'm developing a Laravel 5.8 application running inside a Docker container on a server behind a reverse proxy, forwarding requests to the application based on a URL subdirectory, e.g. example.org/laravel/.

Everything (Routes, HTTPS links, assets, ...) is working fine, except the redirect to the intended page after login.

I've accomplished proper URL generation for routes, assets, etc. by using

app('url')->forceRootUrl(config('app.url'));  // https://example.org/laravel/
app('url')->forceScheme('https');

My Problem:

Suppose I have defined a route /foo with the auth middleware. When I'm logged out and visit example.org/laravel/foo I am correctly redirected to example.org/laravel/login, but after login I'm redirected to example.org/foo, which does not exist.

Investigation results:

Accessing /foo while being logged out

  1. auth middleware throws an AuthenticatedException, which is caught in Illuminate\Routing\Pipeline and passed to Illuminate\Foundation\Exceptions\Handler::unauthenticated() (via Handler::render())
  2. Handler::unauthenticated() returns redirect()->guest() (Illuminate\Routing\Redirector::guest())
  3. Redirector::guest() sets the url.intended session key to $this->generator->full() (Illuminate\Http\Request::fullUrl() via Illuminate\Routing\UrlGenerator::full())
  4. Request::fullUrl() calls Symfony\Component\HttpFoundation\Request::getUri() (via $this->url())
  5. Request::getUri() builds the URL from the $_SERVER and request header data (see below) as follows ($qs: query string):
$this->getScheme().'://'.$this->getHttpHost().$this->getBaseUrl().$this->getPathInfo().$qs
---
getScheme()   => 'http'         // As $_SERVER['HTTPS'] is not set
getHttpHost() => 'example.org'  // From $this->headers->get('HOST')
getBaseUrl()  => ''             // From $_SERVER['SCRIPT_NAME']   *[1]
getPathInfo() => '//foo'        // From $_SERVER['REQUEST_URI']
$qs           => ''             // From $_SERVER['QUERY_STRING']
---
*[1]: In Symfony\Component\HttpFoundation\Request::prepareBaseUrl():
      $baseUrl    = 'index.php' (L. 1745)
      $requestUri = '//foo'     (L. 1768)
      $prefix     = '/'         (L. 1778)
   => return ''                 (L. 1780)
  1. This results in session url.intended being set to http://example.org//foo instead of http(s)://example.org/laravel/foo

$_SERVER data (excerpt):

"HTTP_HOST" => "example.org"
"SERVER_NAME" => "example.org"
"QUERY_STRING" => ""
"REQUEST_URI" => "//foo"
"SCRIPT_NAME" => "/index.php"

Exact Composer package versions:

  • laravel/framework: v5.8.3
  • symfony/http-foundation: v4.2.4
1

1 Answers

0
votes

I researched little bit and find that problem is at $_SERVER variable.

It sets wrong value on HTTP_POST when proxying some domain to local ip as below:

server {
  listen 80;
  listen [::]:80;

  server_name domain.com;

  location / {
    proxy_pass http://127.0.0.1:4567;
  }
}

I fixed it by manually setting HTTP_HOST on proxy.

In your situation you need to add this line: proxy_set_header Host example.org/laravel;

My situation is different than yours little bit. It redirects me to http://127.0.0.1:4567 after successfully login on domain.com. Because Laravel's session.url_previous was wrong. Which comes from $_SERVER['HTTP_HOST'].

As a result I hope this will help you.

Whole Nginx conf file:

server {
  listen 80;
  listen [::]:80;

  server_name domain.com;

  location / {
    #changes happened here
    proxy_set_header Host domain.com;

    proxy_pass http://127.0.0.1:4567;
  }
}