Back to blogs

Tech & Trends

18. 02. 2022

How to handle both API and Basic authentication in Laravel

by Ricardo Čerljenko

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 () {
    // PROTECTED ROUTES
});

Or using Basic auth:

// routes/api.php

use Illuminate\Support\Facades\Route;

Route::middleware('auth.basic')->group(function () {
    // PROTECTED ROUTES
});

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);
    }
}

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.

We’re available for partnerships and open for new projects. If you want to know more about us, click here.
Also, don’t forget to follow us on Instagram and Facebook