改善
Kaizen  · Today I Learned by Ville Säävuori

Integrating MongoDB Realm Auth With Nuxt Auth

I’ve been playing with MongoDB Realm lately and my last exercise was to integrate the Realm Auth with Nuxt Auth. They both implement a standard Oauth2 workflow but turns out making them work together wasn’t as straightforward as one might think.

MongoDB Realm And [Google] OAuth 2.0

From the documentation:

The Google authentication provider allows users to log in with their existing Google account through Google Sign-In. When a user logs in, Google provides MongoDB Realm with an OAuth 2.0 access token for the user. Realm uses the token to identify the user and access approved data from Google APIs on their behalf.

In order to unite the Nuxt Auth module and Realm Auth module, I needed to first add Google login to the Nuxt project, then intercept the oauth login flow, and finally inject the Realm login.

Both realm-web and @nuxtjs/auth-next packages are relatively young and the documentation is unfortunately on par with the rest of the JavaScript ecosystem. Both are also written in TypeScript and missing some exports so the task was mostly studying the code.

Adding Google Login to a Nuxt App

Nuxt Auth ships with a built-in Google provider so this part was very easy, but I was surprised of the lack of proper documentation or examples. Assuming you have already configured the Google Oauth 2.0 Client API, here’s a working configuration for nuxt.config.js auth section:

strategies: {
    google: {
    clientId: process.env.GOOGLE_CLIENT_ID,
    redirectUri: process.env.LOGIN_REDIRECT_URI,
    scope: ['profile', 'email'],
    responseType: 'token id_token',
    codeChallengeMethod: '',
    },
},

To log in, just call this.$auth.loginWith('google'), that’s all there’s to it. See the official documentation for more details.

Implementing A Custom Nuxt Auth Oauth2 Scheme

After spending one whole day doing trial and error with all kinds of different variations and methods of using realm-web together with the built-in Google provider, writing a custom scheme for Nuxt Auth seemed to be the least bad option.

The greatest challenge here was the fact that some of the needed helper functions weren’t exported by the package so I needed to copy them in the project. I created a ticket for this and also added the whole scheme code as an example in the comments. Save the scheme (full code in linked issue) in ~/schemes/mongoAuth.ts and copy the needed utils from the repo into ~/schemes/utils.ts. (Didn’t say it was pretty!)

Another catch was the fact that for unknown reason imports from the @nuxtjs/auth-next package need to be written as import foo from '~auth/runtime' and for TypeScript to understand the magic, you need to have a shim.d.ts that resolves the exports.

So, in ~/shim.d.ts add the following:

declare module '~auth/runtime' {
  export { Oauth2Scheme } from '@nuxtjs/auth-next'
}

Finally, modify the Nuxt Auth config to include the custom strategy (that now needs explicit endpoint URLs as we want to use Google but aren’t using the built-in provider):

strategies: {
    modifiedOauth: {
    scheme: '~/schemes/mongoAuth',
    clientId: process.env.GOOGLE_CLIENT_ID,
    redirectUri: process.env.LOGIN_REDIRECT_URI,
    scope: ['profile', 'email'],
    responseType: 'token id_token',
    codeChallengeMethod: '',
    endpoints: {
        authorization: 'https://accounts.google.com/o/oauth2/auth',
        userInfo: 'https://www.googleapis.com/oauth2/v3/userinfo',
    },
    },
},

Now you have a fully working Google authentication in your Nuxt app which is also integrated to Realm!

Final Words

Although this setup seems to work fine for now, probably I wouldn’t push anything like this into production on a mission critical site. I wouldn’t consider neither realm-web nor @nuxtjs/auth-next production ready by any stretch of the imagination. On the other hand, if you want an easy way to integrate your Nuxt app with MongoDB Realm, setting this whole workflow up takes less than an hour.

I hope both of these packages get the love and attention they deserve to mature a bit as having these kind of cool tools is really great!