ilijaNL / graphql-codegen-signed-operation

GraphQL codegen plugin for signing operation with some secret
https://github.com/ilijaNL/graphql-codegen-signed-operation
MIT License
4 stars 1 forks source link

Signed hash mismatch for fragments when using with AppSync Lambda authorizer #1

Open nahn20 opened 1 year ago

nahn20 commented 1 year ago

Love the plugin, but have been having issues verifying any requests with fragments. I'm using AppSync and am handling the validation within a Lambda authorizer. Given how annoying AppSync is, there's a good chance this is an issue specific to using the event.requestContext.queryString parameter provided. Here's an example of how we're using it:

        const stableQuery = printExecutableGraphQLDocument(parse(queryString));
        const expectedHash = createHmac("sha256", gqlSecret)
            .update(stableQuery)
            .digest("hex");
        console.log(expectedHash, hash);

And here's an examples of outputs to demonstrate that it works correctly with no fragments.

INFO    mutation ClientUpdate($input: MutationClientUpdateInput!) { clientUpdate(input: $input) }
INFO    2b6d3034ce59d737df0024ac903c9f02042bf86f341a289f97c4f4962f8658a2 2b6d3034ce59d737df0024ac903c9f02042bf86f341a289f97c4f4962f8658a2

And an example in which it breaks with a fragment.

INFO    fragment UserFragment on User { __typename colorTheme firstName lastName profilePicture { __typename blurHash url } profilePictureBlurHash relationshipType userId } query GetClientProfile { getClientProfile { __typename birthdate numFriends relationshipType userType ...UserFragment } }
INFO    ca7205cc9e733197724e2d0a35d68df73a1cfcfbadeb899be84b6b3de9d2f2c2 f842207215a93954b6473054cb1aa4fd3438e731946d4cddd84463ca9df26839
ilijaNL commented 1 year ago

Hey, thanks for using this plugin. I honestly never used appsync before so I don't have the full context what happens by appsync.

Do you include typename in all your client queries? The printExecutableGraphQLDocument(parse(queryString)) should ensure same ordering. However perhaps appsyncs adds additional fields to the queries? (`typename`?)

nahn20 commented 1 year ago

Good catch!

I filtered out all the __typenames and now operations with selections work correctly. Unfortunately, did not solve the fragment issue. Is there any way I can easily debug the plugin to see the exact stable query string it's using?

ilijaNL commented 1 year ago

Good catch!

I filtered out all the __typenames and now operations with selections work correctly. Unfortunately, did not solve the fragment issue. Is there any way I can easily debug the plugin to see the exact stable query string it's using?

Yes it is kinda simple plugin. You can put console.log in your node_modules on this line https://github.com/ilijaNL/graphql-codegen-signed-operation/blob/a958ffefc07e15025d646d37b6eef9255773a4eb/src/plugin.ts#L123

And then run gen.

Perhaps for more context, could you share your codegen configuration?

nahn20 commented 1 year ago

Great thank you so much! This helped me figure out the issue. For some reason, AppSync flips the order of the Query and the Fragments. I now have consistent hashes by removing __typename on the server side and swapping this line of code in plugin.ts.

https://github.com/ilijaNL/graphql-codegen-signed-operation/blob/a958ffefc07e15025d646d37b6eef9255773a4eb/src/plugin.ts#L123 to const doc = parse([operation, ...requiredFragmentDefinitions].map(print).join('\n'));

Do you think this optionality is worth including in the plugin config? If so, I can make a pull request to add it.

ilijaNL commented 1 year ago

Good to know you figured it out! Sure you can make a pr. Another good pr would be to addTypename option which automatically adds __typename to all entities but this requires using the ast visitor