If your training data points you toward server components, server actions, edge middleware, or any next-auth API — those don't apply here. There is exactly one runtime: the browser.
Everything auth- and GraphQL-related lives in src/lib/matthews-auth-graphql/. The package exposes one import path:
@/lib/matthews-auth-graphql—MatthewsAuthGraphqlProvider,RequireAuth,LoginCallback,useAuth(re-exported fromreact-oidc-context).
When adding a page or component under src/pages/** or src/components/**, trust the wrapper:
- Do not create new
ApolloClientinstances. - Do not wrap any tree in another
<AuthProvider>— the umbrella insrc/App.tsxalready does it. - Do not implement token-refresh, 401 retry, or session polling — they're already handled inside the package.
- Use
useQuery/useMutation/useSuspenseQueryfrom@apollo/client/react. The provider above you has wired them up. - Use
useAuthfrom@/lib/matthews-auth-graphqlfor session metadata (the user'sprofile.name,profile.email,error); never to pull the access token for a hand-rolledfetch.
Wrap a route element in <RequireAuth>:
<Route element={<RequireAuth />}>
<Route path="/" element={<Index />} />
</Route>RequireAuth calls signinRedirect() for unauthenticated users (sending them straight to Okta's hosted sign-in page) and renders nothing while the OIDC session is hydrating. There is no /login page we own — the user goes from the protected route straight to Okta and back.
If something you need isn't covered by the package, surface the gap (ask the user, or extend the package deliberately). Don't bypass the wrapper with ad-hoc code.
The four patterns below are what an agent reaches for by reflex when they skip the helpers above. Three of the four fail silently — tests pass, TypeScript is quiet, runtime looks fine — until a refresh edge case manifests in production. Treat each as a bug.
-
new ApolloClient(...)in a component. Bypasses theauthLink → refreshLink → httpLinkchain entirely. Token refresh silently no-ops; the component sees 401s it can't explain. UseuseQuery/useMutation/useSuspenseQueryfrom@apollo/client/react. -
A second
<AuthProvider>wrapping a subtree.react-oidc-contextwon't crash, but the inner provider opens a separate session lifecycle and the two will fight over storage keys. The umbrella inApp.tsxalready installs one. -
Hand-rolled refresh on top of
useAuth(). Conflicts withrefreshLink's single-retry guarantee and withoidc-client-ts's built-in serialization of silent renews. If you think you need this, the answer is no — file a bug against the package instead. -
Raw
fetch(GRAPHQL_URL, { headers: { Authorization:Bearer ${user.access_token}}}). Works once, then breaks when the access token expires — norefreshLink, no retry. Agents reach for this when writing a non-Apollo HTTP call to the GraphQL API; don't. For a truly non-GraphQL authenticated HTTP call to some other service, stop and ask — nofetchWithAuthhelper exists yet and the correct abstraction depends on which service.
If you're about to write any of the four, the root cause is almost always "I didn't know matthews-auth-graphql handles that." Re-read the sections above.