Skip to content

Timezone error in apple login . #1354

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
harrowmykel opened this issue May 2, 2025 · 6 comments
Open

Timezone error in apple login . #1354

harrowmykel opened this issue May 2, 2025 · 6 comments

Comments

@harrowmykel
Copy link

harrowmykel commented May 2, 2025

in \socialiteproviders\apple\Provider.php:155

             $constraints = [
                new SignedWith(new Sha256(), AppleSignerInMemory::plainText($publicKey['key'])),
                new IssuedBy(self::URL),

                // the culprit >>
                new LooseValidAt(SystemClock::fromSystemTimezone()),
            ];
            try {
                $jwtContainer->validator()->assert($token, ...$constraints);

                return true;
            } catch (RequiredConstraintsViolated $e) {
                throw new InvalidStateException($e->getMessage());
            }

The class LooseValidAt() checks that a token was not issued in the future by checking that iat is at least "PT0S" in the past. this causes a problem if the timezone is different or if the token is immediately generated by apple and the difference is less than 0 seconds due to different timezone. how can we make leeway value adjustable? or fix this?

           private function assertIssueTime(Token $token, DateTimeInterface $now): void
           {
               if (! $token->hasBeenIssuedBefore($now)) {
                   throw ConstraintViolation::error('The token was issued in the future', $this);
               }
           }
@harrowmykel
Copy link
Author

harrowmykel commented May 2, 2025

Example of the code and the result. As you can see the value of
(SystemClock::fromSystemTimezone())->now() is greater than $token->claims()->get(RegisteredClaims::ISSUED_AT),
by 0.27 seconds even though they are the same timestamp

Image

Image

Image

@harrowmykel
Copy link
Author

it is currently not possible to fix this issue in the providers package since class LooseValidAt does not accept a negative leeway.

I have created an issue now at JWT
lcobucci/jwt#1110

@SvenRtbg
Copy link

SvenRtbg commented May 6, 2025

Just to state it here: This isn't an issue with time zones. JWT are based on unix timestamps, which doesn't know about time zones, and PHP DateTime classes are well suited to handle time zones correctly.

The issue here seems that the Apple provider validates tokens using "LooseValidAt", which is at first glance supposed to add some leeway in case server and client clocks are not perfectly in sync, but without providing a value for how much leeway is supposed to be applied, the default is "zero seconds". "LooseValidAt" does not enforce a leeway, but is first and foremost to be used if the token does not guarantee to contain "iat", "nbf" and "exp" all at once. If the presence of all of these claims needs to be verified, then "StrictValidAt" should be used, but also this constraint offers to use a leeway parameter.

I am not familiar with details about this library, more specifically how one would be able to configure a suitable leeway value, but this is what needs to happen here, as it seems like the Apple server clock is off by about 270 milliseconds compared to the local time, or maybe this is simply the result of the token not providing fractional seconds for it's timestamps, but the locally generated DateTimeImmutable does provide fractional seconds.

It is my opinion that the LooseValidAt class correctly allows to check if a token is valid based on the leeway provided. Without a leeway, it will check that

  • now is greater or equal to the "iat" claim if this claim exists
  • now is greater or equal to the "nbf" claim if this claim exists
  • now is less than the "exp" claim if this claim exists.

If a nondefault, valid leeway is given, this value is added for "iat" and "nbf", with the effect that "now" is set some amount of seconds into the future when comparing, making token issuers that have a clock in the (not too distant) future validate correctly. If the issuer is running it's clock in the past, it isn't an issue here.

With the "exp" claim, the leeway is subtracted from now before comparing with the expiry time, allowing issuer clocks that run in the past to still be considered valid because "now" is set to the past as well. If the issuer clock is running in the future, then this isn't an issue here.

Without the leeway parameter, the token validation does require second-perfect sync between issuer and validator. Also remember that for some PHP version from the past, the DateTime classes switched from returning only full rounded seconds to fractional seconds in some use cases, which may or may not be a factor here.

TL;DR: This Apple provider needs to use a reasonable leeway when validating token issue times, just to cover for clocks being slightly out of sync.

@harrowmykel
Copy link
Author

@SvenRtbg thanks for the comment. I will try to make a pull request to this library.

@harrowmykel
Copy link
Author

changing to

new LooseValidAt(SystemClock::fromSystemTimezone(), new DateInterval('PT1S'));

will fix the issue. right? @SvenRtbg

@SvenRtbg
Copy link

SvenRtbg commented May 7, 2025 via email

harrowmykel added a commit to harrowmykel/Providers that referenced this issue May 7, 2025
harrowmykel added a commit to harrowmykel/Providers that referenced this issue May 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants