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
- Create a key
- Create a middleware that checks the API Key
- Create an example route and controller
- Test with Postman
- 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
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:
Launchphp 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 launchphp 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!
Â
Top comments (2)
This is very informative.
Since you mentioned testing the APIs with Postman, I'd like to suggest Hoppscotch as an alternative to it. Hoppscotch helps anyone to spin up a RESTful API with pre-determined data like this one: hopp.sh/r/FoKnVv5AyHIk
Checkout Hoppscotch.io - helps to make requests directly from the browser.
hoppscotch / hoppscotch
👽 Open source API development ecosystem - https://hoppscotch.io
Thanks Liyas, I will try it!