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

v6 - ID Token as Authorization header not working with DataStore/App Sync any more (was working with v5, solution proposed) #12590

Closed
3 tasks done
jgo80 opened this issue Nov 20, 2023 · 30 comments
Assignees
Labels
bug Something isn't working GraphQL Related to GraphQL API issues pending-close-response-required A response is required for this issue to remain open, it will be closed within the next 7 days. V6 V6 of Amplify JS

Comments

@jgo80
Copy link

jgo80 commented Nov 20, 2023

Before opening, please confirm:

JavaScript Framework

React Native

Amplify APIs

GraphQL API

Amplify Categories

api

Environment information

# Put output below this line
  System:
    OS: macOS 14.1
    CPU: (10) arm64 Apple M1 Max
    Memory: 1.36 GB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.18.2 - /opt/homebrew/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 9.8.1 - /opt/homebrew/bin/npm
    pnpm: 8.10.5 - /opt/homebrew/bin/pnpm
    Watchman: 2023.11.13.00 - /opt/homebrew/bin/watchman
  Browsers:
    Chrome: 119.0.6045.159
    Safari: 17.1
  npmGlobalPackages:
    corepack: 0.19.0
    npm: 9.8.1

Describe the bug

I have some Custom Claims in my ID Token, generated through a Pre Token Generation Lambda Trigger. I need to pass those to API GraphQL. It was working well in V5 but now does not anymore for Subscriptions in V6. I also have the solution, so please read it at the end of my bug description!

In V5 I was doing it like this:

// V5
import { Amplify } from "aws-amplify";
import config from "./aws-exports";

Amplify.configure({
  ...config,
  API: {
    graphql_headers: async () => ({
      // Replace Access Token by Identity Token
      Authorization: (await Auth.currentSession()).getIdToken().getJwtToken(),
    }),
  },
});

There was no Documentation how to do it in V6, so I figured it out (please also find my request to update the docs aws-amplify/docs#6513 )

So in V6 it is working like this:

// V6
import { Amplify } from "aws-amplify";
import { fetchAuthSession } from "aws-amplify/auth";
import config from "./amplifyconfiguration.json";

Amplify.configure(config, {
  API: {
    GraphQL: {
      headers: async () => ({
        Authorization: (
          await fetchAuthSession()
        ).tokens?.idToken?.toString() as string,
      }),
    },
  },
});

Now here is my point regarding the bug:

  • DataStore does work for sync, queries and mutations
  • It does NOT work for subscriptions!

** Cause for the bug **

  • The customized GraphQL headers set through the Amplify.configure options as shown above are not passed to the AWSAppSyncRealTimeProvider

** Temporary Resolution / Hotfix for the bug **

In order to make it work BOTH for React Native and the Web I had to patch those three files:

  • node_modules/@aws-amplify/api-graphql/src/Providers/AWSAppSyncRealTimeProvider/index.ts
  • node_modules/@aws-amplify/api-graphql/dist/esm/Providers/AWSAppSyncRealTimeProvider/index.mjs
  • node_modules/@aws-amplify/api-graphql/dist/cjs/Providers/AWSAppSyncRealTimeProvider/index.js
	private async _awsAuthTokenHeader({ host }: AWSAppSyncRealTimeAuthInput) {
		const session = await fetchAuthSession();

		return {
			Authorization: session?.tokens?.idToken?.toString(), // <-- Change accessToken for idTolken
			host,
		};
	}

** Change request **

  • Pass the customized GraphQL headers to _awsAuthTokenHeader in AWSAppSyncRealTimeProvider. There is already a property graphql_headers in Type AWSAppSyncRealTimeAuthInput but I think it is not correctly passed down all the way. There also is another variable additionalCustomHeaders, I think this is the place where the Option API: {} is fetched from the Amplify.configure singleton.

I hope my description was understandable. Thanks for implementing this soon!

Expected behavior

Passing ID Token to GraphQL Header should work in V6 for Queries, Mutations AND Subscriptions as it worked in V5.

Reproduction steps

  • Create a GraphQL schema with an Auth rule based on a custom claim
  • Generate custom claim through a Pre Token Generation Lambda Trigger
  • Configure Amplify to use idToken as Authorization header
// V6
import { Amplify } from "aws-amplify";
import { fetchAuthSession } from "aws-amplify/auth";
import config from "./amplifyconfiguration.json";

Amplify.configure(config, {
  API: {
    GraphQL: {
      headers: async () => ({
        Authorization: (
          await fetchAuthSession()
        ).tokens?.idToken?.toString() as string,
      }),
    },
  },
});

Code Snippet

// Put your code below this line.

Log output

// Put your logs below this line


aws-exports.js

No response

Manual configuration

No response

Additional configuration

No response

Mobile Device

No response

Mobile Operating System

No response

Mobile Browser

No response

Mobile Browser Version

No response

Additional information and screenshots

No response

@jgo80 jgo80 added the pending-triage Issue is pending triage label Nov 20, 2023
@jgo80 jgo80 changed the title v6 - ID Token not working with DataStore/App Sync any more (was working with v5) v6 - ID Token as Authorization header not working with DataStore/App Sync any more (was working with v5) Nov 20, 2023
@jgo80 jgo80 changed the title v6 - ID Token as Authorization header not working with DataStore/App Sync any more (was working with v5) v6 - ID Token as Authorization header not working with DataStore/App Sync any more (was working with v5, solution proposed) Nov 20, 2023
@hanna-becker
Copy link

We're facing the same issue in our attempts to migrate out application to v6.

@nadetastic
Copy link
Contributor

Related - aws-amplify/docs#6513

@nadetastic nadetastic added Auth Related to Auth components/category GraphQL Related to GraphQL API issues labels Nov 20, 2023
@jgo80
Copy link
Author

jgo80 commented Nov 20, 2023

@nadetastic thx, I opened both issues and also referenced them 😉 But aws-amplify/docs#6513 only faces the lag of documentation. This issue deals with a bug!

@cwomack cwomack self-assigned this Nov 20, 2023
@nadetastic nadetastic removed the Auth Related to Auth components/category label Nov 20, 2023
@cwomack cwomack added bug Something isn't working and removed pending-triage Issue is pending triage labels Nov 20, 2023
@cwomack
Copy link
Contributor

cwomack commented Nov 20, 2023

@jgo80, thank you for creating this issue. I've marked this as a bug and there's a fix coming soon. I'll update this issue once it's ready and released.

@Sanoodia
Copy link

Sanoodia commented Nov 23, 2023

Im having the same issue my authorization mode of model is custom lambda and Datastore is using authProvider property to add authorization token for graphql call.. here is my code
it was working in v5 but not in v6 after migration

DataStore.configure({ syncPageSize: 1000, maxRecordsToSync: 200000, authProviders: { functionAuthProvider: async () => { console.log("refreshAuthToken",userData.token) const authToken = await refreshAuthToken(); // refreshAuthToken return { token: userData.token }; } }, syncExpressions: [ syncExpression(GlobalLookups, () => { try{ return Predicates.ALL; }catch(error){ console.log(error, userData); } }), syncExpression(CatHerd, () => { try{ if(userType.carrier.includes(userData.company_type)){ return (c) => c.carrier_id.eq(userData.company_id); }else{ return (c) => c.dd_tenant.eq(TENANT#${userData.company_id}); } }catch(error){ console.log(error); } }) ], errorHandler: (error) => { console.log(error) }, });

@imranmunir312
Copy link

imranmunir312 commented Nov 23, 2023

I am trying to configure Datastore with custom Authentication using AWS_LAMBDA but it's constantly showing unauthorized but on the other hand same auth flow is working fine with App Sync. Need Help!

DataStore.configure({ authProviders: { functionAuthProvider: async () => { const authToken = await refreshAuthToken(); return { token: authToken }; } } });

@jgo80
Copy link
Author

jgo80 commented Nov 23, 2023

Custom Authentication is not related to ID Token at all, if you digg down into AWS Amplify DataStore configure, you can see that functionAuthProvider is unrelated to this topic. I'd recommend to open a separate issue.

@OperationalFallacy
Copy link

#12621 same issue I opened here

@david-mcafee david-mcafee self-assigned this Nov 27, 2023
@david-mcafee
Copy link
Member

@jgo80 - We're currently investigating this, but it was unclear to me if you were using DataStore or the GraphQL API (the title mentions DataStore, but the description mentions the GraphQL API). Thank you!

@jgo80
Copy link
Author

jgo80 commented Nov 27, 2023

@david-mcafee the issue is about DataStore, which is based on AppSync, so the answer is both. I just pointed out where the fix is to be inserted, so there should not be many questions.

@david-mcafee
Copy link
Member

Thank you @jgo80! To clarify my question, DataStore and the GraphQL API are two separate library categories that both use AWS AppSync, so I wanted to see which library category you were using. Can you also let us know what your default auth mode is? Thank you!

@jgo80
Copy link
Author

jgo80 commented Nov 28, 2023

@david-mcafee default auth mode is Cognito. Maybe I did not clearly point this out in the repro description, I thought this was clear by mentioning Pre Token Generation Lambda Trigger

Thx for looking into this.

The issue (as described) is that the override is not correctly passed down from Amplify.configure > API > GraphQL > headers to AWSAppSyncRealTimeProvider

Just follow the way back in the code from RealTimeProvider to Configure! (Follow the white rabbit, Neo 😉)

@hanna-becker
Copy link

hanna-becker commented Nov 28, 2023

@jgo80, are you sure this override is still needed for group claims?

import { Amplify } from "aws-amplify";
import { fetchAuthSession } from "aws-amplify/auth";
import config from "./amplifyconfiguration.json";

Amplify.configure(config, {
  API: {
    GraphQL: {
      headers: async () => ({
        Authorization: (
          await fetchAuthSession()
        ).tokens?.idToken?.toString() as string,
      }),
    },
  },
});

For me, the group claims are in the request's idToken even without it. (And for other non-group custom claims, unfortunately the override doesn't work, see my issue).

EDIT: And I just realized, you did not mention group claims, just custom claims. So forget about my question.

@david-mcafee david-mcafee added the V6 V6 of Amplify JS label Nov 28, 2023
@david-mcafee david-mcafee removed their assignment Nov 28, 2023
@jgo80
Copy link
Author

jgo80 commented Nov 29, 2023

@hanna-becker wait, there are different things getting mixed up.

  1. Default Authorization Token is the accessToken, not the idToken. So the accessToken has all default Cognito attributes.
  2. I was not talking about group claims (groups in Amazon Cognito user pools), but I was talking about custom claims I create with a Pre Token Generation Lambda Trigger > Those claims only are contained in the idToken

So my mentioned code is the official way to override/pass the idToken to the Authorization header. However the override was not correctly implemented for subscriptions, that's all. Just a missing link. I just want to avoid confusion and mixing up facts.

@jgo80
Copy link
Author

jgo80 commented Nov 29, 2023

@david-mcafee Talking about DataStore vs. GraphQL API - Both actually use the same library AWSAppSyncRealTimeProvider. I both use DataStore and GraphQL API. I can confirm idToken override works with GraphQL API regarding queries and mutations - however I did not check Subscriptions with GraphQL API. I think the problem is originating from AWSAppSyncRealTimeProvider for both DataStore and GraphQL API.

@david-mcafee
Copy link
Member

david-mcafee commented Nov 30, 2023

@david-mcafee Talking about DataStore vs. GraphQL API - Both actually use the same library AWSAppSyncRealTimeProvider. I both use DataStore and GraphQL API. I can confirm idToken override works with GraphQL API regarding queries and mutations - however I did not check Subscriptions with GraphQL API. I think the problem is originating from AWSAppSyncRealTimeProvider for both DataStore and GraphQL API.

Yep, you're correct that they both use the AWSAppSyncRealTimeProvider (and sounds like you may know already, but DataStore also uses the GraphQL API category). To clarify, I was asking since it was unclear to me which category you were using, and I wanted to make sure I was reproducing your specific use-case! :)

I was able to reproduce the problem, and I'm currently working on the fix + tests. Will update this ticket when that is ready.

@david-mcafee
Copy link
Member

@jgo80 - The fix for this issue has been merged, and is now available via the unstable tag if you would like to validate that this resolves your issue.

This fix will go out with our next release.

@OperationalFallacy
Copy link

OperationalFallacy commented Dec 5, 2023

@david-mcafee I see the subscriptions are working now, ones that collections using

But ones with generateClient() started to fail (on unstable package version).

I see that it is sending headers without idToken information. I had to include token like this to make it work:

   const s = await fetchAuthSession();
    const t = s.tokens?.idToken?.toString();
    const client = generateClient({ authToken: t });

Is it how it should work? Or Amplify.Configure should include by default idToken when configured?

@david-mcafee
Copy link
Member

@david-mcafee I see the subscriptions are working now, ones that collections using

But ones with generateClient() started to fail (on unstable package version).

I see that it is sending headers without idToken information. I had to include token like this to make it work:

   const s = await fetchAuthSession();
    const t = s.tokens?.idToken?.toString();
    const client = generateClient({ authToken: t });

Is it how it should work? Or Amplify.Configure should include by default idToken when configured?

I apologize but I'm not quite sure I understand your use-case. Could you elaborate a bit more on why you are sending headers to both Amplify.configure as well as generateClient?

Unsure if this clarifies things, but whatever is passed to Amplify.configure will always take precedence over headers sent to generateClient as well as individual model operations.

@jgo80
Copy link
Author

jgo80 commented Dec 5, 2023

@david-mcafee thx for your infos - unfortunately the fix seems not to be deployed with the current unstable?

yarn add aws-amplify@unstable results in "aws-amplify": "^6.0.6-unstable.1c5010c.0" which results in "@aws-amplify/api-graphql": "4.0.6-unstable.f2b7a8d.0+f2b7a8d"

Maybe your fix did not make it to the unstable pre-release?

Okay, my bad, I now can confirm it is working with the unstable pre-release @david-mcafee

@OperationalFallacy
Copy link

@jgo80 I think it got into 6.0.6-unstable.e101cea.0+e101cea

@OperationalFallacy
Copy link

Unsure if this clarifies things, but whatever is passed to Amplify.configure will always take precedence over headers sent to generateClient as well as individual model operations.

It does this for sync queries that collections use.

subscriptions and other queries with const client = generateClient() would still have non id token.

@OperationalFallacy
Copy link

Okay, my bad, I now can confirm it is working with the unstable pre-release @david-mcafee

@jgo80 do you use by chance generateClient()? I see queries still get wrong header when using it.

@jgo80
Copy link
Author

jgo80 commented Dec 5, 2023

Okay, my bad, I now can confirm it is working with the unstable pre-release @david-mcafee

@jgo80 do you use by chance generateClient()? I see queries still get wrong header when using it.

No @OperationalFallacy , I'm sorry 🫤

@david-mcafee
Copy link
Member

david-mcafee commented Dec 5, 2023

@OperationalFallacy - can you elaborate more on your use case - ideally with code snippets, if at all possible? Are you saying that headers passed to generateClient are not being included in queries?

Additionally, this change has now been officially released with the latest version of Amplify.

@david-mcafee
Copy link
Member

david-mcafee commented Dec 6, 2023

@ArsSirek - I see that you've closed the DataStore issue linked above as a duplicate of this one - in the ticket, it looks like you're using Amplify version 6.0.5, however, the fix for this issue was released with 6.0.6. Can you try upgrading your Amplify dependency? Thanks!

@ArsSirek
Copy link

ArsSirek commented Dec 7, 2023

Hi @david-mcafee , sure I tried with the unstable version today and it works fine with subscriptions in my case too.

@david-mcafee
Copy link
Member

Glad to hear that, @ArsSirek! And to clarify, there is no need to use unstable any longer, as this fix is now out with the regular release.

@OperationalFallacy - If this is still an issue for you, can you please take a look at my previous comment regarding steps to reproduce your issue? Thank you!

@david-mcafee david-mcafee added the pending-close-response-required A response is required for this issue to remain open, it will be closed within the next 7 days. label Dec 7, 2023
@cwomack
Copy link
Contributor

cwomack commented Dec 11, 2023

With the fix for this issue released in v6.0.6, we'll close this issue. Let us know if there are further problems regarding this topic.

@mattiLeBlanc
Copy link

mattiLeBlanc commented Jun 4, 2024

@chrisbonifacio @jgo80
From the current typing,

image

this is no longer allowed:

Amplify.configure(config, {
  API: {
    GraphQL: {
      headers: async () => ({
        Authorization: (
          await fetchAuthSession()
        ).tokens?.idToken?.toString() as string,
      }),
    },
  },
});

How do I change my Authorization to be idToken then?
This problem is now blocking my upgrade to Amplify 6.

EDIT: I just realised it was a mistake on my end. I need to add the Grahpql headers to the configure function and not as part of the AWS CONFIG credentials. I overlooked that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working GraphQL Related to GraphQL API issues pending-close-response-required A response is required for this issue to remain open, it will be closed within the next 7 days. V6 V6 of Amplify JS
Projects
None yet
Development

No branches or pull requests