chapter-three / next-drupal

Next.js for Drupal has everything you need to build a next-generation front-end for your Drupal site: SSG, SSR, and ISR, Multi-site, Authentication, Webforms, Search API, I18n and Preview mode (works with JSON:API and GraphQL).
https://next-drupal.org
MIT License
634 stars 176 forks source link

Preview with accessToken from next-auth #611

Open fiasco opened 11 months ago

fiasco commented 11 months ago

Package containing the bug

next-drupal (NPM package)

Describe the bug

I'm trying to use next-auth to authenticate a user against Drupal (using simple_oauth), then to use the acquired accessToken in the DrupalClient to ensure I have the right permissions for access to revisions for preview.

However, I can't seem to get access to the accessToken from inside getStaticProps because it is a build time method, even though it runs serverside at runtime on preview. The only session related data available is in previewData but I'm not able to inject this into using the DrupalClient.preview method.

Setup

pages/api/[...nextauth].js


import NextAuth from "next-auth"

export const authOptions = {
  providers: [
    {
      id: "drupal",
      name: "Drupal CMS",
      type: "oauth",
      authorization: {
        url: process.env.NEXT_PUBLIC_DRUPAL_BASE_URL + '/oauth/authorize',
        params: {
          scope: 'content_editor',
        }
      },
      token: process.env.NEXT_PUBLIC_DRUPAL_BASE_URL + '/oauth/token',
      userinfo: process.env.NEXT_PUBLIC_DRUPAL_BASE_URL + '/oauth/userinfo',
      clientId: process.env.DRUPAL_CLIENT_ID,
      clientSecret: process.env.DRUPAL_CLIENT_SECRET,
      profile(profile) {
        return {
          id: profile.sub,
          name: profile.name,
          email: profile.email,
        }
      }
    }
  ],
  secret: process.env.DRUPAL_PREVIEW_SECRET,
  debug: true,
  cookies: {
    // Allow the sessionToken to be accessible through iframes (CMS preview)
    sessionToken: {
      name: `__Secure-next-auth.session-token`,
      options: {
        httpOnly: true,
        sameSite: 'none',
        path: '/',
        secure: true
      }
    },
  },
  callbacks: {
    async session({ session, token, user }) {
      // Attach the token to the session
      session.token = token
      return session
    },
    async jwt({ token, account, profile }) {
      // Attach the access token
      if (account) {
        token.accessToken = account.access_token
        token.id = profile.id
      }
      return token
    }
  }
}

export default NextAuth(authOptions)

pages/api/preview.ts

import { drupal } from '../../lib/drupal';
import { getServerSession } from "next-auth/next"
import { authOptions } from "./auth/[...nextauth]"
import { NextApiRequest, NextApiResponse } from 'next';

export default async function handler(req:NextApiRequest, res:NextApiResponse) {
  // This ensures a session is present.
  const session = await getServerSession(req, res, authOptions)
  return await drupal.preview(req, res);
}

So far so good. The above authenticates me with Drupal and ensures I am authenticated when attempting to preview. The problem occurs when attempting to render a preview. Calls to useSession or getSession inside of getStaticProps always returns null. I presume this is because this process is happening in a build context that doesn't / shouldn't have access to the session.

The solution would appear to be to set the accessToken in the previewData of the request. However, the way that DrupalClient.preview works, I can't add any additional data to the previewData. This is the bug.

Is it possible to pass in a callback to write additional previewData to the response?

fiasco commented 11 months ago

heh, this seems related - https://github.com/vercel/next.js/discussions/32207#discussioncomment-3458862