I’ve managed to get anonymous user authentication working from my Next.js app to MongoDB GraphQL API using Apollo Client. However, I’m not quite sure if this is a recommended approach or if there are any issues to be aware of using this method. I’d also appreciate any feedback as to how to improve things if anyone can suggest anything.
First of all I create a GraphQLProvider
component in /components
directory which wraps the Apollo Provider. It retrieves a valid access token on every request and adds it to the headers:
import * as Realm from "realm-web";
import {
ApolloClient,
ApolloProvider,
HttpLink,
InMemoryCache
} from "@apollo/client";
// import { useApp } from "./useApp";
// Connect to MongoDB Realm app
const app = new Realm.App(process.env.NEXT_PUBLIC_APP_ID);
// Gets a valid Realm user access token to authenticate requests
async function getValidAccessToken() {
// Guarantee that there's a logged in user with a valid access token
if (!app.currentUser) {
// If no user is logged in, log in an anonymous user. The logged in user will have a valid
// access token.
await app.logIn(Realm.Credentials.anonymous());
} else {
// An already logged in user's access token might be stale. Tokens must be refreshed after
// 30 minutes. To guarantee that the token is valid, we refresh the user's access token.
await app.currentUser.refreshAccessToken();
}
// console.log(app.currentUser.accessToken);
return app.currentUser.accessToken;
}
// Add GraphQL client provider
function GraphQLProvider({ children }) {
// const app = useApp();
console.log()
const client = new ApolloClient({
link: new HttpLink({
uri: process.env.NEXT_PUBLIC_GRAPHQL_API_ENDPOINT,
// Get the latest access token on each request
fetch: async (uri, options) => {
const accessToken = await getValidAccessToken();
options.headers.Authorization = `Bearer ${accessToken}`;
return fetch(uri, options);
},
}),
cache: new InMemoryCache(),
});
return (
<ApolloProvider client={client}>
{children}
</ApolloProvider>
);
}
export default GraphQLProvider;
Then in pages/_app.js
I wrap my app with the new provider (which includes the Apollo Provider):
import GraphQLProvider from '@/components/GraphQLProvider';
export default function App({ Component, pageProps }) {
return (
// Wraps Apollo Provider and provides authentication.
<GraphQLProvider>
<Component {...pageProps} />
</GraphQLProvider>
);
}
I then just make the GraphQL query in any components where I need to make an external request for data.
It should be noted that at this point I’m only using cient-side rendering and I don’t have any user accounts on my site and I have enabled anonymous authentication in App Services. It’s purely just to be able to make the connection to MongoDB Atlas App Services and retrieve generic data.
Thanks for any feedback.