aws / aws-appsync-community

The AWS AppSync community
https://aws.amazon.com/appsync
Apache License 2.0
506 stars 32 forks source link

Getting error on Appsync websocket connection: You are not authorized to make this call #373

Open ashwinikumar07 opened 1 month ago

ashwinikumar07 commented 1 month ago

Screenshot 2024-10-02 190752

You are not authorized to make this call

I am trying to create aws appsync subscription with IAM auth. I am able to query/mutation the appsync with the same IAM credentials, but getting the exception on websocket connection.

import { Sha256 } from '@aws-crypto/sha256-js';
import { HttpRequest } from '@aws-sdk/protocol-http';
import { SignatureV4 } from '@aws-sdk/signature-v4';

const createWSSUrl = async (signer, request) => {
    let headerString = "";
    // Sign the request asynchronously
    return signer.sign(request).then((signedRequest) => {
        // Create the URL with the signed headers (base64-encoded)
        headerString = Buffer.from(JSON.stringify({
            host: signedRequest.headers.host,
            'x-amz-date': signedRequest.headers['x-amz-date'],
            Authorization: signedRequest.headers['Authorization'],
        })).toString('base64');

        console.log('Signed headers:', signedRequest.headers);

        console.log('Header String (base64-encoded):', headerString);

        // Construct the WebSocket URL after signing is complete
        const wssURL = `wss://xxxxxxxxxxxxxxxxxxx.appsync-realtime-api.us-east-1.amazonaws.com/graphql?header=${headerString}&payload=e30=`;

        return wssURL; // Return the WebSocket URL
    })
};

export const auth = async () => {
    const endpoint = new URL('https://xxxxxxxxxxxxxxxxxxxxxxx.appsync-api.us-east-1.amazonaws.com/graphql/connect');

    const credentials = {
        accessKeyId: 'xxxxxxxxxxxxxxxxxxxxxxx',
        secretAccessKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    }

    const signer = new SignatureV4({
        region: 'us-east-1',
        service: 'appsync',
        credentials,
        sha256: Sha256
    });

    const request = new HttpRequest({
        url: endpoint,
        method: 'POST',
        data: "{}",
        headers: {
            "accept": "application/json, text/javascript",
            "content-encoding": "amz-1.0",
            "content-type": "application/json; charset=UTF-8",
            host: endpoint.host,
        }
    });

 createWSSUrl(signer, request).then((wssURL) => {
        console.log('WebSocket URL:', wssURL);
        const ws = new WebSocket(wssURL, ["graphql-ws"]);

        ws.onopen = (event) => {
            console.log('WebSocket connected:', event);
            ws.send(
                JSON.stringify({
                type: 'connection_init',
            }));
        };
        ws.onmessage = (event) => {
            console.log('Received message:', event.data);
        };
        ws.onerror = (error) => {
            console.error('WebSocket error:', error);
        };
        // Handle connection close
        ws.onclose = (event) => {
            console.log('WebSocket connection closed:', event);
        };
    }).catch((err) => {
        console.error('Error creating WSS URL:', err);
    });
}
ashwinikumar07 commented 1 month ago

Can anyone help me on this?

jbbasson commented 1 month ago
   const authHeaders = {
      Authorization: `Bearer ${token}`, <-- we use authorizer lambda, change as necessary
      host: `${host.replace('https://', '').replace('/graphql', '')}`, // need to strip the 'https://' and '/graphql' from your appsync http url
      // can specify any other custom headers
    };

    const encodedHeaders = btoa(JSON.stringify(authHeader));
    const emptyPayload = btoa(JSON.stringify({}));

    // we use rxjs WebSocket wrapper for WebSocket()
    return this.wsFactory.makeSocket({
      url: `${your_websocket_url}?header=${encodedHeaders}&payload=${emptyPayload}`,
      protocol: 'graphql-ws',
      openObserver: {
        next: () => {
          this.webSocket$!.next({ type: 'connection_init' });
        },
      },
      closeObserver: {
        next: () => {},
      },
    });
ashwinikumar07 commented 1 month ago

@jbbasson I am using IAM appsync auth and getting the above error.

jbbasson commented 1 month ago

we had to strip the https:// prefix and /graphql post fix from the https endpoint of appsync before setting is as the host in the auth header

ashwinikumar07 commented 1 month ago

@jbbasson I tried strip the https:// prefix and /graphql post fix from the https endpoint of appsync. But still getting the same error.

jbbasson commented 1 month ago

can you show your current version of code?