0

I implemented passport authentication in Laravel and the basic auth. I have UserController and inside it, I have the constructor methode:

 public function __construct()
    {
        $this->middleware('auth.basic.once')->except(['index', 'show']);   
        $this->middleware('auth:api')->except(['index', 'show']); 
    }

The OnceBasic middleware:

public function handle($request, Closure $next)
    {
        if(Auth::guard('api')->check())
        return $next($request);
        else
        return Auth::onceBasic() ?: $next($request);
    }

In the OnceBasic middleware, I'm able to check if the user authenticated using the auth:api then I prevent the authentication from trying to use the onceBasic, So it worked correctly when using the access token. But it fails when trying to authenticate using the onceBasic(email, password) because the auth:api trying to authenticate too and it fails(trying to call the redirectTo() methods inside the default \App\Http\Middleware\Authenticate.php )

My question is there a way to use both of these middlewares, to only successfully authenticate one and prevent the other from working?

Ali Ali
  • 1,756
  • 2
  • 15
  • 34
  • You shouldn't use same route for web and api call. – Tpojka Apr 25 '20 at 10:33
  • Both middlewares for API, users can generate their personal access tokens using the API and I don't have a web or user interfaces @Tpojka – Ali Ali Apr 25 '20 at 14:40
  • You expect some kind of guest on register route, I assume. So you don't need any "auth" middleware on endpoint where you are expecting guests. – Tpojka Apr 25 '20 at 14:42
  • I'm doing some tests for educational purposes, So I'm trying to apply the logic: users can authenticate using their credentials or their access token for the same route. @Tpojka – Ali Ali Apr 25 '20 at 14:48
  • @Tpojka I succeeded in applying half of this logic, if the user has a valid access token, authentication of his identity is skipped. – Ali Ali Apr 25 '20 at 14:54
  • Help me understand it better. If user doesn't have valid token shouldn't you return response of 403 (i.e. Unauthorized) and from frontend send another request to some kind of login page? – Tpojka Apr 25 '20 at 15:02
  • If the user doesn't have valid token And doesn't have valid credentials then he got the error, I don't have a frontend, only API interacting with it using Postman. – Ali Ali Apr 25 '20 at 15:06
  • All server's job in auth:api would be that checks for valid token and return response with 403 for example if token is not valid. If client side wants to register/login user that route shouldn't be under any kind of auth middleware at all. Maybe I don't get it right and I should probably need more context, sorry. – Tpojka Apr 25 '20 at 15:09
  • I need to check if the user has valid credentials I don't need the auth:api to work at all, skipping the check for the access token and the redirect to login. – Ali Ali Apr 25 '20 at 15:12

1 Answers1

1

My approach to using the same controller for two guards required pointing two separate groups of routes to the controllers. I provided an example in this answer to a similar question, here is the example code again:

<?php

    Route::middleware(['auth:admin_api'])->group(function () {
        Route::prefix('admin')->group(function () {
            Route::name('api.admin.')->group(function () {

                ////////////////////////////////////////////////////////////
                /// PLACE ADMIN API ROUTES HERE ////////////////////////////
                ////////////////////////////////////////////////////////////
                Route::apiResource('test','App\Http\Controllers\API\MyController');
                ////////////////////////////////////////////////////////////
            });
        });
    });

    Route::middleware(['auth:api'])->group(function () {
        Route::name('api.')->group(function () {
            ////////////////////////////////////////////////////////////
            /// PLACE PUBLIC API ROUTES HERE ///////////////////////////
            ////////////////////////////////////////////////////////////
            Route::apiResource('test', 'App\Http\Controllers\API\MyController');
            ////////////////////////////////////////////////////////////
        });
    });

So when an admin user goes to admin/test, it uses the admin auth guard, and when a normal user goes to /test it uses the standard auth guard. Both of these use the same controller.

I then created a base controller for my app. Here is how I determined with guard is being used to access the route in the constructor:

<?php


use Illuminate\Http\Response;
use App\Http\Controllers\Controller;

class BaseController extends Controller
{
    protected $user;

    protected $isAdmin = false;

    public function __construct()
    {
        if(Auth::guard('admin_api')->check()) {
            $this->user = Auth::guard('admin_api')->user();
            $this->isAdmin = true;
        } elseif(Auth::guard('api')->check()) {
            $this->user = Auth::guard('api')->user();
            $this->isAdmin = false;
        } else {
            return response()->json([
                'message' => 'Not Authorized',
            ], 401);
        }
    }

mchljams
  • 441
  • 2
  • 9
  • It occurred to me to use this approach, thus we actually use different route endpoints to the second middleware, but currently, I have a lot of routes, and duplicating them will grow the size a lot. let us wait for other thoughts. If none, I will take this approach as the only choice. Thank you. – Ali Ali Apr 27 '20 at 22:04
  • I'd definitely be interested to see another approach, but this is what is working for me. Using the resource routes, and sticking to the method naming conventions has helped me keep the routes file pretty organized. – mchljams Apr 28 '20 at 14:40
  • 1
    Thank you @mchljams, I know this approach will work, but it's not the approach that I'm looking for, so I'm not gonna use it. However, I will mark your answer as accepted and vote up. And thanks again – Ali Ali May 01 '20 at 22:11