apollo icon indicating copy to clipboard operation
apollo copied to clipboard

Use Apollo Nuxt Module with AWS Amplify (appsync) API

Open Billybobbonnet opened this issue 5 years ago • 7 comments

What problem does this feature solve?

I tried to stick with this module when working with a GraphQL AWS API. I couldn't configure how to attach to the request headers the requested API key.

When "edit and resend" the request to add ''x-api-key" as key with the related key as value, it works. See https://stackoverflow.com/q/60816883/3793161

What does the proposed changes look like?

If it is already possible, it's a feature request for the readme. If not, it does not look like a big leap to allow the addition of custom headers for cases like this.

This feature request is available on Nuxt community (#c301)

Billybobbonnet avatar Mar 24 '20 09:03 Billybobbonnet

I'll show some support for this too. I'm trying to get Apollo to talk to my Rails GraphQL backend, but I'm using Devise Token Auth which requires setting specific headers for authentication:

  • client - unique string to identify this client
  • access-token - the token, expires every 2 weeks

It looks like the Apollo module is setup for Basic/Bearer authentication, so I presume it can't be too tricky to allow us to set custom headers.

developius avatar Apr 09 '20 10:04 developius

I figured out a solution to my problem of dynamically setting headers.

In nuxt.config.js you can use clientConfigs to provide your own file, rather than a static options object. That file can export a function that accepts a context argument, where you can retrieve the token and append it to the headers for the apollo request.

// nuxt.config.js

export default {
  apollo: {
    clientConfigs: {
      default: '~/apollo/default-client.js'
    }
  },
}
// apollo/default-client.js

export default function(context) {
  const token = context.app.$cookies.get("apollo-token");
  return {
    httpEndpoint: `http://api.com/graphql`,
    httpLinkOptions: {
      headers: {
        "access-token": token.accessToken,
        client: token.client,
        uid: token.uid,
        expiry: token.expiry
      }
    }
  }
}

Edit: this doesn't seem to work client-side without fully reloading the page 😢

developius avatar Apr 10 '20 09:04 developius

@Billybobbonnet Here's an example from one of my codebases of how to achieve normal connection (for mutations and queries):

// nuxt.config.js

export default {
  apollo: {
    clientConfigs: {
      default: {
        httpEndpoint: `https://${process.env.VUE_APP_WS_GATEWAY_ENDPOINT || 'localhost:4030'}/graphql`,
        httpLinkOptions: {
          headers: {
            'x-api-key': process.env.VUE_APP_WS_API_KEY || 'YOUR_API_KEY',
          },
        },
      },
    }
  },
}

there is a caveat unfortunately, I just couldn't make the subscriptions work, I tried a few strategies in order to have the headers set on the websocket link, but none seem to do it. I think the fault lies with the vue-apollo package.

Here is what I tried:

  1. Ideally this would be awesome to have working:
// nuxt.config.js

export default {
  apollo: {
    clientConfigs: {
      default: {
        httpEndpoint: `https://${process.env.VUE_APP_WS_GATEWAY_ENDPOINT || ''}`,
        wsEndpoint: `wss://${process.env.VUE_APP_WS_GATEWAY_ENDPOINT || ''}`,
        websocketsOnly: true,
        httpLinkOptions: {
          headers: {
            'x-api-key': process.env.VUE_APP_WS_API_KEY || '',
          },
        },
        wsLinkOptions: {
          headers: {
            'x-api-key': process.env.VUE_APP_WS_API_KEY || '',
          },
        },
     }
    }
  },
}

Even more so by dropping the whole http part.

  1. I've tried to set a link instead of the settings above
// nuxt.config.js

export default {
  apollo: {
    clientConfigs: {
      default: {
        link: '~/apollo/websocket',
        wsEndpoint: `wss://${process.env.VUE_APP_WS_GATEWAY_ENDPOINT || ''}`,
        websocketsOnly: true,
      }
    }
  }
}

// apollo/websocket.ts file got the content from https://vue-apollo.netlify.app/guide/apollo/subscriptions.html#setup .

  1. As per the hasura blog https://hasura.io/learn/graphql/vue/subscriptions/1-subscription/
// nuxt.config.js

export default {
  apollo: {
    clientConfigs: {
      default: {
        link: '~/apollo/websocket',
        wsEndpoint: `wss://${process.env.VUE_APP_WS_GATEWAY_ENDPOINT || ''}`,
        websocketsOnly: true,
      }
    }
  }
}
// apollo/websocket.ts file

const link = new WebSocketLink({
   uri:`wss://${process.env.VUE_APP_WS_GATEWAY_ENDPOINT || ''}`,
   options: {
     reconnect: true,
     timeout: 30000,
     connectionParams: () => {
       return { headers: {
          'x-api-key': process.env.VUE_APP_WS_API_KEY || '',
        } };
     },
   }
 });

decebal avatar Apr 24 '20 00:04 decebal

Hi Team, I am also interested in being able to setup the module with AppSync and more specifically with the COGNITO_USER_POOLS auth type. Currently @decebal workaround works great for the API_KEY auth type but I am unable to find a way to send the JWT tokens as part of the Authorization header. Cheers

Stf-F avatar Mar 05 '21 01:03 Stf-F

@Stf-F did u find a solution?

podlebar avatar Nov 06 '21 20:11 podlebar

@Stf-F @podlebar I know this has been a while since your original comment but have you found a way to make it work with Cognito user pools?

What I'm not sure about is how to dynamically set the Authorization header for my AppSync requests.

imduchy avatar Dec 03 '23 13:12 imduchy

@imduchy , for COGNITO_USER_POOLS, the authorization header is a bit tricky (as said on here, where it worked after they removed Bearer from the header content). For me, it started working with this configuration for queries and mutations (on version v5):

nuxt.config.js:

apollo: {
    clients: {
      default: {
        httpEndpoint: 'https://<your_API_ID>.appsync-api.<your-aws-region>.amazonaws.com/graphql',
        wsEndpoint: 'wss://<your_API_ID>.appsync-realtime-api.<your-aws-region>.amazonaws.com/graphql',
        tokenName: 'apollo-token',
        tokenStorage: 'localStorage',
        websocketsOnly: false,
        authType: 'Bearer'
      },
    },
  },

On my store/userStore.ts (using pinia) I set the token for Apollo:

async login(username) {
      // ...
      const { onLogin } = useApollo();
      onLogin(this.token);
}

async logout() {
      // ....
      const { onLogout } = useApollo();
      onLogout();
}

And after that, you just do normal queries in your pages using useAsyncQuery(). If that doesn't work for you, you can try setting authType: null and that way the header won't contain Bearer . Also, testing with the app Postman was quite useful.

Note: I'm still working on subscriptions, so this configuration probably won't work for that. Also, to obtain the token I'm using the package 'amazon-cognito-identity-js'

AdrianVispalia avatar Mar 01 '24 15:03 AdrianVispalia