Skip to content

3.4.0 - token lifecycle, 401 retry, cart floats

Choose a tag to compare

@tomsommer tomsommer released this 07 Sep 18:14
· 1 commit to master since this release

Works through the remaining findings from the audit of 3.0.0. Requires tomsommer/oauth2-onpay ^2.1.

Token handling

  • A stored token carrying expires_in but no issue time never expired. expires_in is relative to the moment of issue, which a stored blob no longer records, so league recomputed the expiry from the current time on every read — leaving the token perpetually an hour fresh however old it really was. It is now treated as spent, and renewed.
  • An unparsable issued_at is likewise treated as spent rather than silently dropped.
  • Tokens are renewed 30 seconds early, so one that is technically alive but will be dead by the time it reaches OnPay does not cost a wasted round trip.
  • expires of 0 means no expiry in league's own terms; asking hasExpired() in that state raised a RuntimeException.
  • A non-string access_token no longer reaches the header, where it rendered as Bearer Array.
  • A malformed token response raised league's InvalidArgumentException, outside the documented exception contract. It is a TokenException now.

One retry after a 401

OnPay is the authority on whether a token is good. A 401 with a refresh token available is now worth exactly one refresh and retry, rather than an immediate failure over clock drift or a token revoked underneath us. With nothing to renew with, behaviour is unchanged — and a second 401 is final.

Cart totals

round(19.99 * 100) is 1999.0, and the total check compared it !== against int 1999, producing:

Cart total does not match amount for payment, cart total was calculated to: 1999, amount provided is: 1999

Amounts are normalised on the way into CartItem, as they already were for shipping and handling.

Also

SimplePayment indexed the response envelope unguarded — the same fault already fixed in the service classes. Converter returned false for anything but the documented date format, putting a bool in properties typed \DateTime; it now returns null and understands ISO-8601. A numeric-string currency code is as valid as an int. And "0" is a legitimate identifier that empty() was calling absent.

PaymentService, GatewayService, PaymentInfo and Converter had no tests at all; they do now. 164 tests, up from 140.