Why do S3 pre signed URLs expire after 12 hours, despite setting a longer duration?

S3 objects can be requested through a so called pre signed URLs, however the pre signed URL is tied to the identity that generated the URL. This means that if the credentials expire that generated this URL, the presigned URL will also stop working.

If you generate a pre signed URL through an IAM role that IAM roles temporary credentials will rotate after 12 hours (by default two hours) so after that the pre signed URL will stop working as well.

Let’s walk through an example of a private bucket that we want to expose an private object from.

The URL I’ve uploaded the image of the yawning cat to is:
https://presignedbucketexample.s3.amazonaws.com/yawning-cat-1082062650-2000-c194fd9b3965473d9392674b827ec9f4.jpg

If we try to access this URL directly we get an Access Denied error. This is expected because the bucket has been setup as a private bucket.

Let’s create a pre signed URL:

aws s3 presign s3://presignedbucketexample/yawning-cat-1082062650-2000-c194fd9b3965473d9392674b827ec9f4.jpg

The URL now includes a lot of parts, let’s break them down:

  • https://presignedbucketexample.s3.us-east-1.amazonaws.com/yawning-cat-1082062650-2000-c194fd9b3965473d9392674b827ec9f4.jpg – This is the path to the URL we already have above
  • X-Amz-Algorithm=AWS4-HMAC-SHA256 – This indicates the signing algorithm used. In this case AWS Signature Version 4
  • X-Amz-Credential=ASIAYGUYHAXXXXXXX/20230709/us-east-1/s3/aws4_request – This is the credential that was used to generate the request in my case this was a Cloudshell session with an IAM user
  • X-Amz-Date=20230709T153137Z – The date when the request was generated
  • X-Amz-Expires=3600 – When does the pre signed URL expire
  • X-Amz-SignedHeaders=host – What headers are included in the signing
  • X-Amz-Security-Token=…. – The security token for the request (this comes from STS
  • X-Amz-Signature=…. – A random signature that signs this request and all its parameters, this is signed with the private part of your authentication

In summary: The identity that you use to generate the presigned URL also controls how long it can be valid for. When I deleted my Cloudshell environment the temporary credentials that were issues for it were revoked and the presigned URL stopped working immediately and I got the error:

ExpiredToken – The provided token has expired.

If you want your S3 pre signed URL’s to last longer than 12 hours you must generate them with a IAM user instead. You can never have a presigned URL that is valid for longer than 7 days. Also be aware that even if you specify a maximum session duration of 12 hours for an IAM role some services might choose not to respect that (for instance Lambda).