Why even I send GET request, the /api returns “Request body is empty” error in Symfony API Platform fusion auth based authentication

I’m new in Symfony and php. I want to authenticate users based fusion auth.

This is the action list:

Users requests for /login endpoint with their username and password.

The API sends request to /api/user to authenticate user login operation

Then the fusion provides an api auth token

Users can send to /api endpoint with this token

If this token is valid, the API is going to response for resource

Configuration file:

security:
    providers:
        app_user_provider:
            entity:
                class: AppEntityUserUser
                property: email
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        main:
            lazy: true
            provider: app_user_provider
            custom_authenticators:
                - AppSecurityTokenAuthenticator
    access_control:
        - { path: ^//login, roles: PUBLIC_ACCESS }
        - { path: ^/admin, roles: ROLE_ADMIN }
        - { path: ^/api, roles: ROLE_USER }
        - { path: ^/profile, roles: ROLE_USER }
        - { path: ^/$, roles: PUBLIC_ACCESS }
        - { path: ^/docs, roles: PUBLIC_ACCESS }

I’m getting request from this controller:

<?php

// src/Controller/SecurityController.php

namespace AppControllerSecurity;

use AppSecurityTokenAuthenticator;
use PHPUnitException;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationJsonResponse;
use SymfonyComponentRoutingAttributeRoute;
use SymfonyContractsHttpClientExceptionClientExceptionInterface;
use SymfonyContractsHttpClientExceptionRedirectionExceptionInterface;
use SymfonyContractsHttpClientExceptionServerExceptionInterface;
use SymfonyContractsHttpClientExceptionTransportExceptionInterface;
use SymfonyContractsHttpClientHttpClientInterface;

class SecurityController extends AbstractController
{
    private ?string $fusionAuthBaseUrl = null;
    private ?string $authorization = null;
    private ?string $applicationId = null;

    private ?array $headers = null;
    private ?HttpClientInterface $httpClient = null;

    public function __construct(HttpClientInterface $httpClient)
    {
        $this->httpClient = $httpClient;
        $this->fusionAuthBaseUrl = "https://example";
        $this->authorization = "authtokenprovidedfromFusionAuth";
        $this->applicationId = "applicationId";
        $this->headers = [
            'Authorization' =>$this->authorization,
            'Content-Type' => 'application/json'
        ];
    }

    #[Route('/login', name: 'user-login', methods: ['POST'])]
    public function login(Request $request, TokenAuthenticator $authenticator): JsonResponse
    {
      
        $content = json_decode($request->getContent(), true);
        $email = $content['email'] ?? null;
        $password = $content['password'] ?? null;

        try {

            // Call Fusion Auth Token endpoint to authenticate user
            $response = $this->httpClient->request('POST', $this->fusionAuthBaseUrl . '/api/login', [
                'headers' => $this->headers,
                'json' => [
                    'loginId' => $email,
                    'password' => $password,
                    'applicationId' => $this->applicationId
                ],
            ]);
            $data = $response->getContent();
            return new JsonResponse($data);

        } catch (ClientExceptionInterface $e) {
            return new JsonResponse(
                [
                    'error' => 'Client error',
                    'details' =>  $e->getMessage()
                ], 401);
        } catch (ServerExceptionInterface $e) {
            return new JsonResponse(
                [
                    'error' => 'Server error',
                    'details'=> $e->getMessage()
                ], 500);
        } catch (Exception $e) {
            return new JsonResponse(
                [
                    'error' => 'An unexpected error occurred',
                    'details' =>$e->getMessage()
                ], 500);
        } catch (RedirectionExceptionInterface $e) {
            return new JsonResponse(
                [
                    'error'=>'Redirection exception',
                    'details'=>$e->getMessage()
                ], 500);
        } catch (TransportExceptionInterface $e) {
            return new JsonResponse(
                [
                    'error'=>'Transport exception',
                    'details'=>$e->getMessage()
                ], 500);
        }
    }
}

User entity to store user id in database

<?php

namespace AppEntityUser;

use AppRepositoryUserUserRepository;
use DoctrineDBALTypesTypes;
use DoctrineORMMapping as ORM;
use SymfonyComponentSecurityCoreUserPasswordAuthenticatedUserInterface;
use SymfonyComponentSecurityCoreUserUserInterface;

#[ORMEntity(repositoryClass: UserRepository::class)]
#[ORMTable(name: 'users')]
class User implements UserInterface//, PasswordAuthenticatedUserInterface
{
    #[ORMId]
    #[ORMGeneratedValue]
    #[ORMColumn(type: Types::GUID, unique: true, nullable: false)]
    //Fusionauth id
    private ?string $uuid = null;

    #[ORMColumn(type: Types::TEXT)]
    private ?string $token = null;

    #[ORMColumn(type: Types::STRING, length: 255)]
    private ?string $email = null;


    #[ORMColumn(type: Types::STRING, length: 255)]
    private ?string $roles = null;

    public function getUuid(): ?string
    {
        return $this->uuid;
    }

    public function getEmail(): ?string
    {
        return $this->email;
    }

    public function setEmail(string $email): self
    {
        $this->email = $email;

        return $this;
    }

    public function getRoles(): array
    {
        return [$this->roles];
    }

    public function setRoles(?string $roles): self
    {
        $this->roles = $roles;

        return $this;
    }

    public function getSalt(): void
    {
        
    }

    public function getUsername(): string
    {
        return (string) $this->email;
    }

    public function setToken (?string $token): static
    {
        $this->token = $token;

        return $this;
    }

    public function getToken(): ?string
    {
        return $this->token;
    }

    public function eraseCredentials()
    {
        
    }

    public function getUserIdentifier(): string
    {
        return (string) $this->token;
    }

    public function getPassword(): ?string
    {
        return null;
    }
}

This is the user provider:

<?php

namespace AppSecurity;

use AppEntityUserUser;
use AppRepositoryAppUserRepository;
use PharIoVersionException;
use SymfonyComponentSecurityCoreExceptionUnsupportedUserException;
use SymfonyComponentSecurityCoreUserPasswordAuthenticatedUserInterface;
use SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreUserUserProviderInterface;

class UserProvider implements UserProviderInterface//, PasswordAuthenticatedUserInterface
{
    private ?UserRepository $userRepository = null;

    public function __construct(?UserRepository $userRepository) {
        $this->userRepository = $userRepository;
    }

    public function loadUserByUsername(?string $username): UserInterface
    {
        $user = $this->userRepository->findOneByUsername($username);
        if (!$user) {
            throw new Exception(sprintf('User with username "%s" not found.', $username));
        }
        return $user;
    }

    public function refreshUser(UserInterface $user): UserInterface
    {
        if (!$user instanceof User) {
            throw new UnsupportedUserException(sprintf('Invalid user class "%s".', get_class($user)));
        }

        $refreshedUser = $this->userRepository->find($user->getUuid());

        if (!$refreshedUser) {
            throw new Exception('User not found.');
        }

        return $refreshedUser;
    }

    public function supportsClass($class): bool
    {
        return User::class === $class;
    }

    public function loadUserByIdentifier(string $identifier): UserInterface
    {
        $user = $this->userRepository->findOneByIdentifier($identifier);

        if (!$user)
        {
           throw new Exception(sprintf('User with identifier "%s" not found.', $identifier));
        }

        return $user;
    }
}

I’m trying to authenticate user with this authenticator:

<?php

// src/Security/TokenAuthenticator.php

namespace AppSecurity;

use AppEntityUserUser;
use DoctrineORMEntityManagerInterface;
use SymfonyComponentHttpFoundationJsonResponse;
use SymfonyComponentHttpFoundationRequest;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentRoutingRouterInterface;
use SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface;
use SymfonyComponentSecurityCoreExceptionAuthenticationException;
use SymfonyComponentSecurityCoreExceptionCustomUserMessageAuthenticationException;
use SymfonyComponentSecurityCoreUserUserInterface;
use SymfonyComponentSecurityCoreUserUserProviderInterface;
use SymfonyComponentSecurityHttpAuthenticatorAbstractAuthenticator;
use SymfonyComponentSecurityHttpAuthenticatorPassportBadgeUserBadge;
use SymfonyComponentSecurityHttpAuthenticatorPassportCredentialsCustomCredentials;
use SymfonyComponentSecurityHttpAuthenticatorPassportCredentialsPasswordCredentials;
use SymfonyComponentSecurityHttpAuthenticatorPassportPassport;

class TokenAuthenticator extends AbstractAuthenticator
{
    private ?UserProvider $userProvider = null;

    public function __construct(UserProvider $userProvider)
    {
        $this->userProvider = $userProvider;
    }

    public function supports(Request $request): ?bool
    {
        return $request->headers->has('Authorization') && str_starts_with($request->headers->get('Authorization'), 'Bearer ');
    }
    public function getCredentials(Request $request): array
    {
        $token = substr($request->headers->get('Authorization'), 7); // Remove 'Bearer ' prefix
        return ['token' => $token];
    }

    public function getUser($credentials): ?UserInterface
    {
        $token = $credentials['token'];
        $user = $this->userProvider->loadUserByIdentifier($token);
        if (!$user)
        {
            throw new CustomUserMessageAuthenticationException('Invalid token');
        }
        return $user;
    }

    public function authenticate(Request $request): Passport
    {
        $credentials = $this->getCredentials($request);
        $user = $this->getUser($credentials);

        if (!$user) {
            throw new CustomUserMessageAuthenticationException('Invalid token.');
        }

        return new Passport(
            new UserBadge($user->getUserIdentifier())
            new CustomCredentials(function (?array $credentials){
                return true;
            }, []
            ));
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {

        return null;
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        // Doğrulama başarısız olduğunda yapılacak işlemler
        return new JsonResponse(['error' => 'Authentication failed error',
            'exception' => $exception->getMessage(),
            'request-user' => $request->getUser(),
            'request' => $request->toArray(),
            'request-host' =>  $request->getHost(),
            'trace' => $exception->getTrace()
        ], Response::HTTP_UNAUTHORIZED);
    }
}

When I try to /login with my credentials, I’m getting a token from fusion. Now I need to get this token to access to the /api endpoint but when I try to send GET request with Authorization Bearer token, the API responses like that:

{
    "@id": "/api/errors/400",
    "@type": "hydra:Error",
    "title": "An error occurred",
    "detail": "Request body is empty.",
    "status": 400,
    "type": "/errors/400",
    "trace": [
        {
            "file": "C:\Users\Onur\Desktop\yakalamac\vendor\symfony\http-kernel\Kernel.php",
            "line": 197,
            "function": "handle",
            "class": "Symfony\Component\HttpKernel\HttpKernel",
            "type": "->"
        },
        {
            "file": "C:\Users\Onur\Desktop\yakalamac\vendor\symfony\runtime\Runner\Symfony\HttpKernelRunner.php",
            "line": 35,
            "function": "handle",
            "class": "Symfony\Component\HttpKernel\Kernel",
            "type": "->"
        },
        {
            "file": "C:\Users\Onur\Desktop\yakalamac\vendor\autoload_runtime.php",
            "line": 29,
            "function": "run",
            "class": "Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner",
            "type": "->"
        },
        {
            "file": "C:\Users\Onur\Desktop\yakalamac\public\index.php",
            "line": 5,
            "function": "require_once"
        }
    ],
    "hydra:title": "An error occurred",
    "hydra:description": "Request body is empty."
}

But this is a normal GET request, so it’s no need to have a body. Also I don’t know how can I check this token does valid. Can you give me some idea about this please.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật