122 lines
4.1 KiB
PHP
122 lines
4.1 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\RefreshToken;
|
|
|
|
class AuthService
|
|
{
|
|
/**
|
|
* Generate RSA private/public key pair if missing
|
|
*/
|
|
public static function ensureKeysExist()
|
|
{
|
|
$privateKeyPath = env('JWT_PRIVATE_KEY_PATH', storage_path('keys/private.pem'));
|
|
$publicKeyPath = env('JWT_PUBLIC_KEY_PATH', storage_path('keys/public.pem'));
|
|
if (!file_exists($privateKeyPath) || !file_exists($publicKeyPath)) {
|
|
@mkdir(dirname($privateKeyPath), 0770, true);
|
|
@mkdir(dirname($publicKeyPath), 0770, true);
|
|
$cmd = "openssl genpkey -algorithm RSA -out $privateKeyPath -pkeyopt rsa_keygen_bits:2048 && openssl rsa -pubout -in $privateKeyPath -out $publicKeyPath";
|
|
exec($cmd);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Issue JWT access token for the given client
|
|
*/
|
|
public static function issueTokenForClient($client, $audience = null)
|
|
{
|
|
$privateKeyPath = env('JWT_PRIVATE_KEY_PATH', storage_path('keys/private.pem'));
|
|
if (!file_exists($privateKeyPath)) {
|
|
throw new \Exception('JWT private key not found');
|
|
}
|
|
$privateKey = file_get_contents($privateKeyPath);
|
|
$now = time();
|
|
$ttl = (int)env('JWT_TTL', 3600);
|
|
$ttl = (int)env('JWT_TTL', 3600 * 24 * 7);
|
|
$exp = $now + $ttl;
|
|
$aud = $audience ?: config('app.url');
|
|
$payload = [
|
|
'iss' => config('app.url'),
|
|
'sub' => $client->client_id,
|
|
'aud' => $aud,
|
|
'iat' => $now,
|
|
'exp' => $exp,
|
|
'jti' => \Illuminate\Support\Str::uuid()->toString(),
|
|
'scope' => $client->scopes,
|
|
'client_db_id' => $client->id,
|
|
];
|
|
return \Firebase\JWT\JWT::encode($payload, $privateKey, 'RS256');
|
|
}
|
|
|
|
/**
|
|
* Issue a refresh token for the client (random string, store in DB as needed)
|
|
*/
|
|
public static function issueRefreshToken($client)
|
|
{
|
|
return false;
|
|
// $rawToken = \Illuminate\Support\Str::random(64);
|
|
// $hashedToken = hash('sha256', $rawToken); // or use bcrypt if you prefer
|
|
|
|
// $refresh = RefreshToken::create([
|
|
// 'client_id' => $client->id,
|
|
// 'token' => $hashedToken,
|
|
// 'expires_at' => now()->addDays(30),
|
|
// 'revoked' => false,
|
|
// ]);
|
|
|
|
// // Return the raw token to the client
|
|
// return $rawToken;
|
|
}
|
|
|
|
/**
|
|
* Verify JWT token and return decoded payload or false
|
|
*/
|
|
public static function verifyToken($token)
|
|
{
|
|
$publicKeyPath = env('JWT_PUBLIC_KEY_PATH', storage_path('keys/public.pem'));
|
|
if (!file_exists($publicKeyPath)) {
|
|
throw new \Exception('JWT public key not found');
|
|
}
|
|
$publicKey = file_get_contents($publicKeyPath);
|
|
try {
|
|
return \Firebase\JWT\JWT::decode($token, new \Firebase\JWT\Key($publicKey, 'RS256'));
|
|
} catch (\Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static function verifyClientToken($token)
|
|
{
|
|
try {
|
|
$parts = explode('.', $token);
|
|
|
|
|
|
if (count($parts) !== 3) {
|
|
return false;
|
|
}
|
|
// $payload = json_decode(base64_decode(strtr($parts[1], '-_', '+/')));
|
|
$payloadRaw = $parts[1];
|
|
$payloadRaw = strtr($payloadRaw, '-_', '+/');
|
|
$padding = strlen($payloadRaw) % 4;
|
|
if ($padding) {
|
|
$payloadRaw .= str_repeat('=', 4 - $padding);
|
|
}
|
|
$payload = json_decode(base64_decode($payloadRaw));
|
|
$clientId = $payload->sub ?? null;
|
|
if (!$clientId) {
|
|
return false;
|
|
}
|
|
|
|
$clients = config('api_clients.clients');
|
|
|
|
$client = collect($clients)->where('api_key', $clientId)->first();
|
|
if (!$client || !isset($client['api_secret'])) {
|
|
return false;
|
|
}
|
|
return \Firebase\JWT\JWT::decode($token, new \Firebase\JWT\Key($client['api_secret'], 'HS256'));
|
|
} catch (\Exception $e) {
|
|
return false;
|
|
}
|
|
}
|
|
} |