Search code examples
phplaravelauthenticationbasic-authentication

Laravel 11: Basic Auth to protect & showcase unfinished app to Client


I have an app that is still under development, yet it is already deployed and live on the server. To protect it from being visited by boots or humans who should not see it yet, I have enabled Basic Auth via server provisioning dashboard (I use runcloud) not Laravel itself.

This all works fine, but because the app integrates payments I had to implement POST route (webhook) for external payment provider to hit it whenever it has to confirm payment. This single route should not be behind basic auth, otherwise payment provider is getting HTTP 401.

So I have:

  1. disabled basic auth on the provisioning dashboard
  2. enabled basic auth on Laravel level by adding auth.basic middleware to all my routes except the webhook one.
    Route::post('/payments/verify', [PaymentsController::class, 'verify'])
        ->name('payments.verify')
        ->withoutMiddleware('auth.basic');

This also works but by default, Laravel will use email and password from users table for credentials. I don't want this. I want a fixed & simple credentials for everyone like "foo" / "bar".

How can I do this in Laravel 11?


Solution

  • OK, So I have decided to approach it with a middleware and the fact that my cloud management software offers temporary domains, so I have created one that is an alias to my production one, and then I have defined the following class:

    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    use Symfony\Component\HttpFoundation\Response;
    
    class ServeOverTemporaryDomain
    {
        public function handle(Request $request, Closure $next): Response
        {
            if (app()->isProduction() && $request->getHost() === config('app.temporary_domain')) {
                return $next($request);
            }
    
            if (app()->isProduction() && $request->getHost() === 'my-production-domain.eu') {
                die; // yep, I simply kill the request
            }
    
            return $next($request);
        }
    }
    

    and:

    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->append(ServeOverTemporaryDomain::class);
    

    Where config('app.temporary_domain') is 'temporary_domain' => env('APP_TEMPORARY_DOMAIN'), which points to:

    APP_TEMPORARY_DOMAIN=temp.foobar.temp-site.link in my .env. file.

    That way, no one can see a thing when reaching publicly known domain, yet no one knows a temp. url under which app and webhook all work as usual.