A typical safe pattern is to generate both the key and nonce, then store or transmit the nonce alongside the ciphertext.
<?php
$key = sodium_crypto_secretbox_keygen();
$nonce = random_bytes(SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$message = "Hello secure world";
$ciphertext = sodium_crypto_secretbox($message, $nonce, $key);
$stored = base64_encode($nonce . $ciphertext);
$decoded = base64_decode($stored, true);
$nonce = substr($decoded, 0, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$ciphertext = substr($decoded, SODIUM_CRYPTO_SECRETBOX_NONCEBYTES);
$decrypted = sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
if ($decrypted === false) {
die("Decryption failed (message tampered or invalid key)");
}
echo $decrypted;
?>