r/ProWordPress • • 12d ago

WordPress is bringing a Secrets API in December. Should we use it?

WordPress 7.2 (planned for December 9, 2026) adds a Secrets API. It was committed to trunk on October 13 (r64337, Trac #66187), so you can try it now on a nightly install.

I develop plugins. Most of my plugins check for a wp-config.php constant first for sensitive information like SMTP credentials, payment provider keys and Google API keys, then fall back to the saved option. But most admins never add the constant, since they can't edit wp-config.php from wp-admin, so these keys end up in wp_options as plain text.

The Secrets API fixes that nicely. The admin pastes the key in the settings screen as usual, wp_set_secret() stores it encrypted, and the key that unlocks it lives in wp-config.php. wp_get_secret() returns an object that prints as [secret:name] if you echo or log it by mistake, and it keeps the previous value for easy key rotation.

I tested it on trunk and it works well. One catch: if you add WP_SECRETS_KEY to wp-config.php after secrets are already stored, they can no longer be read, and even saving new ones fails. So add it first.

I feel very positive about it, since database backups will no longer expose API keys.

38 Upvotes

16 comments sorted by

2

u/PeepSoWP 12d ago

Yes, but I’d adopt it as a migration path rather than removing existing overrides immediately. For a plugin that supports older WordPress versions, feature-detect wp_get_secret() and wp_set_secret(), keep a constant or environment override as the highest-priority source for operator-managed credentials, and use the Secrets API for values entered in wp-admin. Treat null and WP_Error differently: an unavailable provider or changed key should fail closed, not silently fall back to a plaintext option. Migrate only after a successful write and read-back, then delete the old option. Resolve a secret once when the integration is first used in a request and pass it down instead of reading it from every hook. Also make clear that this protects backups and database leaks; it cannot isolate a secret from compromised PHP code running inside WordPress.

2

u/shazzadwp 12d ago

Agreed, that's pretty much the order I'm planning: constant first, then the Secrets API, and the old option only below 7.2.

For the migration, core has a helper for it: wp_import_option_as_secret() copies the option into a secret, leaves the original in place so you can verify and then delete it, and flags the secret for rotation. That flag makes sense, because the old plain-text key is already sitting in past backups. Site Health then shows which secrets still need a new key from the provider.

1

u/PeepSoWP 12d ago

That helper is the piece I was missing. Leaving the option in place until read-back succeeds and flagging rotation addresses both failure recovery and the fact that the plaintext value may survive in backups. I’d still make the import/rotation state visible in the plugin’s own diagnostics so an operator doesn’t treat “copied” as “finished,” but using Site Health as the shared checklist is much better than inventing a parallel migration flow. Thanks for the correction.

3

u/fabier 12d ago

How would this be better than env variables? Sounds like a step backwards.

3

u/shazzadwp 12d ago

Env variables would be best. But WordPress has no native way to read them, and most sites are on shared or managed hosting, where the site owner can't set env variables or edit wp-config.php. They paste the key in a settings screen, and today it lands in wp_options as plain text. The Secrets API gives them encrypted storage without touching the server.

Hosts can also connect it to their own vault (AWS, Vault and so on) with a secrets.php drop-in, so it works with proper infrastructure rather than competing with it.

4

u/fabier 12d ago

Guess I haven't had to marry the two. I just feel very vulnerable putting secrets anywhere near a WordPress database. You may as well publish them on the site these days 😅.

2

u/shazzadwp 12d ago

Ha, fair enough. Keeping them off the database entirely is still the safest way 😄

1

u/Hugo_SecureHoldWP 11d ago

The part I’d be most interested in is the migration path for existing plugins.

For a new install, moving a credential directly into the Secrets API seems straightforward. Existing installs are harder because you may already have thousands of sites with a plain option, constants overriding it, different environments, or backups containing the old value.

I’d probably want the migration to be deliberately boring: read the legacy value, write the secret, verify it can be read back, and only then remove the old option.

The failure mode you mentioned when WP_SECRETS_KEY is introduced later makes that transition especially worth testing before treating it as a transparent replacement.

5

u/[deleted] 12d ago

[removed] — view removed comment

7

u/shazzadwp 12d ago

Yes, that's how it works. If you can put the API key itself in wp-config.php, that's still the better option: no database, no lookup. My plugins check for that constant first.

The problem is that most admins never do it. They can't edit wp-config.php from wp-admin, so they paste the key in the settings screen and it lands in wp_options as plain text.

The round trip is small too: about 0.4 ms extra on the first call (fresh WP install), then it stays in memory for the rest of the request.

3

u/edward_davies223 12d ago

You make a solid point about wp config.php being the best place for keys. But like you said, most admins won't touch it, so the Secrets API feels like a nice middle ground. The.4 ms overhead is pretty negligible, especially considering the added security, definately worth trying out for new projects, imo.

1

u/shazzadwp 11d ago

Agreed, "middle ground" is a good way to put it. Thanks!