5.3: api routes, auth middleware confusion

Published 1 year ago by meredevelopment

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)

Best Answer (As Selected By meredevelopment)
meredevelopment

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

bugsysha
bugsysha
1 year ago (142,225 XP)

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

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
bugsysha
1 year ago (142,225 XP)

Maybe the best way to understand it is to execute command

php artisan route:list
meredevelopment

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\[email protected]                           | api,auth:api |
|        | GET|HEAD  | api/v2/members               | members.index   | App\Http\Controllers\[email protected]                           | api,auth:api |
|        | GET|HEAD  | api/v2/members/create        | members.create  | App\Http\Controllers\[email protected]                          | api,auth:api |
|        | PUT|PATCH | api/v2/members/{member}      | members.update  | App\Http\Controllers\[email protected]                          | api,auth:api |
|        | GET|HEAD  | api/v2/members/{member}      | members.show    | App\Http\Controllers\[email protected]                            | api,auth:api |
|        | DELETE    | api/v2/members/{member}      | members.destroy | App\Http\Controllers\[email protected]                         | api,auth:api |
|        | GET|HEAD  | api/v2/members/{member}/edit | members.edit    | App\Http\Controllers\[email protected]                            | api,auth:api |
|        | GET|HEAD  | api/v2/user                  |                 | Closure                                                                | api,auth:api |
|        | GET|HEAD  | home                         |                 | App\Http\Controllers\[email protected]                              | web,auth     |
|        | GET|HEAD  | login                        | login           | App\Http\Controllers\Auth\[email protected]                | web,guest    |
|        | POST      | login                        |                 | App\Http\Controllers\Auth\[email protected]                        | web,guest    |
|        | POST      | logout                       |                 | App\Http\Controllers\Auth\[email protected]                       | web          |
|        | POST      | password/email               |                 | App\Http\Controllers\Auth\[email protected]  | web,guest    |
|        | POST      | password/reset               |                 | App\Http\Controllers\Auth\[email protected]                | web,guest    |
|        | GET|HEAD  | password/reset               |                 | App\Http\Controllers\Auth\[email protected] | web,guest    |
|        | GET|HEAD  | password/reset/{token}       |                 | App\Http\Controllers\Auth\[email protected]        | web,guest    |
|        | POST      | register                     |                 | App\Http\Controllers\Auth\[email protected]                  | web,guest    |
|        | GET|HEAD  | register                     |                 | App\Http\Controllers\Auth\[email protected]      | web,guest    |

Thanks!

bugsysha
bugsysha
1 year ago (142,225 XP)
meredevelopment

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

Azirius
Azirius
1 year ago (47,210 XP)

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

hsl
hsl
8 months ago (2,465 XP)

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.

kapilvermasgnr

What if someone steal my api_token ?

Scoop7
Scoop7
3 weeks ago (42,900 XP)

@hsl sounds like you want and auth middleware then

Please sign in or create an account to participate in this conversation.