Opened 5 years ago
Last modified 8 hours ago
#53995 reviewing feature request
Application Passwords Expiration
| Reported by: | mboynes | Owned by: | johnbillion |
|---|---|---|---|
| Priority: | normal | Milestone: | 7.2 |
| Component: | Application Passwords | Version: | 5.6 |
| Severity: | normal | Keywords: | needs-design needs-docs has-patch has-unit-tests needs-testing |
| Cc: | Focuses: | rest-api |
Description
As a developer, I want the option to set an "expiration" date on Application Passwords so that they aren't able to be used beyond the period of time that I know they'll be used.
Use case
I've been working with Application Passwords as a replacement for session cookies in an isomorphic decoupled website. I am generating them programmatically and treating them almost identically to sessions. Because they behave like sessions, I want them to expire. I'm working around this presently by including an expiration timestamp in the Application Password name.
While this feature request would solve that specific use case, I believe this would be a worthwhile addition to Application Passwords to add an option to make them more secure.
Attachments (1)
Change History (12)
#1
@
5 years ago
- Keywords needs-patch needs-design needs-docs added
- Milestone Awaiting Review → Future Release
#2
@
5 years ago
- Focuses rest-api added
- Version → 5.6
The idea of expiring tokens was explored in the context of having short-lived tokens with a longer-lived or non-expiring "refresh" token that you would use to mint a new short-lived token. We didn't go with it to keep the initial version as simple as possible. However, we probably wouldn't go with refresh-tokens regardless because the security benefit was fairly minimal, and IIRC from @rmccue's research for the OAuth REST API plugin, few OAuth providers implemented mandatory refresh tokens with a short expiration time.
That being said, I do think having App Passwords with a permanent expiration would be very valuable to have in Core. An additional use case is using App Passwords to do a one-time flow with a user's site where you don't want to keep the App Password around for longer than the setup process. The Introspection endpoint introduced in 5.7 allows for an Application to cleanup after itself when it is finished, but an expiration date could add additional safeguards in case the user abandons the flow, not allowing the Application to delete it's token.
The necessary filters exist so that a developer could add this feature if they desired, however I think there is a strong argument for supporting it in Core. That would allow for interoperability between different plugins that care about Application Passwords. In addition, it means that if an Application can use expiring Passwords even if they don't have a companion plugin already installed on the site.
In terms of what UI is necessary, I do not believe we should expose an input field for controlling the expiration date when manually creating a token, either through authorize-application.php or the user's profile page. I think this would complicate the UI more than necessary for most cases. Additionally, a user may end up shortening or lengthening a token's expiration time in contrast to how the Application expects their token to function. Which could result in broken behavior if the token expires before the Application can finish using it, or sticking around for a long time even when the Application no longer cares for it.
I do think we should indicate on authorize-application.php if an expiration time was provided when promoting the user to Approve the Application. Additionally, I think we should include the expiration time in the list table on the profile page. I think we should consider omitting expired tokens from that list table, as well as potentially deleting them x days after the token has expired. If we do hide the tokens, we need to consider that the UI may be potentially confusing if the user receives a "This application name is already used" error since they won't be able to see the existing App Password entry.
#3
@
8 months ago
Just noting that we've been asked by a client if application password expiry dates can be made mandatory - and my understanding is the current system doesn't support expiry dates.
(This is in the context of application codes being supplied to AI agents.)
This ticket was mentioned in PR #11685 on WordPress/wordpress-develop by @lakshyajeet.
6 months ago
#4
- Keywords has-patch has-unit-tests added; needs-patch removed
This PR introduces the ability to set and manage expiration dates for Application Passwords in WordPress. Currently, application passwords are permanent until revoked; this change enhances security by allowing users to define a "Time to Live" (TTL) for specific credentials.
Key Changes:
- User Interface: Added an "Expires on" date picker to the "Add New Application Password" form.
- Management: Added an "Expires" column to the Application Passwords list table.
- Inline Editing: Implemented AJAX-powered inline editing for expiration dates directly from the list table, including "Save" and "Cancel" functionality.
- REST API: Updated the
application-passwordscontroller to support theexpiresfield for both creation and updates. - Authentication: Updated
wp_authenticate_application_passwordto validate the expiration timestamp. If a password has expired, authentication will fail with anapplication_password_expirederror. - Tests: Added e2e tests and unit tests to cover creation with expiration, inline editing of expiration dates, and ensuring expired passwords display correctly.
https://github.com/user-attachments/assets/e6d6fd2e-7c2e-47ad-8613-8281419ca6cc
Trac ticket: https://core.trac.wordpress.org/ticket/53995
### Use of AI Tools
AI assistance: Yes
Tool(s): Gemini/Antigravity
Model(s): Gemini 3 Flash, Gemini 3.1 Pro
Used for: Troubleshooting E2E test failures and drafting the PR description based on provided code diffs.
@peterwilsoncc commented on PR #11685:
3 weeks ago
#6
During manual testing, I am seeing the following issues:
1) Date picker time is not server time
The date picker pop-over shows the local/computer time rather than the website time. This can result in strange behaviour when setting the time outside of the servers timezone.
- Set server time to UTC
- Move to a positive time zone (I recommend Australia/Melbourne +1000)
- Edit expiry of a application password
- Select current date (28 Sept in Melbourne)
- Expiry date is recorded as the day earlier (27 Sept)
Reproduction steps may be time of day dependent -- whether the local and UTC date are different at the time of reproduction
2) It's possible to set the expiry date to the past.
I was able to set an expiry of both a new and existing app password to be in the past. It may be useful for existing ones but setting the date to the past for a new one should prevent it from being created.
3) Clearing expiry dates is not possible
It's possible to add an expiry date to an application password that doesn't have one but the reverse is not true.
This ticket was mentioned in PR #14069 on WordPress/wordpress-develop by @shewa.
9 days ago
#7
Description
This PR improves the Application Passwords expiration feature on top of PR #11685 by introducing sensible presets, a timezone-aware custom expiration calendar, backend validation, and security UX enhancements aligned with modern token management standards.
Summary of Changes:
- Expiry Presets Dropdown:
- Added a dropdown selector offering standard token lifetime options:
7 days30 days(default)90 daysNo expiryCustom date
- Presets are defined as class constants on
WP_Application_Passwords(EXPIRY_7_DAYS,EXPIRY_30_DAYS,EXPIRY_90_DAYS,EXPIRY_NO_EXPIRY,EXPIRY_CUSTOM) with a helper methodget_expiry_presets().
- Added a dropdown selector offering standard token lifetime options:
- Timezone-Aware Expiration Calculation:
- When selecting a custom date or preset, expiration is calculated to the end of the day (
23:59:59) in the site's configured local timezone (wp_timezone()), converted to UTC ISO format for consistent storage and comparison. - The custom date field utilizes native HTML5 date input with
minset to the site's current date (wp_date( 'Y-m-d' )), preventing users from picking past dates.
- When selecting a custom date or preset, expiration is calculated to the end of the day (
- Validation & Sanitization:
- Updated
WP_Application_Passwords::create_new_application_password()to validate$args['expires']and explicitly reject timestamps in the past with aWP_Error(application_password_past_expiration).
- Updated
- Removal of "Edit Expiry" Action:
- Removed the inline "Edit Expiry" button and editing form from
WP_Application_Passwords_List_Tableandapplication-passwords.js. - Rationale: Similar to industry token management standards (e.g., GitHub Personal Access Tokens and GitLab Access Tokens), application passwords and access tokens are meant to be immutable credentials. Modifying token lifespans post-creation introduces security risks and audit ambiguity. If an application password expires or its validity period needs to change, the secure and recommended practice is to revoke the existing password and generate a new one.
- Removed the inline "Edit Expiry" button and editing form from
- Unit Tests:
- Added tests in
tests/phpunit/tests/auth.phpcovering authentication with expired passwords as well as passwords with valid future expiration. - Added tests in
tests/phpunit/tests/rest-api/application-passwords.phpverifying that past expiration timestamps are rejected during creation and verifying preset definitions.
- Added tests in
Trac ticket: https://core.trac.wordpress.org/ticket/53995
Use of AI Tools
AI assistance: Yes
Tool(s): Antigravity
Model(s): Gemini 3.8 Flash
Used for: Generation of PHPUnit tests, JS code, tests, and translations; refined and verified in a local Docker environment.
#8
@
7 days ago
- Keywords needs-testing added
Hi everyone,
I've opened [PR 14069](https://github.com/WordPress/wordpress-develop/pull/14069), building upon and refining the work started in PR #11685:
### Improvements in this PR:
- Expiration Presets: Introduced a dropdown selector with standard lifespan options (
7 days,30 days(default),90 days,No expiry, andCustom date) defined as constants onWP_Application_Passwords. - Timezone-Aware Calculation: Expiration is calculated to the end of the day (
23:59:59) in the site's local timezone (wp_timezone()), converted to UTC ISO format for consistent storage and comparisons. - Past Date Prevention & Validation: The custom date field sets
minto the current site date to block past selections in the UI, andWP_Application_Passwords::create_new_application_password()now strictly validates timestamps to reject past dates with aWP_Error(application_password_past_expiration). - Removed Post-Creation Expiry Editing: Removed the inline "Edit Expiry" action from the table and JS. Following token management standards (like GitHub and GitLab PATs), credentials should be immutable once issued. If an application password expires or needs a new duration, the recommended and secure approach is to revoke it and generate a new one.
- Testing: Both PHPUnit tests (
tests/phpunit/tests/auth.php,tests/phpunit/tests/rest-api/application-passwords.php) and Playwright E2E tests (tests/e2e/specs/profile/applications-passwords.test.js) are updated and passing.
Feedback and reviews are welcome!
@lakshyajeet commented on PR #11685:
5 days ago
#9
Hi @peterwilsoncc, thanks for testing it out. I have updated the code to support:
- Fix server time and local time descrepency
- Prevent setting a past expiry date
- Add clearing expiry dates
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
@mboynes this seems like a reasonable request, though I'm curious if @georgestephanis or @timothyblynjacobs had considered this as part of the original merge to core and if there was a reason this was left out? Also curious if this is something that should be / needs to be exposed in the WP Admin UI or is better left to adjust as a filter? Confirming the ideal user flow would be helpful if someone wants to take a stab at that to help move this along?