You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
64 lines
1.6 KiB
64 lines
1.6 KiB
<?php |
|
|
|
namespace App\Services; |
|
|
|
use App\Models\ApiToken; |
|
use Illuminate\Support\Str; |
|
|
|
class ApiTokenService |
|
{ |
|
/** |
|
* @param list<string> $scopes |
|
* @return array{token: ApiToken, plain_text: string} |
|
*/ |
|
public function create(string $name, array $scopes, ?int $expiresInDays = null): array |
|
{ |
|
$plain = config('api.token_prefix') . Str::random(48); |
|
$prefix = substr($plain, 0, 12); |
|
|
|
$token = ApiToken::create([ |
|
'name' => $name, |
|
'token_prefix' => $prefix, |
|
'token_hash' => hash('sha256', $plain), |
|
'scopes' => array_values(array_unique($scopes)), |
|
'expires_at' => $expiresInDays ? now()->addDays($expiresInDays) : null, |
|
]); |
|
|
|
return ['token' => $token, 'plain_text' => $plain]; |
|
} |
|
|
|
public function findByPlainText(string $plainText): ?ApiToken |
|
{ |
|
if (! str_starts_with($plainText, config('api.token_prefix'))) { |
|
return null; |
|
} |
|
|
|
$prefix = substr($plainText, 0, 12); |
|
$token = ApiToken::where('token_prefix', $prefix)->first(); |
|
|
|
if ($token === null || ! hash_equals($token->token_hash, hash('sha256', $plainText))) { |
|
return null; |
|
} |
|
|
|
if ($token->expires_at !== null && $token->expires_at->isPast()) { |
|
return null; |
|
} |
|
|
|
$token->update(['last_used_at' => now()]); |
|
|
|
return $token; |
|
} |
|
|
|
public function revoke(ApiToken $token): void |
|
{ |
|
$token->delete(); |
|
} |
|
|
|
/** |
|
* @return list<ApiToken> |
|
*/ |
|
public function listAll(): array |
|
{ |
|
return ApiToken::orderByDesc('created_at')->get()->all(); |
|
} |
|
}
|
|
|