skip to Main Content

I’m trying to use @aws-sdk/client-s3 to read and write some files to an S3 bucket. However, when trying to do this within SvelteKit I get this error:

CredentialsProviderError: Could not load credentials from any providers
    at /repo-location/node_modules/@aws-sdk/credential-provider-node/dist-cjs/defaultProvider.js:13:11

This looks to be because it is looking for process.env variables (among other places).

Is there a way for me to do something like this (I know the below is incorrect)?

import { S3Client } from '@aws-sdk/client-s3';
import { env } from '$env/dynamic/private';

const client = new S3Client({ env, region });

How can I get it to use SvelteKit’s way of handling environment variables instead? Or am I approaching this the wrong way?

2

Answers


  1. Chosen as BEST ANSWER

    Thanks to Filippo, I got the issue resolved. Here's the full TypeScript code for me to get it working.

    import { S3Client, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3";
    import {
      AWS_REGION,
      AWS_ACCESS_KEY_ID,
      AWS_SECRET_ACCESS_KEY,
      S3_BUCKET_NAME,
    } from "$env/static/private";
    
    const s3 = new S3Client({
      region: AWS_REGION,
      credentials: {
        accessKeyId: AWS_ACCESS_KEY_ID,
        secretAccessKey: AWS_SECRET_ACCESS_KEY,
      }
    });
    
    const getKey = (path: string) => `saved/${path}.json`;
    
    export async function saveToS3(path: string, data: JSON) {
      // TODO add some sort of abuse prevention
      const key = getKey(path);
      const uploadCommand = new PutObjectCommand({
        Bucket: S3_BUCKET_NAME,
        Key: key,
        Body: data,
        ACL: "public-read",
      });
      try {
        const response = await s3.send(uploadCommand);
        console.log("S3 upload success ", response);
      } catch (error) {
        console.error("S3 upload error ", error);
      }
    };
    
    export async function loadFromS3(path: string): Promise<JSON> {
      // TODO add some sort of abuse prevention
      const key = getKey(path);
      const getCommand = new GetObjectCommand({
        Bucket: S3_BUCKET_NAME,
        Key: key,
      });
      try {
        const data = await s3.send(getCommand);
        const str = await data.Body.transformToString();
        console.log("S3 download success ", str);
        return str;
      } catch (error) {
        console.error("S3 download error ", error);
        return <JSON>(error);
      }
    }
    

  2. I don’t see any problem with providing static credential values via .env files.

    I’ve tried creating an S3 Client myself and loading the credentials from the .env, following this example in the Svelte docs.

    Here’s my .env file, located at the root of the project:

    ACCESS_KEY_ID = 'MY_ACCESS_KEY'
    ACCESS_KEY_SECRET = 'MY_SECRET'
    

    Here’s how to create the S3 client using JS:

    import { S3Client } from '@aws-sdk/client-s3';
    import { ACCESS_KEY_ID, ACCESS_KEY_SECRET } from '$env/static/private';
    
    const client = new S3Client({
        region:'eu-south-1',
        credentials: {
            accessKeyId: ACCESS_KEY_ID,
            secretAccessKey: ACCESS_KEY_SECRET
        }
    });
    

    However, please note that in a real-world environment, you shouldn’t hardcode credentials.
    Refer to the documentation to determine the most suitable method depending on where your code is running.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search