

AWS SDK for Go V1 has reached end-of-support. We recommend that you migrate to [AWS SDK for Go V2](https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/). For additional details and information on how to migrate, please refer to this [announcement](https://aws.amazon.com/blogs//developer/announcing-end-of-support-for-aws-sdk-for-go-v1-on-july-31-2025/).

# Creating Pre-Signed URLs for Amazon S3 Buckets


This Go example shows you how to obtain a pre-signed URL for an Amazon S3 bucket. You can download complete versions of these example files from the [aws-doc-sdk-examples](https://github.com/awsdocs/aws-doc-sdk-examples/tree/master/go/example_code/s3) repository on GitHub.

## Scenario


In this example, a series of Go routines are used to obtain a pre-signed URL for an Amazon S3 bucket using either GetObject or a PUT operation. A pre-signed URL allows you to grant temporary access to users who don’t have permission to directly run AWS operations in your account. A pre-signed URL is signed with your credentials and can be used by any user.
+  [Presign](https://docs.aws.amazon.com/sdk-for-go/api/aws/request/#Request.Presign) 

## Prerequisites

+ You have [set up](setting-up.md) and [configured](configuring-sdk.md) the SDK.
+ You are familiar with pre-signed URLs. To learn more, see [Uploading Objects Using Pre-Signed URLs](https://docs.aws.amazon.com/AmazonS3/latest/dev/PresignedUrlUploadObject.html) in the Amazon S3 Developer Guide.

## Generate a Pre-Signed URL for a GetObject Operation


To generate a pre-signed URL, use the [Presign](https://docs.aws.amazon.com/sdk-for-go/api/aws/request/#Request.Presign) method on the `request` object. You must set an expiration value because the AWS SDK for Go doesn’t set one by default.

The following example generates a pre-signed URL that enables you to temporarily share a file without making it public. Anyone with access to the URL can view the file.

```
package main

import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
    "log"
    "time"
)

// Downloads an item from an S3 Bucket
//
// Usage:
//    go run s3_download.go
func main() {
    // Initialize a session in us-west-2 that the SDK will use to load
    // credentials from the shared credentials file ~/.aws/credentials.
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String("us-west-2")},
    )

    // Create S3 service client
    svc := s3.New(sess)

    req, _ := svc.GetObjectRequest(&s3.GetObjectInput{
        Bucket: aws.String("amzn-s3-demo-bucket"),
        Key:    aws.String("myKey"),
    })
    urlStr, err := req.Presign(15 * time.Minute)

    if err != nil {
        log.Println("Failed to sign request", err)
    }

    log.Println("The URL is", urlStr)
}
```

If the SDK has not retrieved your credentials before calling `Presign`, it will get them to generate the pre-signed URL.

## Generate a Pre-Signed URL for an Amazon S3 PUT Operation with a Specific Payload


You can generate a pre-signed URL for a PUT operation that checks whether users upload the correct content. When the SDK pre-signs a request, it computes the checksum of the request body and generates an MD5 checksum that is included in the pre-signed URL. Users must upload the same content that produces the same MD5 checksum generated by the SDK; otherwise, the operation fails. This is not the Content-MD5, but the signature. To enforce Content-MD5, simply add the header to the request.

The following example adds a `Body` field to generate a pre-signed PUT operation that requires a specific payload to be uploaded by users.

```
package main

import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
    "log"
    "strings"
    "time"
)

func main() {
    // Initialize a session in us-west-2 that the SDK will use to load
    // credentials from the shared credentials file ~/.aws/credentials.
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String("us-west-2")},
    )

    // Create S3 service client
    svc := s3.New(sess)

    req, _ := svc.PutObjectRequest(&s3.PutObjectInput{
        Bucket: aws.String("amzn-s3-demo-bucket"),
        Key:    aws.String("myKey"),
        Body:   strings.NewReader("EXPECTED CONTENTS"),
    })
    str, err := req.Presign(15 * time.Minute)

    log.Println("The URL is:", str, " err:", err)
}
```

If you omit the `Body` field, users can write any contents to the given object.

The following example shows the enforcing of Content-MD5.

```
package main

import (
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/s3"
    "encoding/base64"
    "fmt"
    "crypto/md5"
    "strings"
    "time"
    "net/http"
)

// Downloads an item from an S3 Bucket in the region configured in the shared config
// or AWS_REGION environment variable.
//
// Usage:
//    go run s3_download.go
func main() {
    h := md5.New()
    content := strings.NewReader("")
    content.WriteTo(h)

    // Initialize a session in us-west-2 that the SDK will use to load
    // credentials from the shared credentials file ~/.aws/credentials.
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String("us-west-2")},
    )

    // Create S3 service client
    svc := s3.New(sess)

    resp, _ := svc.PutObjectRequest(&s3.PutObjectInput{
        Bucket: aws.String("amzn-s3-demo-bucket"),
        Key:    aws.String("testKey"),
    })

    md5s := base64.StdEncoding.EncodeToString(h.Sum(nil))
    resp.HTTPRequest.Header.Set("Content-MD5", md5s)

    url, err := resp.Presign(15 * time.Minute)
    if err != nil {
        fmt.Println("error presigning request", err)
        return
    }

    req, err := http.NewRequest("PUT", url, strings.NewReader(""))
    req.Header.Set("Content-MD5", md5s)
    if err != nil {
        fmt.Println("error creating request", url)
        return
    }

    defClient, err := http.DefaultClient.Do(req)
    fmt.Println(defClient, err)
}
```