简体   繁体   中英

Next.js/Next-Auth/Apollo/GraphQL Setup

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?

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.
  • 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM