meredevelopment's avatar

5.3: api routes, auth middleware confusion

I'm getting very confused by the differences between routes set-up in web.php and ones in api.php. Also the differences between using $this->middleware('auth') and $this->middleware('auth:api'). Please be patient with me...

Setup:

  • I have fired up the standard auth setup with php artisan make:auth. registering and logging in with a user works and I end up at /home.
  • I have a controller called MembersController thats forming a API endpoint, returning JSON. With no auth, this is working as I want it to.
  • I have a route in routes/api.php like this:
Route::group(['prefix' => 'v2'], function() {
  Route::resource('members', 'MembersController');
});

To try and add authentication to MembersController I added:

public function __construct()
    {
        $this->middleware('auth');
    }

When I navigate to http://domain.dev/api/v2/members I get redirected to http://domain.dev/login. If I log in here I get redirected to /home "You are logged in!". GOOD. Now I'm logged in, if I try and go back to http://domain.dev/api/v2/members I get immediately redirected to /home. NOT GOOD.

Interestingly, if I add the members resource route to routes/web.php and not routes/api.php, after I log in I do get sent to /home, BUT if I try to go to http://domain.dev/api/v2/members it works, and I see my pretty pretty JSON :)

So... the reason I'm using the api routes is that I want to eventually get auth:api middleware working, and use token auth sent in a header, or a POST var. This is where I've found the docs get rather thin, but it's probably because I have some fundamental understanding missing.

By the way, if someone fancies some StackExchange points, this person is having exactly the same issue it seems: http://stackoverflow.com/questions/39561695/laravel-5-3-api (not my question)

0 likes
13 replies
bugsysha's avatar

Open config/auth.php. Find guards array and you will see that you have web guard and api guard. The guard specified should correspond to one of the keys in the guards array.

meredevelopment's avatar

Ok, I've checked and I have the following guards:

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

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

What does this tell you / me? As I'm using routes/api.php for my members route, I guess I should be using $this->middleware('auth:api');? I've added this to MembersController and I get the same thing, once logged in, if I try and go to http://domain.dev/api/v2/members I'm redirected to /home.

The fact that the guard driver is 'token' is probably key right? Do I need to be setting a token in the users table or something? If so any pointers how/where, or links to docs that explain it?

Thank you!

bugsysha's avatar

Maybe the best way to understand it is to execute command

php artisan route:list
meredevelopment's avatar

Did you mean you want to see the routes? or that I should be able to see something in them that answers my question? Here they are anyway:

|        | GET|HEAD  | /                            |                 | Closure                                                                | web          |
|        | GET|HEAD  | api/v2                       |                 | Closure                                                                | api          |
|        | POST      | api/v2/members               | members.store   | App\Http\Controllers\MembersController@store                           | api,auth:api |
|        | GET|HEAD  | api/v2/members               | members.index   | App\Http\Controllers\MembersController@index                           | api,auth:api |
|        | GET|HEAD  | api/v2/members/create        | members.create  | App\Http\Controllers\MembersController@create                          | api,auth:api |
|        | PUT|PATCH | api/v2/members/{member}      | members.update  | App\Http\Controllers\MembersController@update                          | api,auth:api |
|        | GET|HEAD  | api/v2/members/{member}      | members.show    | App\Http\Controllers\MembersController@show                            | api,auth:api |
|        | DELETE    | api/v2/members/{member}      | members.destroy | App\Http\Controllers\MembersController@destroy                         | api,auth:api |
|        | GET|HEAD  | api/v2/members/{member}/edit | members.edit    | App\Http\Controllers\MembersController@edit                            | api,auth:api |
|        | GET|HEAD  | api/v2/user                  |                 | Closure                                                                | api,auth:api |
|        | GET|HEAD  | home                         |                 | App\Http\Controllers\HomeController@index                              | web,auth     |
|        | GET|HEAD  | login                        | login           | App\Http\Controllers\Auth\LoginController@showLoginForm                | web,guest    |
|        | POST      | login                        |                 | App\Http\Controllers\Auth\LoginController@login                        | web,guest    |
|        | POST      | logout                       |                 | App\Http\Controllers\Auth\LoginController@logout                       | web          |
|        | POST      | password/email               |                 | App\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail  | web,guest    |
|        | POST      | password/reset               |                 | App\Http\Controllers\Auth\ResetPasswordController@reset                | web,guest    |
|        | GET|HEAD  | password/reset               |                 | App\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm | web,guest    |
|        | GET|HEAD  | password/reset/{token}       |                 | App\Http\Controllers\Auth\ResetPasswordController@showResetForm        | web,guest    |
|        | POST      | register                     |                 | App\Http\Controllers\Auth\RegisterController@register                  | web,guest    |
|        | GET|HEAD  | register                     |                 | App\Http\Controllers\Auth\RegisterController@showRegistrationForm      | web,guest    |

Thanks!

meredevelopment's avatar
Level 3

I worked out what was wrong, thanks to lots of articles around the web and delving into the 5.3 code more than before. I think the links offered above probably do contain the answers but were a little too 'conceptual' for my tiny tired brain. Here's the 'answer' I posted to a similar question on SE:

If you are specifying routes in api.php, you will need to use the auth:api middleware. For example:

    Route::group(['middleware' => ['auth:api']], function () {
        Route::get('/test', function (Request $request) {
             return response()->json(['name' => 'test']);
        });
    });

Notes about Token auth and Laravel 5.3:

  • If you've setup laravel's default auth system, you will also need to add a column for api_token to the user table. If you are using DB seeders, you might want to add something like: $table->char('api_token', 60)->nullable(); to your users table seeder. Alternatively just add the column manually and fill that column with a random 60-char key.
  • When making the request, you can add the api_token as a URL/Querystring parameter like so: domain.com/api/test?api_token=[your 60 char key]. You can also send the key as a header (if using Postman or similar), i.e: Header: Authorization, Value: Bearer [your 60 char key].
  • I order to get a useful error if the token is incorrect, also send the following header with all requests: Header: Accept, Value: application/json. This allows the expectsJson() check in the unauthenticated() function inside App/Exceptions/Handler.php to work correctly.

I found it hard to find clear docs from Laravel about using token auth with 5.3, I think it's because there's a drive to make use of Passport, and it supports tokens in a different way. Here's the article that probably helped most getting it working: https://gistlog.co/JacobBennett/090369fbab0b31130b51

18 likes
Azirius's avatar

Thank you for answering your own question! This helped me with a hobby project!

hsl's avatar

Just ran into this, what's the best approach if you want to have an "internal" API that only works when the user is logged in? The token approach looks a little complex for that.

1 like
metSander's avatar

I just created an account to thank you, this really helped me a lot!

2 likes
vule's avatar

Hi all, Thank for your great question and solution as well. I am on my way to do the same approach your but rather than expose it as URL query, I stored it as a cookie in the browser, my problems is the cookie is it self auto-encripted the token, so that when I use axios to sent back the encripted-token it of course cannot match to the token that store in the 'api_token' column in database. How can I decript the cookie before auth:api. Or any other ways to store the token in client?

Abdul-Qoyyum's avatar

I think it is possible to use local storage instead of cookie

Please or to participate in this conversation.