/laravel-keyable

Add API keys to your Laravel models

Primary LanguagePHPMIT LicenseMIT

Laravel Keyable

Laravel Keyable is a package that allows you to add API Keys to any model. This allows you to associate incoming requests with their respective models. You can also use Policies to authorize requests.

Latest Stable Version Total Downloads License

Installation

Require the givebutter/laravel-keyable package in your composer.json and update your dependencies:

composer require givebutter/laravel-keyable

Publish the migration and config files:

php artisan vendor:publish --provider="Givebutter\LaravelKeyable\KeyableServiceProvider"

Run the migration:

php artisan migrate

Usage

Add the Givebutter\LaravelKeyable\Keyable trait to your model(s):

use Illuminate\Database\Eloquent\Model;
use Givebutter\LaravelKeyable\Keyable;

class Account extends Model
{
    use Keyable;

    // ...
}

Add the auth.apiKey middleware to the mapApiRoutes() function in your App\Providers\RouteServiceProvider file:

// ...

protected function mapApiRoutes()
{
    Route::prefix('api')
        ->middleware(['api', 'auth.apikey'])
	->namespace($this->namespace . '\API')
	->group(base_path('routes/api.php'));
}

// ...

The middleware will authenticate API requests, ensuring they contain an API key that is valid.

Accessing keyable models in your controllers

The model associated with the key will be attached to the incoming request as keyable:

use App\Http\Controllers\Controller;

class FooController extends Controller {

    public function index(Request $request) 
    {
        $model = $request->keyable;

        // ...
    }

}

Now you can use the keyable model to scope your associated API resources, for example:

return $model->foo()->get();

Keys Without Models

Sometimes you may not want to attach a model to an API key (if you wanted to have administrative access to your API). By default this functionality is turned off:

<?php
	
return [
	
    'allow_empty_models' => true
	
];

UUID support

Before migrate you can config if you prefer use bigint or uuid identifiers. By default use bigint like keyable_id

<?php

return [

    'identifier' => 'bigint'
    
];

Making Requests

By default, laravel-keyable uses bearer tokens to authenticate requests. Attach the API key to the header of each request:

Authorization: Bearer <key>

You can change where the API key is retrieved from by altering the setting in the keyable.php config file. Supported options are: bearer, header, and parameter.

<?php
	
return [
	
    'mode' => 'header',
	
    'key' => 'X-Authorization',
	
];

Need to pass the key as a URL parameter? Set the mode to parameter and the key to the string you'll use in your URL:

<?php
	
return [
	
    'mode' => 'parameter',
	
    'key' => 'api_key'
	
];

Now you can make requests like this:

https://example.com/api/posts?api_key=<key>

Authorizing Requests

Laravel offers a great way to perform Authorization on incoming requests using Policies. However, they are limited to authenticated users. We replicate that functionality to let you authorize requests on any incoming model.

To begin, add the AuthorizesKeyableRequests trait to your base Controller.php class:

<?php

namespace App\Http\Controllers;

// ...

use Givebutter\LaravelKeyable\Auth\AuthorizesKeyableRequests;

class Controller extends BaseController
{
    use AuthorizesKeyableRequests;
}

Next, create the app/Policies/KeyablePolicies folder and create a new policy:

<?php

namespace App\Policies\KeyablePolicies;

use App\Models\Post;
use Illuminate\Database\Eloquent\Model;
use Givebutter\LaravelKeyable\Models\ApiKey;

class PostPolicy {

    public function view(ApiKey $apiKey, Model $keyable, Post $post) {
    	return !is_null($keyable->posts()->find($post->id));
    }
    
}

Lastly, register your policies in AuthServiceProvider.php:

<?php

namespace App\Providers;

// ...

use App\Models\Post;
use App\Policies\KeyablePolicies\PostPolicy;
use Givebutter\LaravelKeyable\Facades\Keyable;

class AuthServiceProvider extends ServiceProvider
{
	
    // ...
    
    protected $keyablePolicies = [
        Post::class => PostPolicy::class
    ];

    public function boot(GateContract $gate)
    {
        // ...
        Keyable::registerKeyablePolicies($this->keyablePolicies);
    }
    
}

In your controller, you can now authorize the request using the policy by calling $this->authorizeKeyable(<ability>, <model>):

<?php

namespace App\Http\Controllers\PostController;

use App\Models\Post;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PostController extends Controller {

    public function show(Post $post) {
        $this->authorizeKeyable('view', $post);
        // ...
    }

}

Artisan Commands

Generate an API key:

php artisan api-key:generate --id=1 --type="App\Models\Account"

Delete an API key:

php artisan api-key:delete --id=12345

Security

If you discover any security related issues, please email liran@givebutter.com.

License

Released under the MIT license. See LICENSE for more information.