Add per-client token TTL and expiry support for client credentials - #77
Conversation
|
@abhishek-kaushik could you give me a review of #75 (I added you to this repo) so we can merge tests, and then add test with this PR |
sure @joehoyle , can do it |
|
Ok tests per merged, you should be able to add tests here now |
|
@abhishek-kaushik ping on the above ^ |
The test harness from WP-API#75 and the PHP 7.4+ baseline only exist on main, so the branch has to catch up before tests can be written against it. The only conflict was the use statement block in the authentication namespace, where both sides added an import. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Covers the four parts of the feature: the TTL stored on the client, the expiry stamped on a client credentials token, the authentication layer rejecting an expired token, and expires_in in the token response. Each case was checked by mutation: disabling any one of the four code paths in turn fails at least one of these tests. Two edges are pinned deliberately. A token at exactly its expiry timestamp counts as expired, because the check is `>=`. An expired token still resolves from get_by_id(), so the authentication layer can tell an expired token apart from an unknown one and return the right error. test-admin.php is new — validate_parameters() had no coverage, and the TTL field is validated there. The existing test_is_valid_always_true() is renamed: is_valid() is no longer unconditional now that it defers to is_expired(). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The PHPCS job fails on this branch: the TTL comparisons are not Yoda conditions, and reordering the Access_Token constants left the equals signs unaligned. Both are WPCS rules the rest of the plugin follows. No behaviour change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@joehoyle I've added the tests. I also merged 34 new tests, in four places:
I checked the tests are worth having by breaking each of the four code paths in turn. Every one of them fails at least one test. Two edges are pinned on purpose. A token at exactly its expiry second counts as expired, since the check is Last commit fixes PHPCS on the TTL code (Yoda conditions, and the constant alignment that the reordering in One thing I left alone: 🤖 Generated with Claude Code |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
TTL validation currently accepts malformed input by partially or implicitly casting it to an integer.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (2)
What changed in this PR
Adds configurable per-client TTLs for client-credentials tokens while preserving non-expiring legacy behavior.
Changes:
- Stores client TTL settings and token expiry timestamps.
- Rejects expired tokens and returns conditional
expires_in. - Adds admin controls and expiry-focused tests.
| File | Description |
|---|---|
inc/admin/namespace.php |
Adds TTL validation and admin UI. |
inc/authentication/namespace.php |
Rejects expired access tokens. |
inc/class-client.php |
Persists per-client TTL settings. |
inc/endpoints/class-token.php |
Returns expires_in when applicable. |
inc/tokens/class-access-token.php |
Creates and evaluates expiring tokens. |
tests/test-access-token.php |
Tests token expiry behavior. |
tests/test-admin.php |
Tests admin TTL validation. |
tests/test-authentication.php |
Tests expired-token rejection. |
tests/test-client.php |
Tests TTL persistence. |
tests/test-token-endpoint.php |
Tests expiry response fields. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Brings in per-client token TTL (WP-API#77), RFC 9728 protected resource metadata (WP-API#84), PHP 7.4+ support (WP-API#86) and the dynamic WP test matrix (WP-API#87). Conflicts were between PKCE and token TTL, which both add a client meta field. Both fields are kept everywhere. In Client::update() the PKCE branch writes only the meta keys the caller supplies, while upstream always wrote token_ttl and cleared it when omitted. token_ttl now follows the same preserve-when-omitted rule as the other fields: omitting it keeps the stored value, and passing '' or null clears it. Upstream's tests clear the TTL by passing '' explicitly, so they are unaffected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks @roborourke |
|
thanks a lot @roborourke for working on this, apologies @joehoyle that I could not pick this up |


Summary
Access_Token::create_for_client()reads the TTL from the client and sets anexpirestimestamp on the token at creation time.401 Unauthorized.expires_inin token response — The/oauth2/access_tokenendpoint includesexpires_inin the response only when the token actually has an expiry.Backwards Compatibility
Existing clients have no TTL stored — tokens issued to them will not expire. New clients opt in by setting a TTL value in the admin UI.