public static function ensureInputDataAreValid(GrantType $grantType, TokenRequestAttempt $tokenRequestAttempt)
 {
     $inputDataKeys = $tokenRequestAttempt->getInputData()->all();
     // check if we got the actual input data or just its keys
     if (array_keys($tokenRequestAttempt->getInputData()->all()) !== range(0, count($tokenRequestAttempt->getInputData()->all()) - 1)) {
         $inputDataKeys = array_keys($tokenRequestAttempt->getInputData()->all());
     }
     // using != instead of !== does not check the order of the properties
     if ($grantType->getRequiredInputData() != array_values(array_intersect($inputDataKeys, $grantType->getRequiredInputData()))) {
         throw new MissingOrInvalidInputData($grantType->getIdentifier(), $inputDataKeys, $grantType->getRequiredInputData());
     }
 }
 private function buildAccessToken(TokenRequestAttempt $tokenRequestAttempt, GrantDecision $grantDecision)
 {
     if ($grantDecision->isDenied()) {
         throw new \LogicException('Unable to build an access token with a denied decision');
     }
     $token = $this->configuration->getTokenGenerator()->generate(['length' => $this->configuration->getAccessTokenLength()]);
     $expiresAt = new \DateTime('now', new \DateTimeZone('UTC'));
     $expiresAt->add(\DateInterval::createFromDateString(sprintf("%d seconds", $this->configuration->getAccessTokenTTL())));
     $accessToken = new AccessToken($token, \DateTimeImmutable::createFromMutable($expiresAt), $tokenRequestAttempt->getInputData()->getClientId(), $grantDecision->getResourceOwner(), []);
     $this->accessTokenStorage->save($accessToken);
     return $accessToken;
 }