WordPress 5.6 (released December 8, 2020) introduced Application Passwords — a built-in mechanism for authenticating REST API requests without using the main account password or installing a plugin. An application password is a 24-character randomly generated credential that can be created and revoked independently from the user’s login password. Each application password is tied to a specific user account and shows up under Users → Profile → Application Passwords with a name you give it (e.g. “Mobile App”, “ERP Integration”, “CI/CD Deploy Script”). REST API requests authenticated with an application password run with the same capabilities as the user account it belongs to. This replaces the common pattern of installing JWT Authentication for WP REST API or Basic Auth plugins just to enable API access — the feature is now built into WordPress core for any site on HTTPS.
Problem: You need a CI/CD script to update a WordPress post via the REST API on every deployment — without storing the user's main password in the pipeline environment variables, and with the ability to revoke the credential if the pipeline is compromised.
Solution: Generate an Application Password for a dedicated editor user, store it in the CI environment, and use HTTP Basic Auth with the username and application password for REST API requests.
<?php
// ── Creating an Application Password programmatically (admin script) ───
// Useful for provisioning credentials via WP-CLI or a setup routine.
$user_id = 5; // editor user ID
$app_name = 'CI/CD Pipeline';
[ $new_password, $item ] = WP_Application_Passwords::create_new_application_password(
$user_id,
[ 'name' => $app_name ]
);
// $new_password is the plain-text password — store it NOW, it cannot be retrieved again
// $item contains uuid, name, created, last_used, last_ip
echo "Generated application password: " . $new_password . "
";
// ── List existing application passwords for a user ─────────────────────
$passwords = WP_Application_Passwords::get_user_application_passwords( $user_id );
foreach ( $passwords as $pw ) {
printf( "Name: %s | UUID: %s | Last used: %s
",
$pw['name'],
$pw['uuid'],
$pw['last_used'] ? date( 'Y-m-d', $pw['last_used'] ) : 'Never'
);
}
// ── Revoke a specific application password ─────────────────────────────
WP_Application_Passwords::delete_application_password( $user_id, $uuid );
// ── Disable Application Passwords globally (e.g. for intranet sites) ──
add_filter( 'wp_is_application_passwords_available', '__return_false' );
Using the application password in a REST API request (shell / curl):
# Application passwords use HTTP Basic Auth.
# Username: WordPress username
# Password: the generated 24-char application password (spaces are ignored)
curl -X POST https://example.com/wp-json/wp/v2/posts/42 -u "editor_username:xxxx xxxx xxxx xxxx xxxx xxxx" -H "Content-Type: application/json" -d '{"content": {"raw": "<p>Updated by CI pipeline.</p>"}}'
# In PHP with wp_remote_request:
# 'headers' => [
# 'Authorization' => 'Basic ' . base64_encode( 'editor_username:xxxxxxxxxxxxxxxxxxxxxxxx' ),
# ]
NOTE: Application Passwords require HTTPS — WordPress disables the feature on non-SSL sites by default. You can override this check with the wp_is_application_passwords_available filter (for local development with __return_true), but never do so on a production site over plain HTTP. Application passwords also do not work for wp-login.php form logins — they are strictly for REST API and XML-RPC authentication. A user's main login password is never exposed or affected by application passwords.