How to simply expose an endpoint with API Key in Laravel

tonyjoe

Tony Joe Dev

Posted on August 2, 2023

How to simply expose an endpoint with API Key in Laravel

We all need, sooner or later, to expose an endpoint quickly and with the greatest possible security.
Laravel provides advanced methods to manage authentication, whether username/password or API token.

But here we are talking about an agile method that we can use in a project where, for example, we do not intend to use users or use Laravel Sanctum.


First, the basics: What is an API Key?

The Key

An API Key is a key or token to be used for authenticating one or more server-to-server calls.

In other words, it is a secret key and therefore must never be exposed in the frontend code (such as that of a SPA).


Steps

  1. Create a key
  2. Create a middleware that checks the API Key
  3. Create an example route and controller
  4. Test with Postman
  5. Create a test class

1. Create a key

Add a variable in the .env file:

# .env
# ...

APP_FAST_API_KEY=paste_here_a_generated_api_key
Enter fullscreen mode Exit fullscreen mode

The key must be in the .env file, because we don't want to keep it in repository.

šŸ’” SMALL TIP to generate a key on the fly:
Launch php artisan tinker and then simply \Str::random(64)

Generate an API Key on-fly


Then, add an array key that refer the variable in the .env file:

// config/app.php

return [
    // ...

    'fast_api_key' => env('APP_FAST_API_KEY'),

];
Enter fullscreen mode Exit fullscreen mode

šŸ’” SMALL TIP:
In case, remember to launch php artisan cache:config


2. Create a middleware that checks the API Key

$ php artisan make:middleware VerifyFastApiKey
Enter fullscreen mode Exit fullscreen mode
// app/Http/Middleware/VerifyFastApiKey.php

class VerifyFastApiKey
{
    public function handle(Request $request, Closure $next): Response
    {
        $apiKey = config('app.fast_api_key');

        $apiKeyIsValid = (
            ! empty($apiKey)
            && $request->header('x-api-key') == $apiKey
        );

        abort_if (! $apiKeyIsValid, 403, 'Access denied');

        return $next($request);
    }
}
Enter fullscreen mode Exit fullscreen mode

Create an alias for this middleware:

// app/Http/Kernel.php

class Kernel extends HttpKernel
{
    // ...

    protected $middlewareAliases = [
        // ...

        'with_fast_api_key' => \App\Http\Middleware\VerifyFastApiKey::class,
    ];

}
Enter fullscreen mode Exit fullscreen mode

3. Create an example route and controller

Add some routes in routes/api.php with the newly created with_fast_api_key middleware:

// routes/api.php

Route::group([
    'prefix' => 'v1',
    'middleware' => 'with_fast_api_key'
], function () {

    Route::post('/just/an/example', [SomethingController::class, 'justAnExample']);

    // ...
});
Enter fullscreen mode Exit fullscreen mode

Create an example controller:

$ php artisan make:controller SomethingController
Enter fullscreen mode Exit fullscreen mode
// app/Http/Controllers/SomethingController.php

class SomethingController extends Controller
{
    public function justAnExample()
    {
        return [
            'msg' => 'It works!'
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

4. Test with Postman

First, call the endpoint /just/an/example without an API Key set in Headers, and check if it fails as expected:

Test the endpoint - 403


Finally, call the endpoint /just/an/example with the correct API Key set in the Header X-API-Key, and check if it works as expected:

Test the endpoint - OK 200


5. Create a test class

Make test class:

$ php artisan make:test FastApiKeyTest
Enter fullscreen mode Exit fullscreen mode

Add some test methods:

// tests/Feature/FastApiKeyTest.php

class FastApiKeyTest extends TestCase
{
    public function test_fail_without_api_key(): void
    {
        $response = $this->postJson('/api/v1/just/an/example');

        $response->assertStatus(403);
    }

    public function test_fail_with_wrong_api_key(): void
    {
        $response = $this->postJson('/api/v1/just/an/example', [], [
            'X-API-Key' => 'a-wrong-key'
        ]);

        $response->assertStatus(403);
    }

    public function test_success_with_corrent_api_key(): void
    {
        $response = $this->postJson('/api/v1/just/an/example', [], [
            'X-API-Key' => config('app.fast_api_key')
        ]);

        $response->assertStatus(200);
    }
}
Enter fullscreen mode Exit fullscreen mode

Finally, launch the tests:

$ php artisan test
Enter fullscreen mode Exit fullscreen mode

Launch the tests


āœø Enjoy your coding!

Ā 

If you liked this post, don't forget to add your Follow to my profile!

If you want to preview my content, Subscrive to my Newsletter!
šŸ’– šŸ’Ŗ šŸ™… šŸš©
tonyjoe
Tony Joe Dev

Posted on August 2, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related