3
votes

I've started work on an existing Laravel 5.2 project. I'm needing to build some basic API requests for the front-end of the application to talk with the database. These routes need to be authenticated by the user's session.

I've tried setting up middleware using the auth:api driver, and in ../config/auth.php setting the api['driver'] to 'session'. However, I keep getting 302 redirected to the login page even though the user is authenticated with all permissions and roles.

Can someone recommend some reading or other solution ideas of how to achieve API authentication based on the user session?

from routes/api.php:

Route::group(["middleware" => ["auth:api"]], function () {
    // results in 302 redirect to /login
    Route::get('test', function(){
        return "TEST";
    });    

});

from config/auth.php

'guards' => [
'web' => [
    'driver' => 'session',
    'provider' => 'users',
],

'api' => [
    'driver' => 'session',
    'provider' => 'users',
],

app/Http/Kernel.php

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array
     */
    protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
        \App\Http\Middleware\NoCache::class,
    ];

    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'role' => \Zizaco\Entrust\Middleware\EntrustRole::class,
        'permission' => \Zizaco\Entrust\Middleware\EntrustPermission::class,
        'ability' => \Zizaco\Entrust\Middleware\EntrustAbility::class,
        'dashboard' => \App\Http\Middleware\dashboardMiddleware::class,
        'system' => \App\Http\Middleware\systemMiddleware::class
    ];
}
2
Post an example of your code. It sounds like the middleware may not be setup right. Maybe it can be that your route hierarchy is a little messed upidelara
@JackGal i've added a copy of the code for you.kirgy
Are you trying to access such route from your browser?idelara
@JackGal I've tried accessing from the browser, but I figured the header "Accept-Encoding application/json" would be needed, so I've also copied the browser request as curl, imported into postman, and changed that header to above (the cookie file is copied doing this method). Same issue occurs of 302 redirect to "/login".kirgy
Ok.. can you include the part of your middleware groups in your Kernel class? I wanna see if your setup there is correctidelara

2 Answers

0
votes

This is be old post but from my experience and what I've learned we don't use session based mechanism authentication for API request from third party app b/c session based authentication is like if you have not been authenticated yet (like not yet logged in ), it will redirect you to login page (like the author of this question said "getting 302 redirected to the login page").

But API request is XMLHttpRequest (ajax request), not browser request, if so, how could it redirect you to login page? (check network tab in Developer tool and you will see, the response from this request is 302 and the response body is the login html page).

Therefore, we should only use token based mechanism for API authentication, which will return message like "you're not authenticated" as json response, which can be consumed by your 3rd party app.

For laravel specifically, you can use session provider for api guard, but you need to go to Kernel.php and add

\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class

, which are core of laravel session based authentication, to your api middleware group. Otherwise, even if you're already logged in, you'll still be unauthenticated because laravel api routes by default don't have necessary middlewares for session based authentication.

 protected $middlewareGroups = [ 
        'web' => [
            // ...
        ],  

        'api' => [
            \App\Http\Middleware\EncryptCookies::class,          // <------- ADD THIS
            \Illuminate\Session\Middleware\StartSession::class, // <------ ADD THIS
            // ...
        ],  
    ];

Ref: https://laracasts.com/discuss/channels/laravel/protecting-api-routes-with-session-guard https://laravel.io/forum/02-09-2016-52-ajax-auth-not-picking-up-session

-2
votes

The issue is that you are not passing any authentication headers in the request, therefore, it is obvious that it is redirecting you to the login screen, even when you hit the API using postman.

To prove this, try removing the auth middleware from the following line Route::group(["middleware" => ["auth:api"]], ... in your routes file, and you should be able to get TEST as a response if you hit your test route. Also, please do have in mind that our api automatically binds the api/ prefix to all api routes. Therefore, you should make a request to /api/test and you should get TEST back.

If you want to include auth to your api, please read Laravel's Passport docs. If you want something much simpler, start with the onceBasic Auth middleware in the docs.

I hope this points you in the right way!

Let me know if you have any other questions.

Cheers!