Context: A simple Vanilla JS SPA wrapped in and served via WP, as a custom WP template (the template page only contain custom code, without any WP headers, etc.).
Purpose Even if the user is already authenticated in WP itself to be able to load the JS app, to make Ajax calls to the wp-api we need to also pass the nonce as auth header.
Usually the nonce is provided by using an inline script, and print the nonce with PHP, this way:
wp_add_inline_script(
'script-handle',
'const my_script_params = ' . json_encode(
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'my_nonce' => wp_create_nonce( 'my_nonce' )
)
),
'before'
);
However I would like to avoid this approach, mainly because I do not load any WP headers and therefore the scripts enquque doe snot work.
Therefore my solution is to pass back the nonce in the URL after a successful login:
function redirect_with_nonce(){
$nonce = wp_create_nonce( 'wp_rest');
$redirect_url = add_query_arg( 'nonce', $nonce, get_option('siteurl'));
wp_redirect($redirect_url);
exit;
}
add_action('wp_login', 'redirect_with_nonce', 10, 2);
and finally take it from the URL and save it to the localStorage with a few lines of JS like:
function refreshNonce() {
var query_string = new URLSearchParams(window.location.search);
var nonce = query_string.get("nonce") || null;
if (nonce) {
window.localStorage.setItem("nonce", nonce);
}
}
I was wondering if this approach can be recomended, if this is better than the "inline script" usual approach and/or more or less secure.
Thanks!
If WordPress nonces were actually Numbers Used Once, this would be fine. But these nonces have a longer lifetime than that. They aren't invalidated when used by WordPress.
So it is a security risk to embed them in URLs (that is, in GET requests). GET request URLs can be logged by proxy servers and are visible in transit even when https is in use.
So don't do this.
Information carried in the body of the HTML document you send out is, when you use https, not visible in transit. It's encrypted. The end user, the browser user, can see it of course, but not third parties like proxy servers.