Make WordPress Core

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)

application_password_expiry.mp4​ (1.3 MB ) - added by lakshyajeet 6 months ago.
Application password expiry UI

Download all attachments as: .zip

Change History (12)

#1 @JeffPaul
5 years ago

  • Keywords needs-patch needs-design needs-docs added
  • Milestone Awaiting Review → Future Release

@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?

#2 @TimothyBlynJacobs
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 @leedxw
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-passwords controller to support the expires field for both creation and updates.
  • Authentication: Updated wp_authenticate_application_password to validate the expiration timestamp. If a password has expired, authentication will fail with an application_password_expired error.
  • 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.

@lakshyajeet
6 months ago

Application password expiry UI

#5 @johnbillion
6 weeks ago

  • Milestone Future Release → 7.2
  • Owner set to johnbillion
  • Status new → reviewing

​@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.

  1. Set server time to UTC
  2. Move to a positive time zone (I recommend Australia/Melbourne +1000)
  3. Edit expiry of a application password
  4. Select current date (28 Sept in Melbourne)
  5. 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

https://github.com/user-attachments/assets/92b944b7-85ad-4773-8f85-cdd055b88746

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:

  1. Expiry Presets Dropdown:
    • Added a dropdown selector offering standard token lifetime options:
      • 7 days
      • 30 days (default)
      • 90 days
      • No expiry
      • Custom 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 method get_expiry_presets().
  2. 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 min set to the site's current date (wp_date( 'Y-m-d' )), preventing users from picking past dates.
  3. Validation & Sanitization:
    • Updated WP_Application_Passwords::create_new_application_password() to validate $args['expires'] and explicitly reject timestamps in the past with a WP_Error (application_password_past_expiration).
  4. Removal of "Edit Expiry" Action:
    • Removed the inline "Edit Expiry" button and editing form from WP_Application_Passwords_List_Table and application-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.
  5. Unit Tests:
    • Added tests in tests/phpunit/tests/auth.php covering authentication with expired passwords as well as passwords with valid future expiration.
    • Added tests in tests/phpunit/tests/rest-api/application-passwords.php verifying that past expiration timestamps are rejected during creation and verifying preset definitions.

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 @shewa
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:

  1. Expiration Presets: Introduced a dropdown selector with standard lifespan options (7 days, 30 days (default), 90 days, No expiry, and Custom date) defined as constants on WP_Application_Passwords.
  2. 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.
  3. Past Date Prevention & Validation: The custom date field sets min to the current site date to block past selections in the UI, and WP_Application_Passwords::create_new_application_password() now strictly validates timestamps to reject past dates with a WP_Error (application_password_past_expiration).
  4. 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.
  5. 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

This ticket was mentioned in ​Slack in #core by audrasjb. ​View the logs.


2 days ago

This ticket was mentioned in ​Slack in #core by im3dabasia1. ​View the logs.


8 hours ago

Note: See TracTickets for help on using tickets.