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

Use multi-auth with Apollo client #562

Open
mdegrees opened this issue May 13, 2020 · 4 comments
Open

Use multi-auth with Apollo client #562

mdegrees opened this issue May 13, 2020 · 4 comments
Labels
question Ask us a question

Comments

@mdegrees
Copy link

mdegrees commented May 13, 2020

When using Apollo client with Appsync, there seems to be no example showing the multi-auth scenario. On my schema I'm using @aws_api_key @aws_cognito_user_pools on multiples queries as in my use case some data is accessible to guests as well as to users.

What is the current behavior?
Currently you can either use API key or Cognito Pool as demonstrated here:
https://github.com/awslabs/aws-mobile-appsync-sdk-js#using-authorization-and-subscription-links-with-apollo-client-no-offline-support

What I expected
Providing both the api Key and Jwt Token with, AppSync picks the appropriate

**What I have tried **
I tried the bellow hack but it seems too cumbersome + subscriptions do not work.

import { createAuthLink } from "aws-appsync-auth-link";
import { SubscriptionHandshakeLink } from "aws-appsync-subscription-link/lib/subscription-handshake-link";
import { NonTerminatingHttpLink } from "aws-appsync-subscription-link/lib/non-terminating-http-link";
import { getMainDefinition } from "apollo-utilities";
import { ApolloLink } from "apollo-link";
import { HttpLink } from "apollo-link-http";
import ApolloClient from "apollo-client";
import { InMemoryCache } from "apollo-cache-inmemory";
import fetch from "isomorphic-unfetch";
import { setContext } from "apollo-link-context";
import config from "../../src/aws-exports";
import Amplify from "@aws-amplify/core";
import Auth from "@aws-amplify/auth";

Amplify.configure(config);

const url = config.aws_appsync_graphqlEndpoint;

const httpLink = new HttpLink({ uri: url, fetch });

const apolloAuthLink = setContext(async (_, { headers }) => {
  try {
    const session = await Auth.currentSession();
    return {
      headers: {
        ...headers,
        authorization: session.getIdToken().getJwtToken(),
      },
    };
  } catch (e) {
    return {
      headers: {
        ...headers,
        "X-Api-Key": config.aws_appsync_apiKey,
      },
    };
  }
});

const wsLink = ApolloLink.from([
  new NonTerminatingHttpLink("subsInfo", { uri: url }, true),
  new SubscriptionHandshakeLink("subsInfo"),
]);

let link;

if (process.browser) {
  link = ApolloLink.from([
    apolloAuthLink,
    ApolloLink.split(
      (operation) => {
        const { query } = operation;
        const definition = getMainDefinition(query);
        return definition.kind === "OperationDefinition" && definition.operation === "subscription";
      },
      wsLink,
      httpLink
    ),
  ]);
} else {
  link = ApolloLink.from([apolloAuthLink, httpLink]);
}

export default function createApolloClient(initialState, ctx) {
  // The `ctx` (NextPageContext) will only be present on the server.
  // use it to extract auth headers (ctx.req) or similar.
  return new ApolloClient({
    ssrMode: Boolean(ctx),
    link,
    cache: new InMemoryCache().restore(initialState),
  });
}

Thank you

@boredcode
Copy link

I'm using a similar hack except it's a little more cumbersome cos the fallback auth scheme I'm using is @aws_iam and not @ aws_api_key key which requires sigv4 signed headers.

@dtelaroli
Copy link

+1

@sammartinez sammartinez added the question Ask us a question label Jun 16, 2020
@anasqadrei
Copy link

I used ApolloLink.split() to decide which link to use

import { ApolloClient, ApolloLink, HttpLink } from '@apollo/client'
import { createAuthLink } from 'aws-appsync-auth-link'

let accessToken

// a function to be called when user login/out or when access token expires
export const setAccessToken = (token) => {
  accessToken = token
}

function createApolloClient() {
  // API key link
  const apiAuthLink = createAuthLink({
    auth: {
      type: 'API_KEY',
      apiKey: 'ABC123...',
    },
  })

  // OpenID Connect link
  const oidcAuthLink = createAuthLink({
    auth: {
      type: 'OPENID_CONNECT',
      jwtToken: async () => accessToken,
    },
  })
  
  // decide which the proper link from above to use (directional link)
  const awsLink = ApolloLink.split((operation) => {
    // use your own conditions here to decide which link to use. e.g. Auth.currentSession()
    return (operation.operationName === `getUserDetails` || operation.variables.id === 1)
  }, oidcAuthLink, apiAuthLink)

  // http link (the terminating link in the chain)
  const httpLink = new HttpLink({
    uri: 'https://xxx.appsync.aws.com/graphql',
  })

  // create ApolloClient with AWS links and cache
  return new ApolloClient({
    link: ApolloLink.from([ awsLink, httpLink ]),
    cache: new InMemoryCache(),
  })
}

@tobiasriemenschneider
Copy link

I'm using a similar hack except it's a little more cumbersome cos the fallback auth scheme I'm using is @aws_iam and not @ aws_api_key key which requires sigv4 signed headers.

Hi @boredcode,
could you paste some code?
I think I'll need to go for something similar..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Ask us a question
Projects
None yet
Development

No branches or pull requests

6 participants