I think the problem is something along these lines:
CloneRequest gets ran as Before Middleware before anything else. When you run $request->duplicate(), at this moment, there is no session store on the request object. (I think even if there was, this still would fail, because diving into the code shows that the session is not cloned using the duplicate() method).
You then pass the $clone into the next() method which makes its way thru the middleware stack. When it reaches StartSession, it sets a singleton session store on your clone, but the "original" Request object doesn't get set.
Then when you hit your login form, the session $errors object is referenced within login.blade.php, which doesn't exist because you have no session (because it is set on your clone), and everything blows up.
This test confirms my theory:
class CloneRequest
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
$clone = $request->duplicate();
\App::bind('test', function() use ($clone) { return $clone; });
return $next($clone);
}
}
Then within login.blade.php:
Original Request: {{ dump(\Request::hasSession()) }}
Clone Request: {{ dd(resolve('test')->hasSession() ) }}
// results in
// Original Request:
// false
// Clone Request:
// true
If I remove the dd() and allow it to proceed, when it reaches the $errors->has('email'), it throws the "page has expired" message. Turning on debug, we can see that the underlying error is "Session store not set on request"