amplify-js: v6 - ID Token as Authorization header not working with DataStore/App Sync any more (was working with v5, solution proposed)
Before opening, please confirm:
- I have searched for duplicate or closed issues and discussions.
- I have read the guide for submitting bug reports.
- I have done my best to include a minimal, self-contained set of instructions for consistently reproducing the issue.
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,queriesandmutations - 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.tsnode_modules/@aws-amplify/api-graphql/dist/esm/Providers/AWSAppSyncRealTimeProvider/index.mjsnode_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
_awsAuthTokenHeaderinAWSAppSyncRealTimeProvider. There is already a propertygraphql_headersin TypeAWSAppSyncRealTimeAuthInputbut I think it is not correctly passed down all the way. There also is another variableadditionalCustomHeaders, I think this is the place where the OptionAPI: {}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
About this issue
- Original URL
- State: closed
- Created 7 months ago
- Reactions: 2
- Comments: 29 (11 by maintainers)
Commits related to this issue
- fix(data): fix library configuration options headers for subscriptions (#12590) (#12659) — committed to aws-amplify/amplify-js by david-mcafee 7 months ago
@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.
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 }; } } });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.
Hi @david-mcafee , sure I tried with the unstable version today and it works fine with subscriptions in my case too.
@david-mcafee thx for your infos -
unfortunately the fix seems not to be deployed with the current unstable?yarn add aws-amplify@unstableresults 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
@hanna-becker wait, there are different things getting mixed up.
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.
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) }, });@OperationalFallacy - can you elaborate more on your use case - ideally with code snippets, if at all possible? Are you saying that headers passed to
generateClientare not being included in queries?Additionally, this change has now been officially released with the latest version of Amplify.
@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.
@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!