We'd like to use Javascript AWS SDK to upload files to S3, but without using credentials at all.
Uploading using credentials works, but we cannot generate an AWS IAM user for each of our app users (or should we?)
Therefore, similar to using GET, we'd like the server to generate a pre-signed URL, send it to browser, and have the browser upload to that URL.
However, there are no examples on how to accomplish this. Is this possible, and how? If not, could it be implemented?
Also, if not setting a credential, even before making the upload to S3 HTTPS request, the SDK errors with
code: "CredentialsError"
message: "No credentials to load"
(We tried uploading to a Key set to pre-signed URL)
The JS SDK docs mention this, so it seems it would be possible:
Pre-signing a putObject (asynchronously)
var params = {Bucket: 'bucket', Key: 'key'};
s3.getSignedUrl('putObject', params, function (err, url) {
console.log('The URL is', url);
});
If you already have a presigned URL generated for the browser, you can simply send an XHR request with that URL and the payload to upload to S3. The SDK would not be required to do this. A jQuery example below:
$.ajax({
url: presignedUrl, // the presigned URL
type: 'PUT',
data: 'data to upload into URL',
success: function() { console.log('Uploaded data successfully.'); }
});
If you're asking how to _generate_ a signed URL, this would have to be done on the server side, not the client. Are you running node.js on the server? If not, you will want to use an SDK for the server environment (we have SDKs for Ruby, Java, Python, and .NET, as well).
Thanks, that's what I was looking for!
I preferred using aws cognito identitypoolid;
`
var bucketName = '....';
AWS.config.region = 'us-east-1';
var IdentityPoolId = '........';
AWS.config.update({
credentials: new AWS.CognitoIdentityCredentials({
IdentityPoolId: IdentityPoolId
})
});
var bucket = new AWS.S3({
params: {
Bucket: bucketName,
}
});
................
...............
var params = {
Key: objKey,
ContentType: blob.type,
Body: blob,
ACL: 'public-read'
};
bucket.putObject(params, function (err, data) {
if (err) {
results.innerHTML = 'ERROR: ' + err;
} else {
console.log('succesfully uploaded the image!');
console.log('https://s3.amazonaws.com/..../'+""+objKey);
}
`
For aws cognito you are using the SDK. I guess there must be a distinction on what the original post is about.
If I understand correctly, @scottsd was concerned about creating credentials for each user in order to let them upload files to S3.
Pre-signed URL's is the preferable non-invasive way of letting unknow users upload files to S3. Although, there must be one user (the one providing credentials server side) that is using his account to generate the pre-signed url. Obviously, that user needs to have permissions to perform such operation. (SDK client-side or any AWS related interaction other than the upload is not required) *Credentials not required... client side!
Assume Role. If you are managing a cognito user pool or any other Authentication provider, you can create a "Federated Identity" that will let your users "Assume a Rol" with S3 privileges or any other privileges you define for a role, for Authenticated and Non-authenticated users, depending how you configure it. (SDK client-side required for simplicity, AWS interactions for authentication and signing required) *Credentials required client side!
Further to this question: AWS supports a managed uploader in the SDK ( https://aws.amazon.com/blogs/developer/announcing-the-amazon-s3-managed-uploader-in-the-aws-sdk-for-javascript/ ) which handles multi-part uploads and supplies progress checks, among other features. Can this be used with presigned S3 URLs? Or must the user be logged in to AWS first?
If you already have a presigned URL generated for the browser, you can simply send an XHR request with that URL and the payload to upload to S3. The SDK would not be required to do this. A jQuery example below:
$.ajax({ url: presignedUrl, // the presigned URL type: 'PUT', data: 'data to upload into URL', success: function() { console.log('Uploaded data successfully.'); } });If you're asking how to _generate_ a signed URL, this would have to be done on the server side, not the client. Are you running node.js on the server? If not, you will want to use an SDK for the server environment (we have SDKs for Ruby, Java, Python, and .NET, as well).
why does it have to be on the server side? I have this in my Vue app and it works perfectly:
const aws = require('aws-sdk')
aws.config.update({
secretAccessKey: process.env.VUE_APP_AWS_SECRET_ACCESS_KEY,
accessKeyId: process.env.VUE_APP_AWS_ACCESS_KEY,
})
export const s3 = new aws.S3({
signatureVersion: 'v4',
region: process.env.VUE_APP_AWS_REGION,
})
and then I'll just use the s3 instance in my functions. Is this a bad design? In case it is then why?
Thanks in advance!
@kepi0809 this way you are exposing your credentials to the world, so you should use another approach (like using a server to generate a pre-signed url for you to use in Vue).
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.
Most helpful comment
If you already have a presigned URL generated for the browser, you can simply send an XHR request with that URL and the payload to upload to S3. The SDK would not be required to do this. A jQuery example below:
If you're asking how to _generate_ a signed URL, this would have to be done on the server side, not the client. Are you running node.js on the server? If not, you will want to use an SDK for the server environment (we have SDKs for Ruby, Java, Python, and .NET, as well).