Generate Expiring Amazon S3 Link

You don't have to make files on Amazon S3 public (they aren't by default). But you can generate special keys to allow access to private files. These keys are passed through the URL and can be made to expire.


    * Calculate the HMAC SHA1 hash of a string.
    * @param string $key The key to hash against
    * @param string $data The data to hash
    * @param int $blocksize Optional blocksize
    * @return string HMAC SHA1
    function el_crypto_hmacSHA1($key, $data, $blocksize = 64) {
        if (strlen($key) > $blocksize) $key = pack('H*', sha1($key));
        $key = str_pad($key, $blocksize, chr(0x00));
        $ipad = str_repeat(chr(0x36), $blocksize);
        $opad = str_repeat(chr(0x5c), $blocksize);
        $hmac = pack( 'H*', sha1(
        ($key ^ $opad) . pack( 'H*', sha1(
          ($key ^ $ipad) . $data
        return base64_encode($hmac);

    * Create temporary URLs to your protected Amazon S3 files.
    * @param string $accessKey Your Amazon S3 access key
    * @param string $secretKey Your Amazon S3 secret key
    * @param string $bucket The bucket (
    * @param string $path The target file path
    * @param int $expires In minutes
    * @return string Temporary Amazon S3 URL
    * @see
    function el_s3_getTemporaryLink($accessKey, $secretKey, $bucket, $path, $expires = 5) {
      // Calculate expiry time
      $expires = time() + intval(floatval($expires) * 60);
      // Fix the path; encode and sanitize
      $path = str_replace('%2F', '/', rawurlencode($path = ltrim($path, '/')));
      // Path for signature starts with the bucket
      $signpath = '/'. $bucket .'/'. $path;
      // S3 friendly string to sign
      $signsz = implode("\n", $pieces = array('GET', null, null, $expires, $signpath));
      // Calculate the hash
      $signature = el_crypto_hmacSHA1($secretKey, $signsz);
      // Glue the URL ...
      $url = sprintf('', $bucket, $path);
      // ... to the query string ...
      $qs = http_build_query($pieces = array(
        'AWSAccessKeyId' => $accessKey,
        'Expires' => $expires,
        'Signature' => $signature,
      // ... and return the URL!
      return $url.'?'.$qs;



<?php echo el_s3_getTemporaryLink('your-access-key', 'your-secret-key', 'bucket-name', '/path/to/'); ?>


  1. User Avatar
    Claude "CodeAngry" Adrian
    Permalink to comment#

    You should mention the real author when you paste my code here.

    Without further ado… the original source of this snippet is:
    5ubliminal’s Amazon S3 Expiring Link Builder.

    Thank you!

    • User Avatar
      Chris Coyier
      Permalink to comment#

      Great, thanks for noting. I always try and do that. I was looking for this function for myself, found it on Snipplr, and it wasn’t clear who the original author was, so I just credited the page I found it on.

  2. User Avatar
    Permalink to comment#

    What is to stop someone from refreshing the screen and getting a new URL? I thought AWS was supposed to be able to provide a secure URL, but short of learning the PHP API is there not a way to deliver content securely?

    Thanks for this script. Both of you.

    • User Avatar
      Chris Coyier
      Permalink to comment#

      Nothing, but then that NEW link expires after the time limit too. The point is, in order to have a useful link to the file, you have to be viewing that particular page, because otherwise the link is pretty useless.

  3. User Avatar
    Permalink to comment#


    Can you please provide some more detailed instructions for a PHP noob like me?
    Got following questions:
    a) Where do I put the first file?
    b) How do I name it?
    c) Where exactly would I put the 2nd box that you show here?
    d) Won’t the bad guy be able to see my Access KEy etc when he opens that page?


  4. User Avatar
    Permalink to comment#

    Your way of explaining everything in this article is actually good, every
    one be capable of effortlessly know it, Thanks a lot. http://shop-computer.

    info Very very first, for every single store.Try to find the product or service be
    substituted for something you normally use?

  5. User Avatar
    Sanjay Khatri
    Permalink to comment#

    This is nice tutorial….it helps me a lot.. I have checked all over but didn’t get right solution.

    Here I find the right solution without wasting a time…

    Nice tutorial.. Kepp it up…

    5***** stars

  6. User Avatar
    Permalink to comment#

    Is there a working version of this anywhere? I saw one on wordpress but the problem was that the temporary link actually revealed the access key if you mouse over it. Another on revealed the access key & secret key when you mouse over it.

    So yeah, is there a working version? And if not could someone make this into a workable WordPress plugin? :)

  7. User Avatar
    Permalink to comment#

    To clarify this blog post, the Amazon documentation (scroll to the last example) specifies that the string to be used to generate the signature is:


    That string is used to produce a binary sha1-hmac, which should be base64 encoded. It seems strange to do the hmac generation manually (I assume the original code was for older PHP versions) – the following is a more succinct way to do the same thing:

    function getTemporaryUrl($key, $secret, $bucket, $path, $expirySeconds = 30)
        $expiry = time() + $expirySeconds;
        // Format the string to be signed
        $string = sprintf("GET\n\n\n%s\n/%s/%s", $expiry, $bucket, $path);
        // Generate an HMAC-SHA1 signature for it
        $signature = base64_encode(hash_hmac('sha1', $string, $secret, true));
        // Create the final URL
        return sprintf(
                'AWSAccessKeyId' => $key,
                'Expires' => $expiry,
                'Signature' => $signature

    Which would have the same usage:

    echo getTemporaryUrl('your-access-key', 'your-secret-key', 'bucket-name', '/path/to/');
    • User Avatar
      mark harris
      Permalink to comment#

      I like your snippet however would this method still work if the downloadable file is big and url expires while downloading before the file is downloaded completely.

  8. User Avatar
    Permalink to comment#

    I just have 1 doubt…what if I want the url to be valid forever i.e it should not expire or you can say infinite expiry time

    • User Avatar
      Permalink to comment#

      Then you’ll be able to simply make the S3 link public. That’ll give the users unlimited access to the S3 files. The blog post was aiming to restrict that unlimited access by creating a pre-signed URL.

  9. User Avatar
    Permalink to comment#

    Is there anyone who can help me to write the above two functions in c#? I have very little knowledge of php and trying to create the same on .net world.
    Thanks in advance,

  10. User Avatar

    Big Ups!

  11. User Avatar
    will barker

    Is there a way to set a custom error page to display when these expire? As far as I can work out you can only do that when using the webhosting options in s3 console. When using that the expiry code here does not work.

Leave a Comment

Posting Code!

You may write comments in Markdown. This makes code easy to post, as you can write inline code like `<div>this</div>` or multiline blocks of code in triple backtick fences (```) with double new lines before and after.

Code of Conduct

Absolutely anyone is welcome to submit a comment here. But not all comments will be posted. Think of it like writing a letter to the editor. All submitted comments will be read, but not all published. Published comments will be on-topic, helpful, and further the discussion or debate.

Want to tell us something privately?

Feel free to use our contact form. That's a great place to let us know about typos or anything off-topic.