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?
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
Add a variable in the .env
file:
# .env
# ...
APP_FAST_API_KEY=paste_here_a_generated_api_key
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)
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'),
];
💡 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
// app/Http/Middleware/VerifyFastApiKey.php
class VerifyFastApiKey
{
public function handle(Request $request, Closure $next): Response
{
$apiKey = config('app.fast_api_key');
$apiKeyIsValid = (
filled($apiKey)
&& $request->header('x-api-key') === $apiKey
);
abort_if (! $apiKeyIsValid, 403, 'Access denied');
return $next($request);
}
}
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,
];
}
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']);
// ...
});
Create an example controller:
php artisan make:controller SomethingController
// app/Http/Controllers/SomethingController.php
class SomethingController extends Controller
{
public function justAnExample()
{
return [
'msg' => 'It works!'
];
}
}
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:
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:
5. Create a test class
Make test class:
php artisan make:test FastApiKeyTest
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);
}
}
Finally, launch the tests:
php artisan test
✸ Enjoy your coding!