skip to Main Content

I am using JWT Token Authentication with lexik/jwt-authentication-bundle version 2.18.1.
I have an API and my complete user information is stored in the JWT token I get from an external system.
The information is an multidimensional array with the user identifier "uid" being stored in the user.

Example:

{
    "application": {
        "appcode": "my_app"
    },
    "user": {
        "uid": "p320666",
        "firstname": "John",
        "mail": "John.Doe.com",
        "lastname": "Doe"
    },
    "grants": [
        "create"
    ],
    "resources": [
        {
            "code": "foo",
            "values": [
                "5"
            ]
        }
    ],
    "updateDate": {}
}

My user identifier is uid and it is in the 2nd level of my information array.

If I set in my configuration user_id_claim: user I get understandably the warning:
Array to string conversion because in JWTAuthenticator.php

        $passport = new SelfValidatingPassport(
            new UserBadge(
                (string)$payload[$idClaim],
                function ($userIdentifier) use ($payload) {
                    return $this->loadUser($payload, $userIdentifier);
                }
            )
        );

it tries to read my user array as a string.

If I set uid in my configuration it isn’t found. user.uid also doesn’t work.

Is there an option to access my uid information without changing the structure of the payload?

2

Answers


  1. Chosen as BEST ANSWER

    I solved it now by writing a custom authenticator:

    security.yaml

    security:
      enable_authenticator_manager: true
      providers:
        jwt:
          lexik_jwt:
            class: AppSecurityUserUser
    
    [...]
    
      firewalls: # selbstdefinierte Bereiche: dev oder doc können auch abc heißen
    [...]
        api:
          pattern: ^/api
          stateless: true
          jwt:
            authenticator: app.custom_authenticator
    

    services.yaml

      app.custom_authenticator:
        class: AppSecurityAuthenticationJwtTokenAuthenticator
        parent: lexik_jwt_authentication.security.jwt_authenticator
    

    lexik_jwt_authentication.yaml

    lexik_jwt_authentication:
    [...]
      pass_phrase: '%env(JWT_PASSPHRASE)%' # required for token creation
      token_ttl: 3600 # token TTL in seconds, defaults to 1 hour
      user_id_claim: user 
    

    and finally my custom authenticator where I changed the line (string) $payload[$idClaim]['uid'], and also call an extra class TokenDataProcessor to extract my complete user info from the payload:

    
    namespace AppSecurityAuthentication;
    
    [...]
    
    class JwtTokenAuthenticator extends JWTAuthenticator
    {
        private JWTTokenManagerInterface $jwtManager;
    
        public function __construct(
            JWTTokenManagerInterface $jwtManager,
            EventDispatcherInterface $eventDispatcher,
            TokenExtractorInterface $tokenExtractor,
            UserProviderInterface $userProvider,
            ?TranslatorInterface $translator = null
        ) {
            $this->jwtManager = $jwtManager;
            parent::__construct($jwtManager, $eventDispatcher, $tokenExtractor, $userProvider, $translator);
        }
    
    [...]
    
        public function doAuthenticate(Request $request): Passport
        {
            $token = $this->getTokenExtractor()->extract($request);
            if (false === $token) {
                $message = 'Unable to extract a JWT token from the request. Also, make sure to call `supports()`'
                           . ' before `authenticate()` to get a proper client error.';
                throw new LogicException($message);
            }
    
            try {
                if (!$payload = $this->jwtManager->parse($token)) {
                    throw new InvalidTokenException('Invalid JWT Token');
                }
            } catch (JWTDecodeFailureException $e) {
                if (JWTDecodeFailureException::EXPIRED_TOKEN === $e->getReason()) {
                    throw new ExpiredTokenException();
                }
    
                throw new InvalidTokenException('Invalid JWT Token', 0, $e);
            }
    
            $idClaim = $this->jwtManager->getUserIdClaim();
            if (!isset($payload[$idClaim])) {
                throw new InvalidPayloadException($idClaim);
            }
    
            $passport = new SelfValidatingPassport(
                new UserBadge(
                    (string) $payload[$idClaim]['uid'],
                    function ($userIdentifier) use ($payload) {
                        return $this->loadUser($payload, $userIdentifier);
                    }
                )
            );
    
            $passport->setAttribute('payload', $payload);
            $passport->setAttribute('token', $token);
    
            return $passport;
        }
    
        public function loadUser(array $payload, string $identity): UserInterface
        {
            try {
                $user = (new TokenDataProcessor())
                    ->extract($payload);
    
                return $user;
            } catch (InvalidAuthDataException $e) {
                $message = 'Authentication Failure with Credentials: ' . json_encode($payload)
                           . ' - ' . $e->getMessage();
                $this->logInfo($message);
                throw new ApiException(401, $message, $e, [], 7020);
            }
        }
    }
    

  2. Try this,
    To extract the uid property from the JSON string in PHP, you can decode the JSON string into an associative array using json_decode(), and then access the uid property as you would with any associative array. Here’s how you can do it:

    $jsonString = '{
        "application": {
            "appcode": "my_app"
        },
        "user": {
            "uid": "p320666",
            "firstname": "John",
            "mail": "John.Doe.com",
            "lastname": "Doe"
        },
        "grants": [
            "create"
        ],
        "resources": [
            {
                "code": "foo",
                "values": [
                    "5"
                ]
            }
        ],
        "updateDate": {}
    }';
    
    // Decode the JSON string into an associative array
    $data = json_decode($jsonString, true);
    
    // Access the 'uid' property from the 'user' object
    $uid = $data['user']['uid'];
    
    echo $uid; // Output: p320666
    

    In this code:

    json_decode($jsonString, true) decodes the JSON string into an associative array. The second parameter true is used to specify that we want an associative array instead of an object.
    We then access the uid property using array notation ($data['user']['uid']).
    This will give you the value of the uid property from your JSON string.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search