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?
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 = (
! empty($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!
If you liked this post, don't forget to add your Subscribe to my newsletter!
Subscribe to my newsletter
Read articles from Tony Joe directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Tony Joe
Tony Joe
Senior Dev. Clean code lover and therefore lover of Laravel. Best friend of deep work & focusing. Interested in critical thinking, self improvement, personal finance and rock'🤟'roll! 📍 I’m curious. I read a lot, listen, study, analyze. But I can’t stand fanaticism: I don’t like chasing after the last-minute framework all the time.