![JSON APIs with Laravel: Part 5 - Authentication and Permissions cover image](https://d33wubrfki0l68.cloudfront.net/b170417fc959f9608d8315015b549d739ea6d1f9/a33e9/assets/img/api-series-part-5.jpg)
JSON APIs with Laravel: Part 5 - Authentication and Permissions
Oliver Sarfas • August 27, 2019
programming laravelThis a part of my "JSON APIs with Laravel" series. If you've missed any of the previous episodes you can find them at the bottom of this article
Recap
Basic API is working as needed. But now, we need to add some basic authentication to give ourselves some control over who can do what.
Of course, this is entirely optional, so don't worry if you don't need it. Some APIs are public by design and will not require any of this.
Authentication
For our API authentication we will be using the jwt-auth package. To get started with it and get it installed, follow the Wiki found here
In a nutshell, this adds a new middleware called auth:api
that we can use to protect our endpoints. For those interested, it's a custom Guard for Laravel that uses Token based Authentication against your user model.
Once installed, we'll need to add the new auth:api
middleware to our controller / methods that we want to protect. In this instance, we're going to protect ALL of our API methods.
Protecting API endpoints
To add our auth:api
middleware to the routes, we can either control them method-by-method, or just stick it on the controller. Equally, we can protect the Route declaration.
The chosen method is entirely down to personal preference. For this example, I'm going to put the middleware declaration in the Route declaration in the routes/web.php
file.
We're going to change our file to look like the following;
# File; routes/web.php
<?php
Route::resource('contact', 'ContactController')->middleware([
'auth:api',
]);
Now, whenever a request is made to any of our endpoints, you'll need to send Authorization
headers with your request; preferably with a Bearer
token method. There are alternative methods, using ?token={{token}}
for instance.
Permissions
For granular permissions we're going to use Laravel Policies. So we'll make the ContactPolicy
class, using the following command;
```shell script php artisan make:policy ContactPolicy --model=Contact
This gives us the `app\Policies\ContactPolicy` class, which we can give some granular permissions to. First, we'll register it in our `AuthServiceProvider`.
```php
# File: app\Providers\AuthServiceProvider.php
<?php
namespace App\Providers;
use App\Contact;
use App\Policies\ContactPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
Contact::class => ContactPolicy::class,
];
/**
* Register any authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
}
}
Now our policy is mapped, we can run authorize()
methods on our Contact
model to ensure that the user has permission to do the action, before it is persisted/read to the database.
Granular permissions per method
For the sake of keeping this short, I'm going to show only one of our BREAD methods below. The same logic follows for the other 4, and you can extract this out to make your own concepts as well.
In this instance, we're going to restrict the Read method to only those who have an email address ending in @sarfas.codes
.
To do so, go to the view(User $user, Contact $contact)
method on our new ContactPolicy class.
We need to add the following logic to return a boolean, this boolean determines whether the action is allowed;
public function view(User $user, Contact $contact)
{
return Str::endsWith($user->email, '@sarfas.codes');
}
Now, we just need to check if the user can do this, at the controller level. So let's go to the show()
method in our controller and review it. Our show method needs to look like the following;
# File: app\Http\Controllers\ContactController.php
<?php
[...]
/**
* Display the specified resource.
*
* @param Request $request
* @param Contact $contact
*
* @return Response
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function show(Request $request, Contact $contact)
{
$this->authorizeForUser($request->user, 'view', $contact);
return response()->json($contact);
}
[...]
This will check that the current user has sufficient permission to view
the given Contact based on the Policy logic we've written. If it fails, the server will throw an AuthorizationException
resulting in a HTTP 401
error.
Next Up? The end?
What do you want us to do next?. I'm at a crossroads on where to take this series right now 🤔 We've got a basic API, added some permissions and auth - so that should do for 90% of projects. You can get into rate limiting, verbose logging and the like, however they could realistically do with a series all of their own.
Let me know on twitter where you'd like this to go, or if there's any part of Laravel that you'd like me to go into detail on.