Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to connect to Events API with IAM authentication #14001

Closed
3 tasks done
dreamorosi opened this issue Nov 11, 2024 · 1 comment
Closed
3 tasks done

Unable to connect to Events API with IAM authentication #14001

dreamorosi opened this issue Nov 11, 2024 · 1 comment
Assignees
Labels
GraphQL Related to GraphQL API issues pending-maintainer-response Issue is pending a response from the Amplify team.

Comments

@dreamorosi
Copy link

dreamorosi commented Nov 11, 2024

Before opening, please confirm:

JavaScript Framework

Not applicable

Amplify APIs

GraphQL API

Amplify Version

v6

Amplify Categories

api

Backend

None

Environment information

# Put output below this line
System:
    OS: macOS 14.7.1
    CPU: (12) arm64 Apple M2 Pro
    Memory: 100.64 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.12.2 - ~/.local/state/fnm_multishells/83883_1731329339080/bin/node
    Yarn: 1.22.22 - ~/.local/state/fnm_multishells/83883_1731329339080/bin/yarn
    npm: 10.5.0 - ~/.local/state/fnm_multishells/83883_1731329339080/bin/npm
    pnpm: 9.6.0 - ~/.local/state/fnm_multishells/83883_1731329339080/bin/pnpm
  Browsers:
    Chrome: 130.0.6723.117
    Safari: 18.1
  npmPackages:
    @aws-sdk/client-location: ^3.687.0 => 3.687.0 
    @aws/amazon-location-utilities-auth-helper: ^1.2.0 => 1.2.0 
    @types/react: ^18.3.12 => 18.3.12 
    @types/react-dom: ^18.3.1 => 18.3.1 
    @vitejs/plugin-react: ^4.3.3 => 4.3.3 
    aws-amplify: ^6.8.0 => 6.8.0 
    aws-amplify/adapter-core:  undefined ()
    aws-amplify/analytics:  undefined ()
    aws-amplify/analytics/kinesis:  undefined ()
    aws-amplify/analytics/kinesis-firehose:  undefined ()
    aws-amplify/analytics/personalize:  undefined ()
    aws-amplify/analytics/pinpoint:  undefined ()
    aws-amplify/api:  undefined ()
    aws-amplify/api/server:  undefined ()
    aws-amplify/auth:  undefined ()
    aws-amplify/auth/cognito:  undefined ()
    aws-amplify/auth/cognito/server:  undefined ()
    aws-amplify/auth/enable-oauth-listener:  undefined ()
    aws-amplify/auth/server:  undefined ()
    aws-amplify/data:  undefined ()
    aws-amplify/data/server:  undefined ()
    aws-amplify/datastore:  undefined ()
    aws-amplify/in-app-messaging:  undefined ()
    aws-amplify/in-app-messaging/pinpoint:  undefined ()
    aws-amplify/push-notifications:  undefined ()
    aws-amplify/push-notifications/pinpoint:  undefined ()
    aws-amplify/storage:  undefined ()
    aws-amplify/storage/s3:  undefined ()
    aws-amplify/storage/s3/server:  undefined ()
    aws-amplify/storage/server:  undefined ()
    aws-amplify/utils:  undefined ()
    maplibre-gl: ^4.7.1 => 4.7.1 ()
    react: ^18.3.1 => 18.3.1 
    react-dom: ^18.3.1 => 18.3.1 
    react-map-gl: ^7.1.7 => 7.1.7 
    vite: ^5.4.11 => 5.4.11 
  npmGlobalPackages:
    corepack: 0.25.2
    npm: 10.5.0

Describe the bug

When using the aws-amplify/data with an Events API set up with IAM authentication, the connection fails with a NonRetryableError.

Expected behavior

The Websocket should work with IAM authentication.

Reproduction steps

import React, { useState, useEffect, useRef } from "react";
import { Amplify } from 'aws-amplify';
import { ConsoleLogger } from 'aws-amplify/utils';
ConsoleLogger.LOG_LEVEL = 'DEBUG';
import { fetchAuthSession } from 'aws-amplify/auth'
import { events } from 'aws-amplify/data';
import { createRoot } from "react-dom/client";
import Map from "react-map-gl/maplibre";
import { withIdentityPoolId } from "@aws/amazon-location-utilities-auth-helper";

import 'maplibre-gl/dist/maplibre-gl.css';
import "./index.css";

Amplify.configure({
  Auth: {
    Cognito: {
      region: "eu-west-1",
      identityPoolId: "eu-west-1: xxxxxxxxxx",
      allowGuestAccess: true,
    }
  },
  API: {
    Events: {
      endpoint: "https://api-id.appsync-api.eu-west-1.amazonaws.com/event",
      region: "eu-west-1",
      defaultAuthMode: "iam"
    }
  },
  region: "eu-west-1",
});

const identityPoolId = "eu-west-1:xxxxxxxxxx";
const region = "eu-west-1";
const styleName = "Standard"; // Standard, Monochrome, Hybrid, or Satellite

const authHelper = await withIdentityPoolId(identityPoolId);

const App = () => {
  const [myEvents, setMyEvents] = useState([]);
  const channelRef = useRef(null)

  useEffect(() => {
    const connectAndSubscribe = async () => {
			console.log('Connecting to channel')
      if (channelRef.current) {
        return;
      }
      try {
        const channel = await events.connect('/default/channel')
	console.log('Channel subscribed')
	channelRef.current = channel

        channel.subscribe({
	  next: (data) => {
            console.log('received', data)            
          },
	  error: (err) => console.log(err),
        })
      } catch (e) {
         console.log('Error connecting to channel: ', e)
      }
     }

    connectAndSubscribe();

    return () => {
			if (channelRef.current) {
				channelRef.current.close()
			}
		}
  }, []);

  return (
    <Map
      initialViewState={{
        longitude: -123.1169,
        latitude: 49.2824,
        zoom: 16,
      }}
      style={{ width: "100vw", height: "100vh" }}
      mapStyle={`https://maps.geo.${region}.amazonaws.com/v2/styles/${styleName}/descriptor`}
      transformRequest={authHelper.getMapAuthenticationOptions().transformRequest}
    />
  );
}

createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Code Snippet

// Put your code below this line.

Log output

See logs below ⬇️ ⬇️ ⬇️ ⬇️ ⬇️

// Put your logs below this line
[DEBUG] 34:13.758 AWSAppSyncRealTimeProvider Auth - Authenticating with "iam"
[DEBUG] 34:13.759 CognitoCredentialsProvider - Clearing out in-memory credentials
[DEBUG] 34:13.880 AWSAppSyncEventsProvider - Establishing retryable connection
[DEBUG] 34:13.880 retryUtil - bound  attempt #1 with this vars: ["wss://gasctn76kraldllcpmqms44pyu.appsync-realtime-api.eu-west-1.amazonaws.com/event/realtime","header-eyJhY2NlcH ......
[DEBUG] 34:13.880 AWSAppSyncEventsProvider - Establishing WebSocket connection to wss://gasctn76kraldllcpmqms44pyu.appsync-realtime-api.eu-west-1.amazonaws.com/event/realtime
[DEBUG] 34:14.119 AWSAppSyncEventsProvider - subscription message from AWS AppSyncRealTime: {"errors":[{"errorType":"BadRequestException","message":"The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.\n\nThe Canonical String for this request should have been\n'POST\n/event\n\naccept:application/json, text/javascript\ncontent-encoding:amz-1.0\ncontent-type:application/json; charset=UTF-8\nhost:api-id.appsync-api.eu-west-1.amazonaws.com\nx-amz-date:20241111T173413Z\nx-amz-security-token:xxxxxxxxxxxxx\n\naccept;content-encoding;content-type;host;x-amz-date;x-amz-security-token\nxxxxxxxxxxxxxx'\n\nThe String-to-Sign should have been\n'AWS4-HMAC-SHA256\n20241111T173413Z\n20241111/eu-west-1/appsync/aws4_request\n714896dcf56b33c34cec13ee8137ebc0a5c35895af0ac92924fd111a4ccab2e4'\n","errorCode":400}],"type":"connection_error"} 
[DEBUG] 34:14.120 retryUtil - error on bound  NonRetryableError: BadRequestException
    at AWSWebSocketProvider._establishConnection (aws-amplify_data.js?v=b49bb864:7873:17)
    at async chunk-2MQQKA2O.js?v=21653013:1073:17
DEBUG] 34:14.120 retryUtil - bound  non retryable error NonRetryableError: BadRequestException
    at AWSWebSocketProvider._establishConnection (aws-amplify_data.js?v=b49bb864:7873:17)
    at async chunk-2MQQKA2O.js?v=21653013:1073:17
chunk-2MQQKA2O.js?v=21653013:114 [DEBUG] 34:14.120 AWSAppSyncEventsProvider - Connection exited with NonRetryableError: BadRequestException
    at AWSWebSocketProvider._establishConnection (aws-amplify_data.js?v=b49bb864:7873:17)
    at async chunk-2MQQKA2O.js?v=21653013:1073:17
chunk-2MQQKA2O.js?v=21653013:107 [DEBUG] 34:14.121 AWSAppSyncEventsProvider {err: NonRetryableError: BadRequestException
    at AWSWebSocketProvider._establishConnection (http://loc…}

The header, once base64 decoded has the following JSON (redacted):

{
  "accept": "application/json, text/javascript",
  "content-encoding": "amz-1.0",
  "content-type": "application/json; charset=UTF-8",
  "host": "api-id.appsync-api.eu-west-1.amazonaws.com",
  "x-amz-date": "20241111T173413Z",
  "x-amz-security-token": "xxxxxxxx",
  "authorization": "AWS4-HMAC-SHA256 Credential=ASIAXxxxxxxxxxxxxxx/20241111/eu-west-1/appsync/aws4_request, SignedHeaders=accept;content-encoding;content-type;host;x-amz-date;x-amz-security-token, Signature=5ecfxxxxxxxxxxxxxxxx"
}

aws-exports.js

No response

Manual configuration

Amplify.configure({
  Auth: {
    Cognito: {
      region: "eu-west-1",
      identityPoolId: "eu-west-1:xxxxxxxxxxxxxxxxxxx",
      allowGuestAccess: true,
    }
  },
  API: {
    Events: {
      endpoint: "https://api-id.appsync-api.eu-west-1.amazonaws.com/event",
      region: "eu-west-1",
      defaultAuthMode: "iam"
    }
  },
  region: "eu-west-1",
});

Additional configuration

Resources:
  WebsocketAPI:
    Type: AWS::AppSync::Api
    Properties:
      EventConfig:
        AuthProviders:
          - AuthType: AWS_IAM
        ConnectionAuthModes:
          - AuthType: AWS_IAM
        DefaultPublishAuthModes:
          - AuthType: AWS_IAM
        DefaultSubscribeAuthModes:
          - AuthType: AWS_IAM
      Name: trackerAssetWebsocketAPI
  
  WebsocketAPINamespace:
    Type: AWS::AppSync::ChannelNamespace
    Properties:
      ApiId: !GetAtt WebsocketAPI.ApiId
      Name: asset-tracker
  
  IdentityPoolEC8A1A0D:
    Type: AWS::Cognito::IdentityPool
    Properties:
      AllowUnauthenticatedIdentities: true
      CognitoIdentityProviders: []
  
  IdentityPoolAuthenticatedRole42131CF5:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Federated: cognito-identity.amazonaws.com
            Action: sts:AssumeRoleWithWebIdentity
            Condition:
              StringEquals:
                'cognito-identity.amazonaws.com:aud': !Ref IdentityPoolEC8A1A0D
              ForAnyValue:StringLike:
                'cognito-identity.amazonaws.com:amr': authenticated
      Description: !Join ['', ['Default Authenticated Role for Identity Pool ', !GetAtt IdentityPoolEC8A1A0D.Name]]
  
  IdentityPoolUnauthenticatedRole68AEFF8B:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Federated: cognito-identity.amazonaws.com
            Action: sts:AssumeRoleWithWebIdentity
            Condition:
              StringEquals:
                'cognito-identity.amazonaws.com:aud': !Ref IdentityPoolEC8A1A0D
              ForAnyValue:StringLike:
                'cognito-identity.amazonaws.com:amr': unauthenticated
      Description: !Join ['', ['Default Unauthenticated Role for Identity Pool ', !GetAtt IdentityPoolEC8A1A0D.Name]]
  
  IdentityPoolDefaultRoleAttachmentD81AFC39:
    Type: AWS::Cognito::IdentityPoolRoleAttachment
    Properties:
      IdentityPoolId: !Ref IdentityPoolEC8A1A0D
      Roles:
        authenticated: !GetAtt IdentityPoolAuthenticatedRole42131CF5.Arn
        unauthenticated: !GetAtt IdentityPoolUnauthenticatedRole68AEFF8B.Arn

  websocketServicePolicy:
    Type: AWS::IAM::Policy
    Properties:
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action:
              - appsync:EventSubscribe
              - appsync:EventConnect
              - appsync:EventPublish
            Resource:
              - !Join 
                - ''
                - - 'arn:aws:appsync:'
                  - !Ref AWS::Region
                  - ':'
                  - !Ref AWS::AccountId
                  - ':apis/'
                  - !GetAtt WebsocketAPI.ApiId
                  - '/*'
      PolicyName: websocketServicePolicy
      Roles:
        - !Ref IdentityPoolUnauthenticatedRole68AEFF8B

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

@github-actions github-actions bot added pending-triage Issue is pending triage pending-maintainer-response Issue is pending a response from the Amplify team. labels Nov 11, 2024
@cwomack cwomack added the GraphQL Related to GraphQL API issues label Nov 11, 2024
@iartemiev iartemiev self-assigned this Nov 12, 2024
@dreamorosi
Copy link
Author

[email protected] fixed the issue.

@github-actions github-actions bot added pending-maintainer-response Issue is pending a response from the Amplify team. and removed pending-triage Issue is pending triage pending-maintainer-response Issue is pending a response from the Amplify team. labels Nov 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
GraphQL Related to GraphQL API issues pending-maintainer-response Issue is pending a response from the Amplify team.
Projects
None yet
Development

No branches or pull requests

3 participants