7
votes

I am not sure how to send signed http request do AppSync GraphQL endpoint. There is no library for do that in AWS.

  • aws-amplify don't work because works only in browser, not in Lambda function.
  • aws-sdk for AppSync is only for admin usage, it doesn't have methods for call user side api

It is possible to make IAM signed HTTP request from AWS Lambda? (in some easy way)

3

3 Answers

5
votes

i would recommend reading this article: Backend GraphQL: How to trigger an AWS AppSync mutation from AWS Lambda,

quoting the author, https://stackoverflow.com/users/1313441/adrian-hall, we've:

GraphQL is routed over HTTPS. That means we can simulate the GraphQL client libraries with a simple HTTPS POST. Since we are using IAM, we need to sign the request before we deliver it. Here is my code for this:

// ... more code here
    // POST the GraphQL mutation to AWS AppSync using a signed connection
    const uri = URL.parse(env.GRAPHQL_API);
    const httpRequest = new AWS.HttpRequest(uri.href, env.REGION);
    httpRequest.headers.host = uri.host;
    httpRequest.headers['Content-Type'] = 'application/json';
    httpRequest.method = 'POST';
    httpRequest.body = JSON.stringify(post_body);

    AWS.config.credentials.get(err => {
        const signer = new AWS.Signers.V4(httpRequest, "appsync", true);
        signer.addAuthorization(AWS.config.credentials, AWS.util.date.getDate());

        const options = {
            method: httpRequest.method,
            body: httpRequest.body,
            headers: httpRequest.headers
        };

        fetch(uri.href, options)
// ... more code here

I've been using it as a template for all my Lambda->AppSync communication!

0
votes

You can use any graphql client or a sigv4 signed HTTP request. Here's how you create the signature for your request (https://docs.aws.amazon.com/general/latest/gr/signature-version-4.html). If you attach an execution role to your lambda you can access it access key from lambda environment variables (https://docs.aws.amazon.com/lambda/latest/dg/lambda-environment-variables.html).

0
votes

This question is already answered but since it came up first for me I thought I'd share another solution.

My use-case was to send a signed request to custom HTTP API hosted on AWS where cognito was used as authentication backend that only had ALLOW_USER_SRP_AUTH enabled (so no ALLOW_ADMIN_USER_PASSWORD_AUTH nor ALLOW_USER_PASSWORD_AUTH)

I ended up combining this example from AWS showing how to do cognito authentication in node:

With the other example from AWS showing how to sign request:

You plug in the second example into the first example by replacing this line (from first example):

//(...)
        //refreshes credentials using AWS.CognitoIdentity.getCredentialsForIdentity()
        AWS.config.credentials.refresh(error => {
            if (error) {
                console.error(error);
            } else {
                // Instantiate aws sdk service objects now that the credentials have been updated.
                // example: var s3 = new AWS.S3();
                console.log('Successfully logged!'); // <-- replace this line
            }
        });
//(...)

Second example needs some tweaks to fit your requirements, things I had to change was:

  • HTTP method (I needed GET)
  • signer declaration - I had to change service (replaced es with execute-api)
  • In signer.addAuthorization I had to use AWS.config.credentials (already initialized by the code from first example) instead of AWS.EnvironmentCredentials('AWS')

Hope this helps someone!