Lumen Force Https Redirect on Heroku

2016

If you've ever been in a situation where you want to force your Laravel application to redirect all URL's to HTTPS at the application level, you've probably come across this Stack Overflow answer which suggests you make a Middleware like the following:

namespace App\Http\Middleware;

use Closure;

class HttpsProtocol {

    public function handle($request, Closure $next)
    {
        if (!$request->secure() && env('APP_ENV') === 'prod') {
            return redirect()->secure($request->getRequestUri());
        }

        return $next($request); 
    }
}

This is all fine and good, and works well for Laravel, but unfortunately fails to work in Lumen due to the request object and redirect() helper lacking their respective secure() methods. Luckily, a solution for Lumen isn't much more complicated. If you dig a bit deeper into Lumens Redirector class (which powers the redirect() helper), there is a to() method available where the 4th parameter is a boolean denoting whether or not the redirect should be made securely:

public function to($path, $status = 302, $headers = [], $secure = null)
{
    $path = $this->app->make('url')->to($path, [], $secure);

    return $this->createRedirect($path, $status, $headers);
}

That means our Lumen version of the HttpsProtocol middleware can look something like this:

namespace App\Http\Middleware;

use Closure;

class HttpsProtocol
{
    public function handle($request, Closure $next)
    {
        if (($request->header('x-forwarded-proto') <> 'https') && app()->environment() === 'prod') {
            $request->setTrustedProxies([ $request->getClientIp() ]);
            
            return redirect()->to($request->getRequestUri(), 301, $request->header(), true);
        }

        return $next($request);
    }
}

As you can see, we've utilized the redirect() helpers to() method and passed along all our parameters from the request, most notably the 4th “true” parameter denoting that the request should be made securely. And we're all done!

* One thing to note is that only 1 part of our new middleware is Heroku specific, the $request->header('x-forwarded-proto') <> 'https' line which specifically looks for a header Heroku sends along. If your application is not hosted on Heroku, you may need to inspect the request for a different header to determine whether or not the request is being made over HTTPS. However, the rest of the code can remain the same.