January 13, 2016 14:44

Laravel 5.2 has much better support for allowing multiple methods of authentication.

For example, you may want to authorize users with a username and password on the website, but with a random token string on the API.

Setting up tokens is simple enough, assuming you have all of the default config. First you need to add a column called api_token to your users table. It can be any length but the longer it is, the more secure.

Here is an example migration:

Schema::table('users', function (Blueprint $table) {
     $table->char('api_token', 60)->nullable()->after('remember_token');
});

Then you need to make sure that the api guard is specified for any API routes. Unfortunately, Laravel is not able to determine this by itself; it simply defaults to the web guard.

Route::group(['middleware' => ['auth:api']], function()
{
    // API routes here
});

Finally you just need to pass this api_token when sending an API request. There are multiple ways you can do this. Check out the TokenGuard class to see where I'm getting this:

  • as a GET parameter named api_token
  • as an Authorization header (Authorization: Bearer [api_token])
  • or as an auth password

Here is how you would use each of those methods with Guzzle:

$guzzle = new GuzzleHttp\Client();
$guzzle->request($url, ['api_token' => $api_token]);
$guzzle->request($url, [], ['headers' => ['Authorization' => 'Bearer ' . $api_token]]);
$guzzle->request($url, [], ['auth' => [$username, $api_token]]);

The bearer token may take some additional setup. Apache sometimes strips the Authorization token from requests, so you need to add these two lines to your public/.htaccess file:

RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

Finally, of course, you need to generate an api_token for every user that is using the API. Best to do this when creating the user.

Note about upgrades

If you're upgrading from Laravel 5.1 or earlier, chances are you'll need to update some other files.

If you followed the upgrade instructions, you should have already added an "api" guard with a "token" driver to config/auth.php:

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

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

You may also need to update your Authenticate middleware. In file app/Http/Middleware/Authenticate.php, make sure your handle method takes a $guard as an argument and that that guard is used when checking if the user is logged in. The final method should look like this:

public function handle($request, Closure $next, $guard = null)
{
   if (Auth::guard($guard)->guest()) {
        if ($request->ajax()) {
            return response('Unauthorized.', 401);
        } else {
            return redirect()->guest('auth/login');
        }
    }

    return $next($request);
}

Laravel