How to handle both API and Basic authentication in Laravel

rcerljenko

Ricardo Čerljenko

Posted on March 3, 2022

How to handle both API and Basic authentication in Laravel

While building your app in Laravel PHP Framework, you have multiple ways of protecting your API routes with various auth guards or Basic auth. Would it be nice to support both API guard and Basic auth at the same time?

In default Laravel app you can protect your API routes like this:

// routes/api.php

use Illuminate\Support\Facades\Route;

Route::middleware('auth:api')->group(function (): void {
    // PROTECTED ROUTES
});
Enter fullscreen mode Exit fullscreen mode

Or using Basic auth:

// routes/api.php

use Illuminate\Support\Facades\Route;

Route::middleware('auth.basic')->group(function (): void {
    // PROTECTED ROUTES
});
Enter fullscreen mode Exit fullscreen mode

But it's not possible to guard your routes with both of them. E.g., if there's no provided Bearer token use the Basic auth. To accomplish this we need to make some adjustments to the default Authenticate middleware which is provided in the app/Http/Middleware directory. Here's how I achieved that:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Auth\AuthenticationException;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Auth\Middleware\Authenticate as Middleware;

class Authenticate extends Middleware
{
    /**
     * Handle an incoming request.
     */
    public function handle($request, Closure $next, ...$guards): Response
    {
        try {
            $this->authenticate($request, $guards);
        } catch (AuthenticationException $e) {
            if (!$request->wantsJson()) {
                throw $e;
            }

            if ($response = $this->auth->onceBasic()) {
                return $response;
            }
        }

        return $next($request);
    }
}
Enter fullscreen mode Exit fullscreen mode

First, we catch the AuthenticationException which is thrown by the parent authenticate() method. That means that every provided guard (or a default one) didn't produce a valid user.

Now we can try to do a Basic auth but only if the client expects a JSON response (we don't want to try Basic auth in a normal web context because it would pop-up the Basic auth prompt box on every browser request).

Take note that onceBasic() method returns null if the provided Basic auth credentials are valid. If not, it returns an already formed Error Response bag which you can safely return from the middleware.

Now we're able to authenticate our users on API routes with both API guard and fallback Basic auth by simply using a default auth middleware.

Thank you for reading this! If you've found this interesting, consider leaving a ❤️, 🦄 , and of course, share and comment on your thoughts!

Lloyds is available for partnerships and open for new projects. If you want to know more about us, check us out.

Also, don’t forget to follow us on Instagram and Facebook!

💖 💪 🙅 🚩
rcerljenko
Ricardo Čerljenko

Posted on March 3, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related