config('app.url'), 'sub' => $username, 'typ' => 'ldap', 'is_admin' => $isAdmin, 'groups' => $groups, 'scopes' => $scopes, 'iat' => $now, 'exp' => $now + config('api.ldap_jwt_ttl'), ]; return JWT::encode($payload, $this->secret(), 'HS256'); } /** * @return array{username: string, is_admin: bool, scopes: list}|null */ public function validate(string $jwt): ?array { try { $decoded = JWT::decode($jwt, new Key($this->secret(), 'HS256')); $payload = (array) $decoded; if (($payload['typ'] ?? '') !== 'ldap') { return null; } return [ 'username' => (string) ($payload['sub'] ?? ''), 'is_admin' => (bool) ($payload['is_admin'] ?? false), 'scopes' => array_values((array) ($payload['scopes'] ?? [])), ]; } catch (UnexpectedValueException|\DomainException|\InvalidArgumentException) { return null; } } private function secret(): string { $key = config('app.key'); if (str_starts_with($key, 'base64:')) { return base64_decode(substr($key, 7), true) ?: $key; } return $key; } }