0

I am using the following plugin( @axa-fr/react-oidc-context ) in React to enable authentication with AzureAd. Now I need to access the access_token in ApolloClient after the authentication is done. I am not sure how to fetch the access_token in non react component like ApolloClient.

Here is what i am doing.

App.js

import React from "react";
import { HashRouter, Route, Switch } from "react-router-dom";
import { AuthenticationProvider, withOidcSecure } from "@axa-fr/react-oidc-context";
import { IDENTITY_CONFIG } from "./utils/configuration";
// components
import Layout from "./Layout";

export default function App() {
  return (
    <AuthenticationProvider configuration={IDENTITY_CONFIG}>
      <HashRouter>
        <Switch>
          <Route path="/" component={withOidcSecure(Layout)} />
        </Switch>
      </HashRouter>
    </AuthenticationProvider>
  );
}

Layout.js

import React from "react";
import { Route, Switch, withRouter } from "react-router-dom";
import { ApolloProvider } from "@apollo/react-hooks";
import client from "./apollo";

import Dashboard from "./pages/dashboard";

function Layout(props) {
  return (
    <>
      <ApolloProvider client={client}>
        <Switch>
          <Route exact path="/" component={Dashboard} />
        </Switch>
      </ApolloProvider>
    </>
  );
}

export default withRouter(Layout);

apollo.js

import { InMemoryCache } from "apollo-cache-inmemory";
import { ApolloClient } from "apollo-client";
import { ApolloLink, split } from "apollo-link";
import { setContext } from "apollo-link-context";
import { HttpLink } from "apollo-link-http";
import { WebSocketLink } from "apollo-link-ws";
import { getMainDefinition } from "apollo-utilities";

import { useReactOidc } from "@axa-fr/react-oidc-context";

const { oidcUser } = useReactOidc();

console.log(oidcUser.access_token)

const httpUri = process.env.REACT_APP_SERVER_URL
  ? process.env.REACT_APP_SERVER_URL
  : "https://48p1r2roz4.sse.codesandbox.io";
const wsUri = httpUri.replace(
  /^https?/,
  process.env.REACT_APP_ENV === "dev" ? "ws" : "wss"
);

const httpLink = new HttpLink({
  uri: httpUri
});

const wsLink = new WebSocketLink({
  uri: wsUri,
  options: {
    lazy: true,
    reconnect: true
    // connectionParams: () => {
    //   return { headers: { Authorization: getAuthHeader() } };
    // }
  }
});

const authLink = setContext((_, { headers }) => {
  //   const auth = getAuthHeader()

  return {
    headers: {
      ...headers
      //   Authorization: auth,
    }
  };
});

const terminatingLink = split(
  ({ query }) => {
    const { kind, operation } = getMainDefinition(query);
    return kind === "OperationDefinition" && operation === "subscription";
  },
  wsLink,
  authLink.concat(httpLink)
);

const link = ApolloLink.from([terminatingLink]);
const cache = new InMemoryCache();

const client = new ApolloClient({
  link,
  cache
});

export default client;

I am trying to pull the access token in apollo.js file, but it's throwing error where it says I cannot access React Hooks in Non React component.

thotam
  • 643
  • 10
  • 19

2 Answers2

0

Never used this library before, but it looks like it's using a higher order component to pass props to the wrapped component that you're passing into withOidcSecure. You should be able to access whatever data is being provided through the props in your Layout component. Try using console.log(props) inside of it and see what it returns, I'm not sure exactly what data's being passed down.

Chris B.
  • 4,148
  • 1
  • 7
  • 24
0

As the token info is getting stored in sessionStorage after authentication, i was able to pull access_token info from session storage and assigned as Authorization Header to my ApolloClient.

Please let me know if there is a better solution.

Update:

Instead of getting token for session storage, we can use useReactOidc to get the access_token as pass as props to Apollo Client. Please see the updated code.

Layout.js

import React from "react";
import { Route, Switch, withRouter } from "react-router-dom";
import { ApolloProvider } from "@apollo/react-hooks";
import { useReactOidc } from "@axa-fr/react-oidc-context";
import client from "./apollo";

import Dashboard from "./pages/dashboard";

function Layout(props) {
  const { oidcUser } = useReactOidc();

  return (
    <>
      <ApolloProvider client={client(oidcUser.access_token)}>
        <Switch>
          <Route exact path="/" component={Dashboard} />
        </Switch>
      </ApolloProvider>
    </>
  );
}

export default withRouter(Layout);

apollo.js

import { InMemoryCache } from "apollo-cache-inmemory";
import { ApolloClient } from "apollo-client";
import { ApolloLink, split } from "apollo-link";
import { setContext } from "apollo-link-context";
import { HttpLink } from "apollo-link-http";
import { WebSocketLink } from "apollo-link-ws";
import { getMainDefinition } from "apollo-utilities";

const httpUri = process.env.REACT_APP_SERVER_URL
  ? process.env.REACT_APP_SERVER_URL
  : "http://localhost:8080/v1/graphql";
const wsUri = httpUri.replace(
  /^https?/,
  process.env.REACT_APP_ENV === "dev" ? "ws" : "wss"
);

const httpLink = new HttpLink({
  uri: httpUri
});

const wsLink = token =>
  new WebSocketLink({
    uri: wsUri,
    options: {
      lazy: true,
      reconnect: true,
      connectionParams: () => {
        return { headers: { Authorization: `Bearer ${token}` } };
      }
    }
  });

const authLink = token =>
  setContext((_, { headers }) => {
    return {
      headers: {
        ...headers,
        Authorization: `Bearer ${token}`
      }
    };
  });

const terminatingLink = token =>
  split(
    ({ query }) => {
      const { kind, operation } = getMainDefinition(query);
      return kind === "OperationDefinition" && operation === "subscription";
    },
    wsLink(token),
    authLink(token).concat(httpLink)
  );

const link = token => ApolloLink.from([terminatingLink(token)]);
const cache = new InMemoryCache();

const client = token =>
  new ApolloClient({
    link: link(token),
    cache: cache
  });

export default client;
thotam
  • 643
  • 10
  • 19