Type something to search...
How to Use Application Passwords in WordPress?

How to Use Application Passwords in WordPress?

Sooner or later, something outside WordPress needs to write to it. A deploy script publishes release notes, a Zapier-style automation creates draft posts from a form, a Next.js frontend submits comments, or a mobile app uploads photos to the media library. The tempting shortcut is to hand that tool an administrator's username and password. That is a bad idea: the password grants full access to everything, it cannot be revoked without changing it everywhere, and it stops working the moment the user turns on two-factor authentication.

WordPress has a built-in answer: application passwords. Added in WordPress 5.6, they are separate, per-application credentials for the REST API and XML-RPC. Each one belongs to a user, has a name, can be revoked on its own, and keeps working with two-factor authentication.

This article covers how application passwords work, how to create them in the admin and with WP-CLI, how to authenticate REST API requests with curl, PHP, and JavaScript, how to let apps request a password with the authorization flow, how to restrict or disable the feature, how to use least-privilege users, and how to fix the most common authentication errors.

What Application Passwords Are

An application password is a 24-character, randomly generated password attached to a WordPress user account. It has a few properties that make it very different from the user's main password:

PropertyMain user passwordApplication password
Used forBrowser login at wp-login.phpREST API and XML-RPC requests
Can log in to wp-adminYesNo
Number per userOneMany, one per app or integration
Revocable individuallyNo, must be changed everywhereYes, without affecting anything else
Works with two-factor authRequires the second factorYes, designed for that case
Tracks last useNoYes, last used date and IP address
Chosen byThe userGenerated by WordPress

Application passwords inherit the permissions of the user they belong to. A password created for an Editor can do whatever an Editor can do through the API, no more and no less. They are not scoped to specific endpoints, which is why the user you attach them to matters.

Since WordPress 6.8, application passwords are stored with the fast, cryptographically secure BLAKE2b hashing algorithm. WordPress only shows the plain password once, when it is created.

Requirements

Application passwords are available when:

  • The site uses HTTPS, or the environment type is set to local. Sending a password over plain HTTP would expose it, so WordPress hides the feature on non-HTTPS production sites.
  • Nothing has disabled them. Some security plugins and hosts turn them off by default.
  • The user has permission to manage their own application passwords. By default, any logged-in user can.

To mark a local development site as local, set the environment type in wp-config.php:

// wp-config.php
define( 'WP_ENVIRONMENT_TYPE', 'local' );

Creating an Application Password in the Admin

  1. Go to Users → Profile, or edit another user under Users → All Users if you are an administrator.
  2. Scroll down to the Application Passwords section.
  3. Enter a descriptive name in New Application Password Name, such as Deploy script (GitHub Actions) or Next.js frontend.
  4. Click Add New Application Password.
  5. Copy the generated password immediately. It is shown once, in groups of four characters separated by spaces, like abcd EFGH 1234 ijkl MNOP 5678.

The spaces are only for readability. WordPress strips them when it checks the password, so you can store it with or without them.

Below the form, the table lists every application password for that user with its creation date, last used date, and last IP address. Use those columns to find credentials that are no longer used.

Creating Application Passwords with WP-CLI

WP-CLI is the better choice for automation and for servers you provision with scripts:

# Terminal
# Create a password and print only the password
wp user application-password create deploy-bot "GitHub Actions deploy" --porcelain

# List a user's application passwords
wp user application-password list deploy-bot --fields=uuid,name,created,last_used,last_ip

# Revoke one by its UUID
wp user application-password delete deploy-bot 6633824d-c1d7-4f79-9dd5-4586f734d69e

# Revoke all of a user's application passwords
wp user application-password delete deploy-bot --all

--porcelain prints just the password, which makes it easy to pipe into a secrets manager. Store it as a secret in your CI system or hosting provider, never in a repository.

Authenticating REST API Requests

Application passwords use HTTP Basic authentication. The client sends an Authorization header with the username and application password, base64-encoded. Because base64 is not encryption, this is only safe over HTTPS.

With curl

curl builds the header for you with --user:

# Terminal
# Check who you are authenticated as
curl --user "deploy-bot:abcd EFGH 1234 ijkl MNOP 5678" \
  "https://example.com/wp-json/wp/v2/users/me?context=edit"

# Create a draft post
curl --user "deploy-bot:abcd EFGH 1234 ijkl MNOP 5678" \
  -H "Content-Type: application/json" \
  -d '{"title":"Release 2.4.0","content":"New features and fixes.","status":"draft"}' \
  "https://example.com/wp-json/wp/v2/posts"

The /wp/v2/users/me request is the quickest test. If authentication works, you get the user's details. If it fails, you get a 401 error, explained in the troubleshooting section below.

In scripts, read the credentials from environment variables instead of typing them in the command:

# deploy/publish-release-notes.sh
#!/usr/bin/env bash
set -euo pipefail

: "${WP_URL:?}" "${WP_USER:?}" "${WP_APP_PASSWORD:?}"

curl --fail-with-body --silent --show-error \
  --user "${WP_USER}:${WP_APP_PASSWORD}" \
  -H "Content-Type: application/json" \
  -d "{\"title\":\"Release ${RELEASE_VERSION}\",\"status\":\"draft\"}" \
  "${WP_URL}/wp-json/wp/v2/posts"

With PHP from Another WordPress Site

When one WordPress site talks to another, use the HTTP API:

// wp-content/plugins/wsm-remote-publisher/wsm-remote-publisher.php
function wsm_create_remote_draft( string $title, string $content ) {
$credentials = base64_encode( WSM_REMOTE_USER . ':' . WSM_REMOTE_APP_PASSWORD );

$response = wp_remote_post(
'https://news.example.com/wp-json/wp/v2/posts',
array(
'timeout' => 15,
'headers' => array(
'Authorization' => 'Basic ' . $credentials,
'Content-Type'  => 'application/json',
),
'body'    => wp_json_encode(
array(
'title'   => $title,
'content' => $content,
'status'  => 'draft',
)
),
)
);

if ( is_wp_error( $response ) ) {
return $response;
}

$code = wp_remote_retrieve_response_code( $response );
$body = json_decode( wp_remote_retrieve_body( $response ), true );

if ( 201 !== $code ) {
return new WP_Error( 'wsm_remote_publish_failed', $body['message'] ?? 'Unexpected response', array( 'status' => $code ) );
}

return $body['id'];
}

Define WSM_REMOTE_USER and WSM_REMOTE_APP_PASSWORD in wp-config.php or load them from environment variables, so they stay out of the database and version control.

With JavaScript on a Server

In Node.js, or in a server-side route of a framework such as Next.js:

// lib/wordpress.ts
const WP_URL = process.env.WP_URL!;
const auth = Buffer.from(
  `${process.env.WP_USER}:${process.env.WP_APP_PASSWORD}`,
).toString("base64");

export async function createDraft(title: string, content: string) {
  const res = await fetch(`${WP_URL}/wp-json/wp/v2/posts`, {
    method: "POST",
    headers: {
      Authorization: `Basic ${auth}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ title, content, status: "draft" }),
  });

  if (!res.ok) {
    const error = await res.json().catch(() => ({}));
    throw new Error(
      `WordPress returned ${res.status}: ${error.message ?? "unknown error"}`,
    );
  }

  return res.json();
}

Never put an application password in browser JavaScript. Anything shipped to the browser can be read by every visitor. Keep the request on the server and expose only what the frontend needs. For more on how the API is organized, see what is the WordPress REST API, and how to use it.

Letting an App Request a Password

If you build an app that connects to other people's WordPress sites, do not ask users to copy and paste a password. WordPress has an authorization screen for this at wp-admin/authorize-application.php. Your app sends the user there with a few query parameters:

ParameterRequiredPurpose
app_nameYesHuman-readable name shown to the user and in their profile
app_idRecommendedA UUID identifying your app, stored with the password
success_urlOptionalWhere to send the user after approval; must use HTTPS
reject_urlOptionalWhere to send the user if they decline

An example link:

https://example.com/wp-admin/authorize-application.php?app_name=Photo+Uploader&app_id=1f7b3c2e-5a1d-4b5e-9a4c-2e8f6d0c7a91&success_url=https%3A%2F%2Fapp.example.net%2Fwp-callback

The user logs in if needed, sees which app is requesting access, and approves or rejects it. On approval, WordPress creates the application password and redirects to success_url with site_url, user_login, and password added as query parameters. Your callback stores those credentials securely and uses them for future requests. Without a success_url, WordPress shows the password on screen for the user to copy.

To find out whether a site supports application passwords and where its authorization screen is, request the REST API index at /wp-json/ and look for the application-passwords entry under authentication.

Restricting or Disabling Application Passwords

Two filters control availability.

Disable the feature for the whole site, for example on a site that has no API integrations:

// wp-content/mu-plugins/wsm-application-passwords.php
<?php
/**
 * Plugin Name: WSM Application Password Policy
 */

add_filter( 'wp_is_application_passwords_available', '__return_false' );

Or allow them only for specific users or roles. This example limits application passwords to administrators and a dedicated integration role:

// wp-content/mu-plugins/wsm-application-passwords.php
<?php
/**
 * Plugin Name: WSM Application Password Policy
 */

add_filter( 'wp_is_application_passwords_available_for_user', function ( bool $available, WP_User $user ): bool {
if ( ! $available ) {
return false;
}

return (bool) array_intersect( array( 'administrator', 'integration' ), (array) $user->roles );
}, 10, 2 );

When the filter returns false for a user, the Application Passwords section disappears from their profile and their existing application passwords stop authenticating.

Using a Dedicated, Least-Privilege User

Because an application password carries all of its user's capabilities, the most important security decision is which user it belongs to. Do not attach integrations to your personal administrator account. Create a dedicated user for each integration, with only the role it needs:

# Terminal
# A user for an automation that creates draft posts only
wp user create content-bot bot@example.com --role=contributor --display_name="Content Bot"
wp user application-password create content-bot "Form to draft automation" --porcelain
IntegrationSuggested role
Creates drafts for human reviewContributor
Publishes posts and uploads mediaAuthor
Manages all content, not settingsEditor
Manages plugins, users, or settingsAdministrator (avoid if possible)

If no built-in role fits, create a custom role with exactly the capabilities required. Roles and capabilities are explained in how to set up and manage user roles in WordPress.

A dedicated user also makes auditing easier. Posts, revisions, and uploads created by the integration are attributed to it, and revoking access is as simple as deleting its application password or the user.

Application Passwords and Two-Factor Authentication

Two-factor plugins protect the login form, but REST API requests do not go through it. That is why the official Two Factor plugin blocks API authentication with a user's main password once 2FA is enabled, and allows only application passwords. The result is the setup you want: humans log in with a password and a second factor, and integrations use revocable application passwords. Setting that up is covered in how to enable two-factor authentication on WordPress.

Common Problems and Fixes

  • The Application Passwords section is missing from the profile. The site is not on HTTPS, a plugin or host disabled the feature, or a filter returns false for this user. Check HTTPS first, then security plugin settings, then search the codebase for wp_is_application_passwords_available.
  • 401 rest_not_logged_in even with the right password. The Authorization header never reaches PHP. Some Apache setups running PHP as CGI or FastCGI strip it. The default WordPress .htaccess includes a rule that passes it through. If you replaced .htaccess, restore it under Settings → Permalinks by clicking Save Changes, or add the rule manually.
  • 401 incorrect_password. The password was copied incorrectly, it was revoked, or you used the user's main password. Generate a new application password and test with /wp/v2/users/me.
  • 401 invalid_username. Use the user's login name or email address, not their display name.
  • 403 rest_cannot_create. Authentication worked, but the user lacks the capability. Check the user's role against what the request does.
  • Requests work with curl but not from your server. A firewall, CDN, or security plugin blocks API requests from that IP or user agent. Check its logs and allow the integration.
  • Credentials leaked in a log or repository. Revoke that application password immediately in the user's profile or with wp user application-password delete, then create a new one. Nothing else needs to change.

The .htaccess rule that passes the header through looks like this:

# .htaccess
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

Application Passwords FAQ

No. Application passwords only authenticate REST API and XML-RPC requests. They are rejected on the normal login form, so a leaked application password cannot be used to open the dashboard.

Yes, when used over HTTPS and attached to a user with only the permissions the integration needs. They are randomly generated, stored hashed, shown only once, and can be revoked individually. Their main weakness is that they carry all of the user's capabilities, so use dedicated least-privilege users.

No, they remain valid until they are revoked or the user is deleted. Review the last used column in each user's profile regularly and revoke passwords that have not been used recently or belong to retired integrations.

The most common reasons are that the site is not served over HTTPS, a security plugin or your host disabled the feature, or code uses a filter to turn it off for your user. Local development sites can enable it by setting the environment type to local.

Yes. That is one of their main purposes. Two-factor plugins block API requests that use the main password, but application passwords continue to work, so integrations keep running while people log in with a second factor.

No. Anything in browser JavaScript is visible to every visitor, so the password would leak immediately. Make authenticated requests from a server, such as a serverless function or a framework route, and keep the password in an environment variable.

Conclusion

Application passwords are the right way to connect scripts, apps, and other sites to WordPress. They replace shared admin passwords with separate, named, revocable credentials that work over the REST API, keep working with two-factor authentication, and record when and where they were last used.

Use them well: create a dedicated user with the smallest role that works for each integration, generate the password in the profile or with WP-CLI, store it as a server-side secret, send it only over HTTPS, and revoke it the moment it is no longer needed or might have leaked. If your site has no integrations at all, a one-line filter turns the feature off.

Here are some useful references for going deeper on application passwords:

  1. Make WordPress Core: Application Passwords: Integration Guide — the authorization flow, filters, and integration details.
  2. REST API Handbook: Authentication — cookie, nonce, and application password authentication.
  3. WP-CLI Commands: wp user application-password — creating, listing, and deleting application passwords.
  4. WordPress Developer Resources: wp_is_application_passwords_available_for_user — the per-user availability filter.
  5. Make WordPress Core: WordPress 6.8 will use bcrypt for password hashing — includes the switch to BLAKE2b for application passwords.
Tags :
Share :

Related Posts

WordPress optimization with specific recommended approach

WordPress optimization with specific recommended approach

Whether you run a high traffic WordPress installation or a small blog on a low cost shared host, you should optimize WordPress and your server to run

Continue Reading
Creating and Customizing WordPress Child Themes

Creating and Customizing WordPress Child Themes

Creating a child theme in WordPress is a best practice for making modifications to a theme. By using a child theme, you can update the parent theme w

Continue Reading
Understanding the Distinction Categories vs. Tags in WordPress

Understanding the Distinction Categories vs. Tags in WordPress

WordPress, a powerful content management system, offers a plethora of features to organize content effectively. Among these features, categories and

Continue Reading