If I have a generated Presigned URL that expired, should I be doing get_headers()
(in PHP) to see if a 403 Forbidden
error is thrown, otherwise use that same URL? Or is that a bad idea because it's an unnecessary GET request? Should I always just regenerate a new Presigned URL every time? I'm a little confused because there doesn't seem to be much information about this.
4 Answers
The URL has the time it expires at.
Signature Version 2
htt ps://bucket.s3.amazonaws.com/foo.txt?AWSAccessKeyId=AKIAABCDEFGHIJK&Expires=1508608760&Signature=xxxxxxxxxxx
Expires gives the time in Unix timestamp (in seconds) and Coordinated Universal Time (UTC) .
$ date -d @1508608760
Sat Oct 21 17:59:20 UTC 2017
You can extract the value and compare it with the current time in UTC [time()
], then decide to regenerate or not.
Signature Version 4
htt ps://s3.amazonaws.com/bucket/foo.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256& X-Amz-Expires=3600&X-Amz-Credential=AKIAJRZXXXXXXXXus-east-1%2Fs3%2Faws4_request&X-Amz-SignedHeaders=host&X-Amz-Date=20171021T190750Z&X-Amz-Signature=8b84ae9b59e9f8a8d7066ecc39e797c8dc29848abcdef61717
X-Amz-Date gives the UTC time in ISO 8601 format.
You can extract the value, convert it to epoch/UTC and compare it with the current time in UTC [time()], then decide to regenerate or not.
-
1Awesome solution, don't know why I hadn't thought of that. However, for me, `Amz-Expires` is the expiration time in seconds, while `X-Amz-Date` is the the timestamp – D-Marc Oct 21 '17 at 18:12
-
2@D-Marc `X-Amz-*` is the newer format, called Signature Version 4. Regions where AWS services were rolled out before about 2014 support those plus the older style, called Signature Version 2. – Michael - sqlbot Oct 21 '17 at 19:24
-
5This is not a complete answer - you have to add the expires duration to the `X-Amz-Date` value to get the expiry time – Mike Miller Apr 07 '20 at 14:14
-
Doesn't this rely on implementation details from Amazon's signature process? Is there a more robust way to fetch the details without having to explicitly parse the values from query string and interpreting them? – julealgon Jan 28 '21 at 22:09
-
We also ran into the situation where the Expires unix timetamp looks ok, i.e. sometimes in the future, but the link still presented as access denied after a short period of time, still debugging but it's most likely related to https://aws.amazon.com/premiumsupport/knowledge-center/presigned-url-s3-bucket-expiration/ – James Z. Jun 25 '21 at 03:53
-
@JamesZ. found any solution for this? – radix May 12 '22 at 10:08
The accepted answer isn't quite right for Signature Version 4.
Read on if you landed here looking for a way to find the expiry in js.
import { parseISO, addSeconds } from 'date-fns';
// get the query params: https://stackoverflow.com/a/901144/9362404
const params = new Proxy(new URLSearchParams(signedUrl), {
get: (searchParams, prop) => searchParams.get(prop),
});
const creationDate = parseISO(params['X-Amz-Date']);
const expiresInSecs = Number(params['X-Amz-Expires']);
const expiryDate = addSeconds(creationDate, expiresInSecs);
const isExpired = expiryDate < new Date();
It's pretty obvious what's going on once you list out the query params:
// https://bucketname.s3.ap-southeast-2.amazonaws.com/file-name.pdf
// X-Amz-Algorithm= AWS4-HMAC-SHA256
// X-Amz-Credential= <aws-access-key>/20220722/ap-southeast-2/s3/aws4_request
// X-Amz-Date= 20220722T101759Z
// X-Amz-Expires= 259200
// X-Amz-Signature= gobbeldygook-signature
// X-Amz-SignedHeaders= host

- 369
- 3
- 7
If you use Memcached (or similar), you have the option to push the presigned url in Memcached with the same expiration time. Something like this (pseudo-php code):
$mc->set($your_key, $url, $expiration);
So, you can get the url using
$url = $mc->get($your_key);
If $mc->get returns false, you have to re-generate the presigned url.

- 306
- 5
- 10