diff --git a/app/Http/Middleware/EnsureApiAccessIsAllowed.php b/app/Http/Middleware/EnsureApiAccessIsAllowed.php new file mode 100644 index 0000000..244af83 --- /dev/null +++ b/app/Http/Middleware/EnsureApiAccessIsAllowed.php @@ -0,0 +1,34 @@ +user(); + + if ($user === null || ! $this->featureAccess->allows($user, 'api_access')) { + return $this->errorFactory->make( + code: 'api_not_available', + message: 'API access is not available on your current plan.', + status: 403, + ); + } + + return $next($request); + } +} diff --git a/bootstrap/app.php b/bootstrap/app.php index 063ec62..c32a134 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -1,6 +1,7 @@ alias([ 'api.key' => AuthenticateApiKey::class, + 'api.access' => EnsureApiAccessIsAllowed::class, ]); }) ->withExceptions(function (Exceptions $exceptions): void { diff --git a/routes/api.php b/routes/api.php index d7b709d..6de2f49 100644 --- a/routes/api.php +++ b/routes/api.php @@ -11,10 +11,14 @@ ]))->name('health'); Route::middleware('api.key')->group(function () { - // Test-only route to verify auth middleware wiring. - // Only registered in testing environment. if (app()->environment('testing')) { Route::get('/auth-test', fn () => response()->json(['authenticated' => true])); } }); + + Route::middleware(['api.key', 'api.access'])->group(function () { + if (app()->environment('testing')) { + Route::get('/access-test', fn () => response()->json(['access' => true])); + } + }); }); diff --git a/tests/Feature/Api/V1/ApiAccessFeatureGateTest.php b/tests/Feature/Api/V1/ApiAccessFeatureGateTest.php new file mode 100644 index 0000000..ca4aa9e --- /dev/null +++ b/tests/Feature/Api/V1/ApiAccessFeatureGateTest.php @@ -0,0 +1,35 @@ +create(['plan' => Plan::Free]); + $generated = app(ApiKeyGenerator::class)->create($user, 'Free key'); + + $this->withToken($generated->plainToken) + ->getJson('/api/v1/access-test') + ->assertForbidden() + ->assertJsonPath('error.code', 'api_not_available'); +}); + +it('allows pro user to access protected api endpoints', function () { + $user = User::factory()->create(['plan' => Plan::Pro]); + $generated = app(ApiKeyGenerator::class)->create($user, 'Pro key'); + + $this->withToken($generated->plainToken) + ->getJson('/api/v1/access-test') + ->assertOk(); +}); + +it('allows max user to access protected api endpoints', function () { + $user = User::factory()->create(['plan' => Plan::Max]); + $generated = app(ApiKeyGenerator::class)->create($user, 'Max key'); + + $this->withToken($generated->plainToken) + ->getJson('/api/v1/access-test') + ->assertOk(); +});