Skip to main content

Keep a provider API key encrypted, and never show it back

Free Intermediate

For any add-on where the podcaster brings their own key for an outside service. Benecaster encrypts it at rest: save it with benecaster_store_secret(), read it at the point of use with benecaster_get_secret(), and remove it with benecaster_delete_secret().

Two things are easy to miss. The key goes in through your settings route but never comes out of it — the route reports only whether a key is set. And null from benecaster_get_secret() means ask again, not an error: the key was never set, or can no longer be read after the site’s encryption key changed.

Code

<?php
add_action( 'rest_api_init', static function (): void {
    register_rest_route( 'my-addon/v1', '/settings', [
        [
            'methods'             => 'GET',
            'permission_callback' => static fn() => current_user_can( 'manage_options' ),
            'callback'            => static fn() => [
                // Yes or no — never the key, not even to an administrator.
                'api_key_set' => null !== benecaster_get_secret( 'my-addon', 'api_key' ),
            ],
        ],
        [
            'methods'             => 'POST',
            'permission_callback' => static fn() => current_user_can( 'manage_options' ),
            'callback'            => static function ( \WP_REST_Request $request ) {
                $key = trim( (string) $request->get_param( 'api_key' ) );
                if ( '' === $key ) {
                    benecaster_delete_secret( 'my-addon', 'api_key' );
                } elseif ( ! benecaster_store_secret( 'my-addon', 'api_key', $key ) ) {
                    return new \WP_Error( 'not_stored', __( 'The key could not be saved.', 'my-addon' ), [ 'status' => 500 ] );
                }
                return [ 'api_key_set' => '' !== $key ];
            },
        ],
    ] );
} );

// At the point of use.
function my_addon_call_provider(): void {
    $key = benecaster_get_secret( 'my-addon', 'api_key' );
    if ( null === $key ) {
        return; // Not set, or unreadable after a key change — show "add your API key" in your settings.
    }
    // … call the provider with $key.
}

View on GitHub →

Need this built rather than just documented? See our services →