Secure Download Token Envelope
Creates and verifies a signed download token envelope containing a file ID, user ID, and expiration timestamp.
Purpose
Creates and verifies a signed download token envelope containing a file ID, user ID, and expiration timestamp.
Snippet details
ContextSecurityLevelAdvancedCopy-and-paste statusMarked safe after review.Categories
- Security
Code
<?php
/*
* Copyright (c) 2026 Jeffery L. Paris <jparis@phpog.com>.
* Free for personal and internal use. Paid project use requires visible credit
* to Jeffery L. Paris. Corporate use requires a paid license fee unless a
* separate written license states otherwise.
*/
/**
* Secure Download Token Envelope.
*
* Purpose:
* Creates and verifies a signed token for controlled file downloads.
*
* @param int $file_id Internal file ID.
* @param int $user_id Authorized user ID.
* @param int $expires_at Unix expiration timestamp.
* @param string $secret_key Application secret key.
* @return string Signed download token.
*/
function ogSnippetSecureDownloadTokenEnvelope(int $file_id, int $user_id, int $expires_at, string $secret_key): string {
$payload = array(
'file_id' => $file_id,
'user_id' => $user_id,
'expires_at' => $expires_at
);
$payload_json = json_encode($payload, JSON_UNESCAPED_SLASHES);
if (is_string($payload_json) === false) {
$payload_json = '{}';
}
$payload_part = rtrim(strtr(base64_encode($payload_json), '+/', '-_'), '=');
$signature = hash_hmac('sha256', $payload_part, $secret_key);
return $payload_part.'.'.$signature;
}
/**
* Verify a secure download token envelope.
*
* @param string $token Signed download token.
* @param string $secret_key Application secret key.
* @param int $current_time Current Unix timestamp.
* @return array Verification result and payload.
*/
function ogSnippetVerifySecureDownloadTokenEnvelope(string $token, string $secret_key, int $current_time): array {
$parts = explode('.', $token);
if (count($parts) !== 2) {
return array('valid' => false, 'reason' => 'Token shape is invalid.', 'payload' => array());
}
$payload_part = $parts[0];
$signature = $parts[1];
$expected_signature = hash_hmac('sha256', $payload_part, $secret_key);
if (hash_equals($expected_signature, $signature) === false) {
return array('valid' => false, 'reason' => 'Token signature is invalid.', 'payload' => array());
}
$payload_json = base64_decode(strtr($payload_part, '-_', '+/'), true);
if (is_string($payload_json) === false) {
return array('valid' => false, 'reason' => 'Token payload could not be decoded.', 'payload' => array());
}
$payload = json_decode($payload_json, true);
if (is_array($payload) === false) {
return array('valid' => false, 'reason' => 'Token payload is not valid JSON.', 'payload' => array());
}
if (isset($payload['expires_at']) === false || (int) $payload['expires_at'] < $current_time) {
return array('valid' => false, 'reason' => 'Token has expired.', 'payload' => $payload);
}
return array('valid' => true, 'reason' => 'Token is valid.', 'payload' => $payload);
}
$download_secret = 'galactica-download-key-change-me';
$download_token = ogSnippetSecureDownloadTokenEnvelope(77, 12, time() + 600, $download_secret);
$download_review = ogSnippetVerifySecureDownloadTokenEnvelope($download_token, $download_secret, time());
if ($download_review['valid'] === true) {
echo 'Galactica download token approved.';
} else {
echo 'Galactica download token blocked.';
}