Uploading Objects to Amazon S3 Using Pre-Signed URLs

Amazon S3 is storage for the Internet. But you don't always want to give away the security credentials to anyone who wants to see/upload something on your bucket. This is where pre-signed urls come in. Anyone with valid security credentials can create a pre-signed URL. However, in order to successfully access an object, the pre-signed URL must be created by someone who has permission to perform the operation that the pre-signed URL is based upon. A pre-signed URL gives you access to the object identified in the URL.

I rencently came across the need to upoad an object to Amazon S3 using a pre signed url from an iOS app. There are some examples for Java, .NET and Ruby already available from Amazon. However, I couldn't find something similar for iOS. Here's an example on how you can upload an image to S3 using an presigned url from an iOS app.

-(void) uploadImage:(UIImage *)image atUrl:(NSString *)url {

  // Upload the image.
  NSData *imageData = UIImageJPEGRepresentation(image, 0.7);
  AFHTTPClient *client = [AFHTTPClient clientWithBaseURL:@"BASE_URL"]; // Initialize the client with some base url.

  // Create URL request.
  NSURL *requestURL = [NSURL URLWithString:[url stringByDecodingURLFormat]];
  NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
  [request setHTTPMethod:@"PUT"];
  [request setValue:@"image/jpeg" forHTTPHeaderField:@"Content-Type"];
  [request setHTTPBody:imageData];
  [request setValue:[NSString stringWithFormat:@"%d", [imageData length]] forHTTPHeaderField:@"Content-Length"];
  [request setValue:@"public-read" forHTTPHeaderField:@"x-amz-acl"];
  [request setValue:@"iPhone-OS/6.0 fr_FR NE" forHTTPHeaderField:@"User-Agent"];
  [request setURL:requestURL];

  // Create the request operation.
  AFHTTPRequestOperation *requestOperation = [client HTTPRequestOperationWithRequest:request
                                                                             success:^(AFHTTPRequestOperation *operation, id responseObject) {
                                                                                 // Do something after successful upload.
                                                                             }
                                                                             failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                                                                                 // Upload failed.
                                                                             }];

  [requestOperation setUploadProgressBlock:^(NSUInteger bytesWritten, long long int totalBytesWritten, long long int totalBytesExpectedToWrite) {
      float progress = (float) totalBytesWritten / (float) totalBytesExpectedToWrite;
      // Update progress on UI.
  }];

  // Begin uploading the file.
  [client enqueueHTTPRequestOperation:requestOperation];
}
Published 25 Oct 2013

I build mobile and web applications. Full Stack, Rails, React, Typescript, Kotlin, Swift
Pulkit Goyal on Twitter