I'm using AWS Cognito for authentication, and I'm really confused about how to set it up so AppSync auth waits for Cognito authorization. I have this:
const client = new AWSAppSyncClient(
{
url: process.env.APPSYNC_API_URL,
region: process.env.AWS_REGION,
auth: {
type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS,
jwtToken: () => store.state.auth.user.idToken,
},
},
{
defaultOptions: {
watchQuery: {
fetchPolicy: 'cache-and-network',
},
},
}
);
This works in most cases, but sometimes there's a race condition when the AppSync client is ready but the Vuex store doesn't have the token just yet. Any advice?
Hi,
You can provide an async function that returns a promise containing the token. Here is how you would do it using the Auth module from Amplify:
const client = new AWSAppSyncClient(
{
url: process.env.APPSYNC_API_URL,
region: process.env.AWS_REGION,
auth: {
type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS,
jwtToken: async () => (await Auth.currentSession()).getIdToken().getJwtToken(),
},
},
{
defaultOptions: {
watchQuery: {
fetchPolicy: 'cache-and-network',
},
},
}
);
Hope this helps :)
Ah yes.. right. I guess it makes no sense for me to fetch that from the Vuex store.
Here's the next issue: when Amplify refreshes the user's tokens, how will AppSync pick up on that?
@ffxsam https://github.com/awslabs/aws-mobile-appsync-sdk-js/issues/49 might be helpful
I'm not sure how that helps. Amplify supposedly auto refreshes the tokens for you. How can I know when that happens? How do I update the JWT token in AppSync?
Hey @ffxsam
Ah yes.. right. I guess it makes no sense for me to fetch that from the Vuex store.
Right, things will be easier for you if you read the token using amplify
Here's the next issue: when Amplify refreshes the user's tokens, how will AppSync pick up on that?
For every single request, the AppSync client will await for the promise you return in
jwtToken: async () => (await Auth.currentSession()).getIdToken().getJwtToken()
That jwtToken function will be executed once per request and the token will be always fresh (Amplify internally handles the refresh for you)
Thanks, Manuel!
I might suggest adding promise resolver function in case of error. This will prevent anything from being printed to the console.log.
jwtToken: async () => (await Auth.currentSession()
.then(data => {
return data
})
.catch(err => {
return err
})).getIdToken().getJwtToken(),
After a LONG time trying to figure out where a random error that appeared and crashed our app was, I did this as per your suggestion (thanks @menkveldj):
const client = new AWSAppSyncClient({
url: aws_config.aws_appsync_graphqlEndpoint,
region: aws_config.aws_appsync_region,
auth: {
type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS,
// type: AUTH_TYPE.API_KEY,
// apiKey: aws_config.aws_appsync_apiKey
jwtToken: async () => (await Auth.currentSession()
.then(data => {
return data
})
.catch(err => {
console.log('AWS sux my arse because:',err);
return err
})).getIdToken().getJwtToken()
}
})
However, this doesn't fully solve the problem.
Now I'm getting:
bundle.js:20121 Uncaught (in promise) TypeError: (intermediate value).getIdToken is not a function. I'm not sure how to handing the error case correctly. Thank you for your help.
AWS: Please consider making your product actually work / documenting it adequately to be useable. Reading the many postings on this technology, it's clear that many people have spent many days (like we have) trying to get the very most basic of all functionality (authentication to be able to use it at all) to work using AppSync. We certainly wish that we had never used it at all.
@cdcv You didn't have to dig too far to get the right answer:
https://aws-amplify.github.io/docs/js/api#cognito-user-pools-auth
import Amplify, { Auth } from 'aws-amplify';
import awsconfig from './aws-exports';
Amplify.configure(awsconfig);
const client = new AWSAppSyncClient({
url: awsconfig.aws_appsync_graphqlEndpoint,
region: awsconfig.aws_appsync_region,
auth: {
type: AUTH_TYPE.AMAZON_COGNITO_USER_POOLS,
jwtToken: async () => (await Auth.currentSession()).getIdToken().getJwtToken(),
},
});
It's documented. Their code is a bit different from yours, so I'd try that instead.
Yes @ffxsam that's the code that we started with, which caused all the problems, is directly out of their documentation, and does not work / causes the app to crash because it does not contain adequate error checking and it throws errors.
Most helpful comment
Hi,
You can provide an async function that returns a promise containing the token. Here is how you would do it using the Auth module from Amplify:
Hope this helps :)