I’d add a third expiry case: now equals expires_at exactly. One millisecond before and after still leaves the equality rule undecided. Is a token valid through that timestamp, or already expired?
Keep that test on the injected clock too, with timezone-aware UTC values. Then a separate conversion test can cover a local clock crossing a daylight-saving change without changing the expiry contract. That makes the product decision visible instead of leaving it to whichever comparison operator the implementation happens to use.