Can't get Lexik JWT token from other domain

1.4k views Asked by At

Symfony 4

I made a lexik jwt autorization by instruction:

https://h-benkachoud.medium.com/symfony-rest-api-without-fosrestbundle-using-jwt-authentication-part-2-be394d0924dd

It works fine from postman or console curl. When I try to get token by ajax request (from other domain) I have standart error

No 'Access-Control-Allow-Origin' header is present on the requested resource.

I try to fix it by nelmio_cors bundle

BUT

If I take token by postman or console curl - debugger even doesn't enter to the controller, and I get token (I even don't know how).

If I try to take token by ajax request (from other domain) AFTER installing nelmio - I get into the controller: App\Controller\AuthController::getTokenUser

And I have an 500 error

Cannot autowire argument $user of "App\Controller\AuthController::getTokenUser()": it references interface "Symfony\Component\Security\Core\User\UserInterface" but no such service exists. Did you create a class that implements this interface?

I dont understand why with nelmio_cors request from other domain gets to the controller, and doesn't get without nelmio_cors... How to fix it?

I need to have token by http request from other domain

security.yaml

    # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
    encoders:
        App\Entity\User:
            algorithm: bcrypt


    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: username

    firewalls:

        login:
            pattern:  ^/api/login
            stateless: true
            anonymous: true
            json_login:
                provider: app_user_provider
                check_path:               /api/login_check
                success_handler:          lexik_jwt_authentication.handler.authentication_success
                failure_handler:          lexik_jwt_authentication.handler.authentication_failure
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            anonymous: true

    # Easy way to control access for large sections of your site
    # Note: Only the *first* access control that matches will be used
    access_control:
        - { path: ^/register, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api/login_check, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/api/test,       roles: IS_AUTHENTICATED_FULLY }

router:

api_login_check:
  path: /api/login_check
  controller: App\Controller\AuthController::getTokenUser

AuthController:

<?php

namespace App\Controller;

use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Security\Core\User\UserInterface;

class AuthController extends ApiController
{

    /**
     * @param UserInterface $user
     * @param JWTTokenManagerInterface $JWTManager
     * @return JsonResponse
     */
    public function getTokenUser(UserInterface $user, JWTTokenManagerInterface $JWTManager)
    {
        return new JsonResponse(['token' => $JWTManager->create($user)]);
    }
}

nelmio_cors.yaml:

nelmio_cors:
    defaults:
        origin_regex: true
        allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
        allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
        allow_headers: ['Content-Type', 'Authorization']
        expose_headers: ['Link']
        max_age: 3600
    paths:
        '^/': null

CORS_ALLOW_ORIGIN='^.*$'

.htaccess:

RewriteEngine On
Options +FollowSymlinks
RewriteBase /

RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.*$ index.php [L]

Help please

2

There are 2 answers

2
wawa On

Your issue is (probably) with the UserInterface $user part of your Controller. Try to inject Security $security instead and then get the user object from $security.

<?php

namespace App\Controller;

use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\Security\Core\Security;

class AuthController extends ApiController
{

    /**
     * @param Security $security
     * @param JWTTokenManagerInterface $JWTManager
     * @return JsonResponse
     */
    public function getTokenUser(Security $security, JWTTokenManagerInterface $JWTManager): JsonResponse
    {
        return new JsonResponse(['token' => $JWTManager->create($security->getUser())]);
    }
}

As you can't autowire the current user in Symfony

0
Mirlo On

this solution works for me without get the user :

class ApiController extends AbstractFOSRestController
{

    public $jwtManager;
    public $tokenStorageInterface;
    public $serializer;
    public $imgProvider;

    public function __construct(ImageProvider $imgProvider, TokenStorageInterface $tokenStorageInterface, JWTTokenManagerInterface $jwtManager)
    {
        $this->jwtManager = $jwtManager;
        $this->tokenStorageInterface = $tokenStorageInterface;
        $this->serializer = new Serializer([new ObjectNormalizer()]);
        $this->imgProvider = $imgProvider;
    }

    /**
     * @Route(name="api_login", path="/api/login_check")
     * @return JsonResponse
     */
    public function api_login(): JsonResponse
    {
        $decodedJwtToken = $this->jwtManager->decode($this->tokenStorageInterface->getToken());

        return new JsonResponse([
            'token' => $decodedJwtToken
        ]);
    }
    }