Generating One-Time Use URLs

Share this article

A one-time URL is a specially crafted address that is valid for one use only. It’s usually provided to a user to gain privileged access to a file for a limited time or as part of a particular activity, such as user account validation. In this article I’ll show how to generate, implement, and expire one-time URLs.

Creating a URL

Let’s say we’ve been tasked with writing a user management component, and the project creates a record for a new user account in the database. After signing up, the user receives a confirmation email which provides a one-time URL to activate her account. We can make this URL one-time by including a tracked token parameter, which means the URL would look like this:
http://example.com/activate?token=ee97780...
Not surprisingly, tracking the one-time URL is done by storing information in a database table. So, let’s start with the table definition:
CREATE TABLE pending_users (
    token CHAR(40) NOT NULL,
    username VARCHAR(45) NOT NULL,
    tstamp INTEGER UNSIGNED NOT NULL,
    PRIMARY KEY(token)
);
The table stores the relevant username, a unique token, and a timestamp. I’ll be showing how to generate the token using the sha1() function, which returns a 40-character string, hence the capacity of the token field as 40. The tstamp field is an unsigned integer field used to store a timestamp indicating when the token was generated and can be used if we want to implement a mechanism by which the token expires after a certain amount of time. There are many ways to generate a token, but here I’ll simply use the uniqid() and sha1()
functions. Regardless of how you choose to generate your tokens, you’ll want them to be unpredictable (random) and a low chance of duplication (collision).
<?php
$token = sha1(uniqid($username, true));
uniqid() accepts a string and returns a unique identifier based on the string and the current time in microseconds. The function also accepts an optional Boolean argument to add additional entropy to make the result more unique. The sha1() function calculates the hash of the given string using the US Secure Hash Algorithm 1. Once the functions execute, we’ve got a unique 40-character string which we can use as our token to create the one-time URL. We’ll want to record the token along with the username and timestamp in the database so we can reference it later.
<?php
$query = $db->prepare(
    "INSERT INTO pending_users (username, token, tstamp) VALUES (?, ?, ?)"
);
$query->execute(
    array(
        $username,
        $token,
        $_SERVER["REQUEST_TIME"]
    )
);
Obviously we want to store the token, but we also store the username to remember which user to set active, and a timestamp. In a real world application you’d probably store the user ID and reference a user record in a separate user table, but I’m using the username string for example’s sake. With the information safely placed in the database, we can now construct our one-time URL which points to a script that receives the token and processes it accordingly.
<?php
$url = "http://example.com/activate.php?token=$token";
The URL can be disseminated to the user either by email or some other means.
<?php
$message = <<<ENDMSG
Thank you for signing up at our site.  Please go to
$url to activate your account.
ENDMSG;

mail($address, "Activate your account", $message);

Consuming a URL

We need a script to activate the account once the user follows the link. Indeed, it’s the processing script that works that enforces the one-time use of the URL. What this means is the script will need to glean the token from the calling URL and do a quick check against the data stored in the database table. If it’s a valid token, we can perform whatever action we want, in this case setting the user active and expiring the token.
<?php
// retrieve token
if (isset($_GET["token"]) && preg_match('/^[0-9A-F]{40}$/i', $_GET["token"])) {
    $token = $_GET["token"];
}
else {
    throw new Exception("Valid token not provided.");
}

// verify token
$query = $db->prepare("SELECT username, tstamp FROM pending_users WHERE token = ?");
$query->execute(array($token));
$row = $query->fetch(PDO::FETCH_ASSOC);
$query->closeCursor();

if ($row) {
    extract($row);
}
else {
    throw new Exception("Valid token not provided.");
}

// do one-time action here, like activating a user account
// ...

// delete token so it can't be used again
$query = $db->prepare(
    "DELETE FROM pending_users WHERE username = ? AND token = ? AND tstamp = ?",
);
$query->execute(
    array(
        $username,
        $token,
        $tstamp
    )
);
Going further, we could enforce a 24-hour TTL (time to live) for the URL buy checking the timestamp stored in the table alongside the token.
<?php
// 1 day measured in seconds = 60 seconds * 60 minutes * 24 hours
$delta = 86400;

// Check to see if link has expired
if ($_SERVER["REQUEST_TIME"] - $tstamp > $delta) {
    throw new Exception("Token has expired.");
}
// do one-time action here, like activating a user account
// ...
Working within the realm of Unix timestamps, the expiration date would be expressed as an offset in seconds. If the URL is only supposed to be valid for 24 hours, we have a window of 86,400 seconds. Determining if the link has expired then becomes a simple matter of comparing the current time with the original timestamp and see if the difference between them is less than the expiration delta. If the difference is greater than the delta, then the link should be expired. If the difference is less than or equal to the delta, the link is still “fresh.”

Conclusion

There are several applications for one-time use URLs. The example in this article was a scenario of sending a user a verification link to activate an account. You could also use one-time use URLs to provide confirmation for other activities, give time-sensitive access to information, or to create timed user accounts which expire after a certain time. As a matter of general house keeping you could write a secondary script to keep expired tokens from accumulating in the database if a user never follows them. The script could be run periodically by an administrator, or preferably set up as a scheduled task or cron job and run automatically. It would also be wise to take this functionality and wrap it up into a reusable component as you implemented it in your application. It’s trivial to do, and so I’ll leave that as an exercise to the reader. Image via Fotolia

Frequently Asked Questions (FAQs) on Generating One-Time Use URLs

What is a One-Time Use URL and how does it work?

A One-Time Use URL, also known as a disposable URL, is a web address that is valid for one use only. It is generated by a server and is typically used for secure file transfers, password resets, or confidential information sharing. Once the URL is used, it becomes invalid and cannot be used again. This ensures that even if the URL is intercepted or copied, it cannot be used to gain unauthorized access.

How secure are One-Time Use URLs?

One-Time Use URLs are generally secure as they are designed to be used once and then become invalid. However, their security largely depends on how they are generated and used. If the generation process is predictable or if the URL is used over an insecure network, it could potentially be intercepted and used by an unauthorized person. Therefore, it’s crucial to use secure methods for generating and transmitting these URLs.

Can One-Time Use URLs be revoked?

Yes, One-Time Use URLs can be revoked or made invalid by the server that generated them. This is typically done after the URL has been used once, but can also be done manually if the URL has not yet been used and needs to be invalidated for security reasons.

How are One-Time Use URLs generated?

One-Time Use URLs are generated by a server using a unique identifier, such as a random string or a hash of some data. This identifier is then appended to the base URL to create the One-Time Use URL. The server keeps track of which URLs have been used and invalidates them after use.

What are the benefits of using One-Time Use URLs?

One-Time Use URLs offer several benefits. They enhance security by ensuring that a URL can’t be reused if it’s intercepted. They also provide a way to share sensitive information or files without exposing them to potential unauthorized access. Additionally, they can be used to track user actions, such as clicking a link in an email, as the server can record when the URL has been used.

Can One-Time Use URLs be used for password resets?

Yes, One-Time Use URLs are commonly used for password resets. When a user requests a password reset, the server generates a One-Time Use URL and sends it to the user’s registered email address. The user can then use this URL to reset their password. Once the URL has been used, it becomes invalid and cannot be used again.

Are there any limitations or drawbacks to using One-Time Use URLs?

While One-Time Use URLs offer many benefits, they also have some limitations. For instance, if a user loses the URL before using it, they may not be able to access the intended resource. Additionally, if the URL is intercepted before the intended user uses it, it could potentially be used by an unauthorized person.

How can I generate a One-Time Use URL?

There are many ways to generate a One-Time Use URL, depending on your specific needs and technical capabilities. Some methods involve using server-side scripting languages like PHP or Node.js, while others may involve using a service or API that generates these URLs for you.

Can One-Time Use URLs be used for file transfers?

Yes, One-Time Use URLs are often used for secure file transfers. The server generates a unique URL for the file, and this URL is sent to the recipient. Once the recipient uses the URL to download the file, the URL becomes invalid.

How long do One-Time Use URLs remain valid?

The validity period of a One-Time Use URL can vary depending on how it’s set up. Some URLs may become invalid as soon as they’re used, while others may remain valid for a certain period of time, such as 24 hours, before they become invalid. This is typically configurable based on your specific needs.

Timothy BoronczykTimothy Boronczyk
View Author

Timothy Boronczyk is a native of Syracuse, New York, where he lives with no wife and no cats. He has a degree in Software Application Programming, is a Zend Certified Engineer, and a Certified Scrum Master. By day, Timothy works as a developer at ShoreGroup, Inc. By night, he freelances as a writer and editor. Timothy enjoys spending what little spare time he has left visiting friends, dabbling with Esperanto, and sleeping with his feet off the end of his bed.

Intermediate
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week