Closed successx closed 2 years ago
Same issue here with:
"@apollo/client": "3.3.13",
"aws-appsync-auth-link": "3.0.4",
"aws-appsync-subscription-link": "3.0.6",
"aws-sdk": "2.873.0",
AppSync no longer supports MQTT on newly created GraphQL API. Would be great to fix IAM auth for websockets!
Hi, Same issue here, I got the same error from IAM auth since I removed my old appsync instance and redeploy it.
"@apollo/client": "^3.3.13",
"aws-appsync-auth-link": "^3.0.4",
"aws-appsync-subscription-link": "^3.0.6",
I need to generate my graphql client depending on the authentication type (IAM / Cognito) to let users log from Federated Entites like Google, either by username/pass. AWSAppsyncClient doesn't let me create 2 instances because of conflict issues. So I chosed ApolloClient.
const createApolloClient = authType => {
const httpLink = new HttpLink({
uri: APIConfiguration.aws_appsync_graphqlEndpoint,
});
const cognitoAuth = {
type: APIConfiguration.aws_appsync_authenticationTypeCognito,
jwtToken: APIConfiguration.aws_jwToken
};
const iamAuth = {
type: APIConfiguration.aws_appsync_authenticationTypeIAM,
credentials: () => Auth.currentCredentials()
};
return new ApolloClient({
cache: new InMemoryCache(),
defaultOptions: {
watchQuery: { fetchPolicy: 'no-cache', errorPolicy: 'ignore' },
query: { fetchPolicy: 'no-cache', errorPolicy: 'all' }
},
connectToDevTools: process.env.APP_STAGE === 'dev',
link: from([
createAuthLink({
url: APIConfiguration.aws_appsync_graphqlEndpoint,
region: APIConfiguration.aws_appsync_region,
auth: authType === 'COGNITO'
? cognitoAuth
: iamAuth
}),
split(op => {
const { operation } = op.query.definitions[0];
if (operation === 'subscription') {
return false;
}
return true;
}, httpLink, createSubscriptionHandshakeLink(
{
url: APIConfiguration.aws_appsync_graphqlEndpoint,
region: APIConfiguration.aws_appsync_region,
auth: authType === 'COGNITO'
? cognitoAuth
: iamAuth
},
httpLink
))
]),
});
}
with
export const APIConfiguration = {
aws_appsync_graphqlEndpoint: process.env.GRAPHQL_ENDPOINT,
aws_appsync_region: process.env.AWS_REGION,
aws_appsync_authenticationTypeIAM: "AWS_IAM",
aws_appsync_authenticationTypeCognito: "AMAZON_COGNITO_USER_POOLS",
aws_jwToken: async () => {
const session = await Amplify.Auth.currentSession();
return session.getIdToken().getJwtToken();
},
};
@successx how did you revert back to mqtt ? I'm very intrigued ... As I use Serverless config file to deploy, it deployed a new appsync instance, I can't find where I can set the protocol to use for subscriptions (pure websocket / mqtt over websocket)
Edit : When I log with username/password, I got a Connection closed error from my subscription with no clue
Hm, I didn't realise app sync already deprecate mqtt. For us, simply use createSubscriptionHandshakeLink(url) does the trick for mqtt. Not sure if it works for your auth cases. For anyone waiting for the fix from aws, I've forked a stripped down version with IAM auth over websocket subscription only (link). We've been using it for the web for a while in our monorepo. Feel free to add your own logging solution to improve it.
@successx How did you fix it?
I've read diff -ru aws-mobile-appsync-sdk-js/packages/aws-appsync-subscription-link aws-appsync-subscription-link
but as there are lots of changes, I did not understand what's the fix there.
After a load of comparison between @successx's changes and the original code. The change that "fixed" the issue for me was to comment out this line: https://github.com/awslabs/aws-mobile-appsync-sdk-js/blob/master/packages/aws-appsync-subscription-link/src/realtime-subscription-handshake-link.ts#L104
This fixes the issue because these graphql_headers
seem to be used here to create the "start subscription" message:
https://github.com/awslabs/aws-mobile-appsync-sdk-js/blob/master/packages/aws-appsync-subscription-link/src/realtime-subscription-handshake-link.ts#L256
but is not used here to initialize the websocket connection: https://github.com/awslabs/aws-mobile-appsync-sdk-js/blob/master/packages/aws-appsync-subscription-link/src/realtime-subscription-handshake-link.ts#L366
Which results in a mismatch of headers and thus a Bad Request
I believe the fix isn't to comment out the line I originally linked but to actually pass through the graphql_headers
to _initializeWebSocketConnection
so that the headers for initializing the websocket connection actually match the subsequent "start subscription" message.
I've made a PR here https://github.com/awslabs/aws-mobile-appsync-sdk-js/pull/633
I've been having the same issue whereby the signed headers appear to mismatch those included in the GraphQL message payload.
As @Eveliyse 's PR (#633) indicates, the removal of graphql_headers
seems to resolve the issue in question.
Thanks for the investigation!
Edit: This change appears to remove any custom headers which are set in a prior link. So if no custom headers are required, the above fix works. But care should be taken when your connection requires custom headers also be set.
import { setContext } from "@apollo/link-context";
const linkParams = {
url: "",
region: "",
auth: {
type: AUTH_TYPE.AWS_IAM,
credentials: {}, // IAM credentials
} as AuthOptions,
};
const httpAndWSCompositeLink = ApolloLink.from([
setContext((request, previousContext) => ({
headers: {
...previousContext.headers,
"x-my-header": "foo-bar",
},
})),
createAuthLink(linkParams),
createSubscriptionHandshakeLink(linkParams),
]);
I commented on PR #633 , aside from removing the headers, it appears that the actual intent may have been to return an object with headers:
instead of:
graphql_headers: () => (headers),
it could be:
graphql_headers: () => ({headers}),
UPDATE: eh I think having the headers as an attribute of an object may have worked as a fluke. attempting to expand the attributes of the headers fails, so the original solution is preferable.
I ended up directly modifying the prototype method so that it won't send graphql_headers to unblock me.
// HACK since this PR {@link https://github.com/awslabs/aws-mobile-appsync-sdk-js/pull/633/files} has not been accepted
// after several months, we go ahead and modify the method to drop the graphql_headers that are causing subscription problems.
const {
AppSyncRealTimeSubscriptionHandshakeLink,
} = require('aws-appsync/node_modules/aws-appsync-subscription-link/lib/realtime-subscription-handshake-link');
const oldStartSubscription =
AppSyncRealTimeSubscriptionHandshakeLink.prototype
._startSubscriptionWithAWSAppSyncRealTime;
AppSyncRealTimeSubscriptionHandshakeLink.prototype._startSubscriptionWithAWSAppSyncRealTime =
function (a) {
if (a.options) {
delete a.options.graphql_headers;
}
return oldStartSubscription.call(this, a);
};
I don't think this issue is fixed. I upgraded to aws-appsync 4.1.2 which includes aws-appsync-subscription-link 2.2.5, and I'm still getting the same error:
The request signature we calculated does not match the signature you provided...
Can anyone else confirm/deny?
If I replace my realtime-subscription-handshake-link.ts with the fixed one, the problem goes away. https://github.com/awslabs/aws-mobile-appsync-sdk-js/blob/apollov2/packages/aws-appsync-subscription-link/src/realtime-subscription-handshake-link.ts
I don't think this issue is fixed. I upgraded to aws-appsync 4.1.2 which includes aws-appsync-subscription-link 2.2.5, and I'm still getting the same error:
The request signature we calculated does not match the signature you provided...
Can anyone else confirm/deny?
aws-appsync-subscription-link@2.2.5 doesn't have the fix. The PR has been merged to apollov2
but not released yet.
Is there an ETA on the release?
@beckleyc - see @kenmckaba's comment above. 2.2.5
is not the latest version for use with Apollo V2. Can you let me know what Apollo versions you are using, and perhaps give examples of how you are setting up the client? We recently updated our README to make this more clear, but open to suggestions if it's still ambiguous.
If you are using Apollo V3 (and this is the suggested approach), then you will NOT want to use aws-appsync to create your client. Instead, you'll want to use the latest versions of the subscription and / or auth links, and follow the configuration listed here: https://github.com/awslabs/aws-mobile-appsync-sdk-js#using-authorization-and-subscription-links-with-apollo-client-v3-no-offline-support
However, if you are using Apollo V2, you can still use the aws-appsync package, but you'll need to use the minor versions that we recently published. For Apollo V2, that's version 2.2.6 for the subscription link (see the apolloV2 tag listed under "Versions": https://www.npmjs.com/package/aws-appsync-subscription-link, and version 2.0.7 for the auth link, also listed under the apolloV2 tag: https://www.npmjs.com/package/aws-appsync-auth-link).
If you have followed the above and are still running into an issue, please let me know and we can re-open this issue.
@kenmckaba - the fixes are released, please let me know if you encounter further issues!
Do you want to request a feature or report a bug? Bug
What is the current behavior? Subscription over web-socket fail for IAM authorization. Receive following error when debugging _handleIncomingSubscriptionMessage.
{ errorType: "BadRequestException", message: "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method....}
If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Successfully initialized handshake with the same signature using IAM auth. The above error only receives at _handleIncomingSubscriptionMessage. Probably because websocket signature is different.What is the expected behavior? https://docs.aws.amazon.com/appsync/latest/devguide/real-time-websocket-client.html Looks like realtime-subscription-handshake-link sign header using "body" key instead of "data" key for IAM authorization from the documentation. However, change "body" to "data" to sign header throw signature mismatch when initializing handshake.
Which versions and which environment (browser, react-native, nodejs) / OS are affected by this issue? Did this work in previous versions?
For the moment, I revert back to use mqtt. It works fine so far, but the deprecation is coming soon. Love to be able to use web socket ASAP.
Cheers,