getPathInfo() === '/login' && $request->headers->has('Authorization')) { return true; } return false; } public function authenticate(Request $request): Passport { $authHeader = $request->headers->get('Authorization'); if (!str_starts_with($authHeader, 'Nostr ')) { throw new AuthenticationException('Invalid Authorization header'); } $eventStr = base64_decode(substr($authHeader, 6), true); $encoders = [new JsonEncoder()]; $normalizers = [new ObjectNormalizer()]; $serializer = new Serializer($normalizers, $encoders); /** @var Event $event */ $event = $serializer->deserialize($eventStr, Event::class, 'json'); if (time() > $event->getCreatedAt() + 60) { throw new AuthenticationException('Expired'); } $validity = (new SchnorrSignature())->verify($event->getPubkey(), $event->getSig(), $event->getId()); if (!$validity) { throw new AuthenticationException('Invalid Authorization header'); } $key = new Key(); return new SelfValidatingPassport( new UserBadge($key->convertPublicKeyToBech32($event->getPubkey())) ); } public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response { return new Response('Authentication Successful', 200); } public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response { return null; } public function isInteractive(): bool { return true; } }