5

I have a fresh installation of Laravel Sanctum API. When I try to log a user in after registration or when submitting the registration form twice, I get an exception with the message "The route dashboard could not be found". I don't understand why it's trying to redirect the user to the 'dashboard' route. The only place that I can see 'dashboard' in my project is in RouteServiceProvider.This seems like a bug too me with Sanctum.

enter image description here

Hamid Hosseini
  • 413
  • 1
  • 5
  • 15
  • 2
    the `guest` middleware will try to redirect to `HOME` that is defined in the `RouteServiceProvider` by default ... is the constant for `HOME` set to `dashboard`? – lagbox Jan 03 '23 at 02:01
  • Yes, the constant for `HOME` is set to `dashboard`. That's what I don't understand, why it's trying to redirect, it's supposed to return an API response. – Hamid Hosseini Jan 03 '23 at 02:20
  • 1
    are you sending the `accept` header for JSON? – lagbox Jan 03 '23 at 02:23
  • Yeah, I am, in Postman and also Axios in my SPA. – Hamid Hosseini Jan 03 '23 at 02:26
  • clear the route cache and try again. php artisan route:clear to clear route cache. php artisan optimize to clear all cache. – Tharuka Dananjaya Jan 03 '23 at 04:40
  • @HamidHosseini what is in `php artisan route:list`? – francisco Jan 03 '23 at 12:28
  • These comments are right. Unless you have a route already pointing to `/dashboard` view, you will get the 404 error. But, what if I don't have such endpoint defined or my App doesn't need it? So, forcing to redirect the user to `/dashboard` after authenticating is a mistake. It should be `/` only. – jgarcias Aug 23 '23 at 01:03

3 Answers3

5

You are right, App\Providers\RouteServiceProvider\RouteServiceProvider::HOME const is set to "/dashboard". If you follow the usage of this const you can see that is used by App\Http\Middleware\RedirectIfAuthenticated middleware

class RedirectIfAuthenticated {
/**
 * Handle an incoming request.
 *
 * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
 */
public function handle(Request $request, Closure $next, string ...$guards): Response
{
    $guards = empty($guards) ? [null] : $guards;

    foreach ($guards as $guard) {
        if (Auth::guard($guard)->check()) {
            return redirect(RouteServiceProvider::HOME);
        }
    }

    return $next($request);
}
}

This middleware is aliased as "guest" in the App\Http\Kernel:

protected $middlewareAliases = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
    'signed' => \App\Http\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'verified' => \App\Http\Middleware\EnsureEmailIsVerified::class,
];

And this middleware is used in unauthenticated routes defined by routes/auth.php

Route::post('/register', [RegisteredUserController::class, 'store'])
            ->middleware('guest')
            ->name('register');

Route::post('/login', [AuthenticatedSessionController::class, 'store'])
            ->middleware('guest')
            ->name('login');

Route::post('/forgot-password', [PasswordResetLinkController::class, 'store'])
            ->middleware('guest')
            ->name('password.email');

Route::post('/reset-password', [NewPasswordController::class, 'store'])
            ->middleware('guest')
            ->name('password.store');

This built-in middleware middleware will try and redirect you to the HOME if you are already authenticated. I think that there is an issue in Laravel breeze scaffolding (php artisan breeze:install api) that not provide a check on the response type in the App\Http\Middleware\RedirectIfAuthenticated middleware. If you see instead the App\Http\Middleware\Authenticate middleware here is automatically provided a redirectTo method that check for the expected response ($request->expectsJson()):

class Authenticate extends Middleware
{
    /**
     * Get the path the user should be redirected to when they are not authenticated.
     */
    protected function redirectTo(Request $request): ?string
    {
        return $request->expectsJson() ? null : route('login');
    }
}

TLDR
In short to work correctly with the App\Http\Middleware\RedirectIfAuthenticated middleware in API based authentication you can add manually the following check in the middleware:

foreach ($guards as $guard) {
if (Auth::guard($guard)->check()) {
  if ($request->expectsJson()) {
    return response()->json(['error' => 'Already authenticated.'], 200);
  }
  return redirect(RouteServiceProvider::HOME);
}
}
Alberto Favaro
  • 1,824
  • 3
  • 21
  • 46
  • 1
    I opened an issue on Github scaffolding project: https://github.com/platformsh-templates/laravel/issues/50 – Alberto Favaro Apr 26 '23 at 07:24
  • 1
    Good effort. It is weird that your bug is still open despite it is a valid one. Just a tiny improvement to the response: `return response()->json(['message' => 'authenticated.'], 200);` (because it is not an error, it is the expected behavior) – Billal Begueradj Aug 15 '23 at 13:59
  • Now this is an answer, explaining where that /dashboard came from was really helpful. – Steve Moretz Aug 18 '23 at 16:38
3

this error shows when you try to register while you are already logged, so make sure to log out before register

0

Make sure the dashboard route is added to the routes/web.php or routes/api.php file.

ex: Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
Jimale Abdi
  • 2,574
  • 5
  • 26
  • 33
Sheeva
  • 1
  • 1