Laravel Redirects Break When Using Origin Referrer Policy

April 28, 2016

Some referrer policies can lead to unintended consequences for your Laravel application. Specifically, those that only populate the Referer header with the origin of the referrer (i.e. scheme, host, and port) can break redirects.

The HTTP referrer header (technically the Referer header due to a misspelling) identifies the web page that linked to the resource being requested. However, if traffic flows from an HTTPS site to a non-HTTPS site the referrer header is omitted.

This is intended behavior per the No Referrer When Downgrade policy, which is the default referrer policy, but there are several options to choose from:

  • No Referrer: No referrer information is included in the request.
  • No Referrer When Downgrade (default): The full URL is sent along with requests from HTTPS to HTTPS, and from HTTP to whatever, but no information is sent when traffic flows from HTTPS to HTTP (a "downgrade").
  • Origin Only: Only the origin (scheme, host and port) is sent along with the request.
  • Origin When Cross-origin: The full URL is included when making same-origin requests, but only the origin is sent when making cross-origin requests (typically traffic between different sites).
  • Unsafe URL: The full URL is sent regardless.

Please refer to this working draft for more information about the different policies.

The policy can be delivered using meta tags:

<meta name="referrer" content="none" />
<meta name="referrer" content="none-when-downgrade" />
<meta name="referrer" content="origin" />
<meta name="referrer" content="origin-when-cross-origin" />
<meta name="referrer" content="unsafe-url" />

If you do want the referrer header to be populated when traffic flows from HTTPS to HTTP you can change the referrer policy to Origin Only, Origin When Cross-origin or Unsafe URL (not recommended).

Laravel and Referrer headers

However, using Origin Only poses some problems for Laravel applications served over HTTPS. When redirecting to the previous page, for example after a failed form validation attempt, Laravel looks to the Referer header for the previous URL:

// Illuminate/Routing/UrlGenerator.php

$url = $referrer ? $this->to($referrer) : $this->getPreviousUrlFromSession();

Laravel will use the session information if the referrer header is missing. But with the Origin Only policy set, Laravel will redirect you back to the front page every time a form validation fails. This is because only the origin, eg. https://, will be present in the Referer header, while the specific resource (e.g. /articles/create) will be lost.

To retain the full URL you should use the Origin When Cross-Origin policy.

<meta name="referrer" content="origin-when-cross-origin" />

This will add the full URL when making same-origin requests, and only the origin when making cross-origin requests. Thus, Laravel is able to fetch the full URI and properly redirect back.