Skip to content
← Back to Snippets
Code

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.';
}