Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

beznez's avatar

Authentication

Hi Laracasts. I'm making an API and I wanted to implement basic authentication. I took a look through the Laravel docs and also this site. I was about to start implementing it, but I wanted to ask the community a question first. My API is based on an account, rather than a user. So I want to change some of the behaviors. After reading up on my options, I decided I want to use middleware. However, basic auth uses an email by default. Is there a way that I can redefine this or do I have to completely define my own authentication and use auth instead of auth.basic?

If anyone has a better way, I'd be interested in that as well. My goal is to have the API allow a user access if they provide the correct account credentials.

One final question: How would I implement it so that it looks like basic auth? That is, I want it to work with curl -u user:pass ... and I want the browser basic auth popup when it is visited in a browser. I do not need any kind of a login or register page; that functionality is in my dashboard for the API.

0 likes
10 replies
rodrigo.pedra's avatar
Level 56

You can extend the AuthenticateWithBasicAuth and use your desired field:

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Routing\Middleware;
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;

class MyBasicAuth extends AuthenticateWithBasicAuth implements Middleware
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // pass the desired field as the argument
        return $this->auth->basic('username') ?: $next($request); 
    }
}

And then update you app\Http\Kernel.php file:

    protected $routeMiddleware = [
        'auth'          => 'App\Http\Middleware\Authenticate',
        'auth.basic'    => 'App\Http\Middleware\MyBasicAuth', // UPDATED!!!
        'guest'         => 'App\Http\Middleware\RedirectIfAuthenticated',
    ];

EDIT: corrected the extends in the middleware

beznez's avatar

Ok, so I've implemented that but it's not working. The page waits for the server to respond and it never does, but I don't have any errors in my laravel log. The 'password' field is named something different as well. Can I define that here too or do I have to use auth?

rodrigo.pedra's avatar

Just tried and it worked... But my password field is named password.

Looked into the source, and the password field should be named password:

https://github.com/laravel/framework/blob/e2314aab84623d0ad434305526d4dbeb5efd9acd/src/Illuminate/Auth/Guard.php#L332

If you need the password field to be named differently you'll have or to extend Guard and provide it, or to use custom Auth, changing your App\Http\Middleware\Authenticate middleware.

Can't the password field be named password?

beznez's avatar

I could rename the field, but it's actually an auth_token. Now this is really just semantics, but since my application has it in it already I might as well try to extend the class before I rename it, just for naming convention consistency. I've only recently been comfortable enough to delve into Laravel's code base and I want to make sure that I have the right procedure for this.

<?php namespace App\Http\Middleware;

// classes I need to use will go here

class MyGuard extends Guard implements GuardContract
{
    // overriding the method from the Guard class
    protected function getBasicCredentials(Request $request, $field)
    {
        // change password to auth_token
        return [$field => $request->getUser(), 'auth_token' => $request->getPassword()];
    }
}

And then in Kernel.php, I add 'myguard' => 'App\Http\Middleware\MyGuard' to $routeMiddleware. Then in routes.php, I add myguard to the middleware like so:

Route::get('path', ['middleware' => ['auth.basic', 'myguard'], 'uses' => 'Controller@method']);
rodrigo.pedra's avatar

Did it work?

You can override the constructor in MyBasicAuth and pass your Guard implementation to its parent class:

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Contracts\Routing\Middleware;
use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;

use App\Namespace\To\MyGuard;

class MyBasicAuth extends AuthenticateWithBasicAuth implements Middleware
{
    public function __construct(MyGuard $auth)
    {
        parent::__construct( $auth );
    }

    public function handle($request, Closure $next)
    {
        // pass the desired field as the argument
        return $this->auth->basic('username') ?: $next($request); 
    }
}
beznez's avatar

No, it didn't work. I put it in the constructor but still nothing. Nothing in my laravel logs either as far as errors go. I guess now is the time to just change the name of the field. Thanks.

rodrigo.pedra's avatar

EloquentUserProvider's retrieveByCredentials method also expects the password field to be called password...

I think it is better to change you field name... Doing so many changes may break your app in a future framework update.

beznez's avatar

Alright, so I've changed my field name but now I'm getting an error. It's trying to look in my 'users' table instead of my 'accounts' table. How do I change this behavior?

rodrigo.pedra's avatar

in your User model add this attribute:

class User extends Model {
    protected $table = 'accounts';

    // omitted for brevity
}
beznez's avatar

Of course. I didn't even think of that. Thanks so much.

Please or to participate in this conversation.