From 7a0cfba530d5107afbb4b638e8047f49c4955123 Mon Sep 17 00:00:00 2001 From: Ivan Moroz Date: Wed, 3 Jun 2026 16:27:45 +0300 Subject: [PATCH] CONV-296: Create API key generation service Co-Authored-By: Claude Sonnet 4.6 --- app/Services/Api/ApiKeyGenerator.php | 26 ++++++++++++ app/Services/Api/GeneratedApiKey.php | 15 +++++++ .../Services/Api/ApiKeyGeneratorTest.php | 40 +++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 app/Services/Api/ApiKeyGenerator.php create mode 100644 app/Services/Api/GeneratedApiKey.php create mode 100644 tests/Feature/Services/Api/ApiKeyGeneratorTest.php diff --git a/app/Services/Api/ApiKeyGenerator.php b/app/Services/Api/ApiKeyGenerator.php new file mode 100644 index 0000000..07a26a9 --- /dev/null +++ b/app/Services/Api/ApiKeyGenerator.php @@ -0,0 +1,26 @@ + $user->id, + 'name' => $name, + 'token_hash' => $hash, + ]); + + return new GeneratedApiKey(apiKey: $apiKey, plainToken: $plainToken); + } +} diff --git a/app/Services/Api/GeneratedApiKey.php b/app/Services/Api/GeneratedApiKey.php new file mode 100644 index 0000000..4988a7f --- /dev/null +++ b/app/Services/Api/GeneratedApiKey.php @@ -0,0 +1,15 @@ +create(); + + $result = app(ApiKeyGenerator::class)->create($user, 'Test key'); + + expect($result->plainToken)->toStartWith('fc_'); + expect($result->apiKey->name)->toBe('Test key'); + expect($result->apiKey->token_hash)->not->toBe($result->plainToken); + expect(hash('sha256', $result->plainToken))->toBe($result->apiKey->token_hash); +}); + +it('stores api key for the given user', function () { + $user = User::factory()->create(); + + $result = app(ApiKeyGenerator::class)->create($user, 'My key'); + + expect($result->apiKey->user_id)->toBe($user->id); + $this->assertDatabaseHas('api_keys', [ + 'user_id' => $user->id, + 'name' => 'My key', + 'token_hash' => hash('sha256', $result->plainToken), + ]); +}); + +it('does not store plain token in database', function () { + $user = User::factory()->create(); + + $result = app(ApiKeyGenerator::class)->create($user, 'Secure key'); + + $this->assertDatabaseMissing('api_keys', [ + 'token_hash' => $result->plainToken, + ]); +});