1

I'm looking for recommendations on how to approach a next.js front end that uses Apollo and GraphQL to access a PostgreSQL database. I figured it made sense to separate the front and back end, but I'm realizing there are tradeoffs. Next.js and NextAuth.js seem designed to work well when using the Next.js API functionality.

A few requirements:

  1. Data needs to be restricted based on the user (public, internal, admin).
  2. Using Google OAuth for signing in

With this in mind, NextAuth.js gets more complicated if you want the back end to be aware of the user's access rights.

However, if my apollo/graphql back end is independent there are definite benefits like:

  1. I can swap out the front end if ever needed so there's some flexibility
  2. Code and dependencies may be simpler than a combined front/back end

My current challenge is that I've got NextAuth.js working within the Next.js app, but I haven't figured out how to control data access. The best idea I've got so far is some sort of token management that mixes NextAuth.js and my back end. That doesn't seem to be the way NextAuth.js is designed though so I'm rethinking the whole architecture and looking for suggestions.

Thanks!

I found a very brief discussion of a similar question here, but I'd love to hear how others would approach this. How to forward user sessions in Next.js + Graphql decoupled architecture?

noynek
  • 23
  • 5
  • I'm going to try and add an answer, but are you using Google OAuth as in a generic social login or as in an Organizational login? I'm not actually sure it makes a difference. – Ben Oct 17 '21 at 00:01
  • 1
    Thanks, @Ben. Most users will be part of the google organization, but not all so it's gotta be flexible enough to support both. I'm reviewing your full post and will get back after I can explore these ideas. Thank you very much! – noynek Oct 17 '21 at 01:28

1 Answers1

0

I'm going to do my best to give a fairly generic answer, using a JWT for Authorization, but I'm going to have to make some assumptions since I'm not super familiar with Google OAuth & related Google system.

First, and most importantly, it's important to clarify the difference between Authentication, or "who you are" and Authorization, or "what you can do."

The best idea I've got so far is some sort of token management that mixes NextAuth.js and my back end. That doesn't seem to be the way NextAuth.js is designed though so I'm rethinking the whole architecture and looking for suggestions.

NextAuth is an Authentication library, and doesn't support external validation of the NextAuth-created JWTs, so you're right to not want to mix NextAuth with your backend. When someone logs in NextAuth creates a NextAuth-specific JWT (an ID Token) that will be passed between the Client and the Next Server. It tells you who the user is, and proves that they've logged in. Unless you're using database sessions, which I haven't used so can't speak to.

Extra work is required to implement Authorization so that you have a JWT that also describes what access rights the user has, that you can pass to your backend.

Ideally you will be able to leverage Google OAuth for this, and assuming that is the case, this is what I would do:

For the architecture

  • I'm not very familiar with GraphQL/Apollo, but separation there seems fine. Important to note, though, that not separating is also probably fine. Any approach will have tradeoffs, so you'll have to evaluate what works best for your situation.
  • Whenever you make a call to the backend, you pass your JWT with the call as an Authorization header, in the form of Bearer <token>.
  • On the backend, then, you validate the token with each incoming call, and allow the call to proceed (or not) as appropriate.

This is the relevant info I found in the Apollo docs.

For the token

In your NextAuth provider configuration, in the jwt callback you can add information to the NextAuth JWT.

Ideally, your Google OAuth also provides you a JWT (an Access Token). This should be something that should be relatively easy to validate on the backend, and it is what you'd want to use for Authorization.

You can store this Google OAuth JWT (access token) within the NextAuth JWT (id token) when the user first logs in, and then retrieve it on the Next.js server before you make your calls to the GraphQL backend. That would look something like this:

// [...nextauth].js
const options = {
  // ... other configuration
  callbacks: {
    jwt: async (token, user, account, profile, isNewUser) => {
      const isSignIn = !!user

      if (isSignIn) {
        token.b2c = {
          accessToken: account.accessToken,
          refreshToken: account.refreshToken,
          iat: profile.iat,
          exp: profile.exp,
        }
      }

      return Promise.resolve(token)

    }
  }
}

This is a simplified example from the configuration I use. My config is for Azure AD B2C but it's the same general flow you're looking for. You can see my full config here which shows some additional code I use to handle refreshing the access token as needed.

If you don't have something usable from the Google OAuth flow, this gets more complicated and you'd have to build something custom.

Ben
  • 5,079
  • 2
  • 20
  • 26
  • Thanks @Ben, I made some progress translating this into the Google provider format. However, I'm currently stuck trying to send the token to my back end. With Apollo-Client I have the ability to set headers, but I can't figure out how to access the JWT token. https://www.apollographql.com/docs/react/networking/authentication/#header After getting stuck with that, I looked into an Apollo feature where you can send the credentials cookie, but I'm hoping I can figure out how to send the token header. https://www.apollographql.com/docs/react/networking/authentication/#cookie – noynek Oct 18 '21 at 17:00
  • I'm starting to wonder about/explore combining the back end with the front end. It seems like Next.js is designed for this, especially looking at Vercel. This would make auth easier and it would make shared code easier. At some point, it might feel like a monolithic project, but for mine, maybe it's the right approach. – noynek Oct 18 '21 at 19:08
  • Not sure on the apollo server auth header/cookie part :/ IMO combining is probably fine. There are always tradeoffs, and that simplicity may very well be the better option for your case - I"ll add a note to that effect in my answer, too. – Ben Oct 18 '21 at 19:44