inertia-laravel
inertia-laravel copied to clipboard
Laravel Passport authorization flow not working with Inertia?
When Laravel Passport redirects back to an external URI after the OAuth 2.0 authorization flow, it renders an iframe of the external website, instead of actually redirecting to the external website.
The thing is I could use Inertia::location($url) to redirect to the external client URL, but this is internal of Passport. The workaround I found was to override the handle method in HandleInertiaRequests.php:
public function handle(Request $request, Closure $next)
{
$parentResponse = parent::handle($request, $next);
if (!empty($request->redirect_uri)) {
return Inertia::location($parentResponse->headers->all()['location'][0]);
}
return $parentResponse;
}
It checks if the request had an request_uri; there should probably be a better condition to test this, though.
This solution partially worked for me while using Token Grant OAuth. Ultimately, I had to create a Blade login form (and controller), and add the following to app/Exceptions/Handler.php:
protected function unauthenticated($request, \Illuminate\Auth\AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
if ($request->response_type === 'code') {
return redirect()->guest(route('oAuth-login-form-route'));
}
return redirect()->route('login');
}
@tranelearth Interesting. I wonder whether there should be more compatibility between Inertia and Passport, and whether they are tested together or not at all.
I have updated my middleware. It is easier to understand now:
public function handle(Request $request, Closure $next)
{
$parentResponse = parent::handle($request, $next);
$location = $parentResponse->headers->get('Location');
if ($this->isExternal($location)) {
if (request()->inertia()) {
return inertia()->location($location);
}
return redirect()->to($location);
}
return $parentResponse;
}
A method to check if an URL is external, which is used above:
public function isExternal($url)
{
$internalHost = parse_url(config('app.url'), PHP_URL_HOST);
$internalPort = parse_url(config('app.url'), PHP_URL_PORT);
$host = parse_url($url, PHP_URL_HOST);
$port = parse_url($url, PHP_URL_PORT);
return $host !== $internalHost || $port !== $internalPort;
}
Hey @abbluiz, thanks for reporting this issue.
Whether Inertia is compatible with Passport or any third-party library really depends on the third-party library for the most part, as Inertia in and by itself is just a generic library. However, I'll leave this issue open so that we can investigate and perhaps come up with a fix for this Passport-specific issue somewhere later.
My personal approach to this would probably be to add a special route that uses Inertia::location() to redirect to the Passport OAuth route. That way, you immediately (as the first step in the chain) tell Inertia that we're no longer using Inertia going forward, allowing Passport to properly render it's routes/do it's thing. Then afterwards, you can make sure it redirects back to your Inertia pages.
Hope this helps!
Hey there,
We're closing this issue because it's inactive, already solved, old or not relevant anymore. Feel free to open up a new issue if you're still experiencing this problem.