3.3.0 - OAuth state verification
The OAuth callback can now verify state.
authorize() has always returned a URL carrying a random state, but nothing could check it on the way back: finishAuthorize() took only the code, the facade exposed no way to reach the state, and the README's callback example spent the code without looking at it.
Upstream did have a check — it compared the returned state against crypt() of a fixed provider id, which is deterministic and therefore not a check. Removing that vestige in 2.0.0 left the gap visible rather than disguised.
Without a state check, a callback cannot be told apart from one an attacker made the visitor follow, which is login CSRF / authorization-code injection.
What changed
$authUrl = $api->authorize();
$_SESSION['onpay_oauth_state'] = $api->getState(); // new
header('Location: ' . $authUrl);
// on the callback
$api->finishAuthorize(
$_GET['code'],
$_GET['state'] ?? null,
$_SESSION['onpay_oauth_state'] ?? null
);The two states are compared with hash_equals() before the code is spent, so a mismatch never reaches the token endpoint.
This is additive: finishAuthorize($code) with no state behaves as it did, for callers who already do the comparison themselves. Supplying one half of the pair and not the other is treated as a mistake rather than a pass.
Both README flows — the plain one and the PKCE one — now store the state before redirecting and hand it back.
Integrations authenticating with StaticToken never enter this flow and are unaffected.