blitz icon indicating copy to clipboard operation
blitz copied to clipboard

cannot get `context.session.$publicData` with `passportAuth` and app router

Open toofusan opened this issue 11 months ago • 0 comments

What is the problem?

I'm trying to migrate from page to app. Our application uses passport -google-oauth20 to authenticate users. But even though users have signed in, they can't be authenticated by useAuthenticatedBlitzContext, and redirect to login page. It seems that there is no session data in BlitzContext.

Session has been created.(in Client Component, useSession returns session data correctly)

How can I do about this?

Paste all your error logs here:

It seems that there is no error logs in both client and server.

Paste all relevant code snippets here:

app/blitz-client.ts

"use client"

import { AuthClientPlugin } from "@blitzjs/auth"
import { setupBlitzClient } from "@blitzjs/next"
import { BlitzRpcPlugin } from "@blitzjs/rpc"

export const authConfig = {
  cookiePrefix: "my-cookie",
}

export const { withBlitz, BlitzProvider, useSession, useAuthenticatedSession } = setupBlitzClient({
  plugins: [AuthClientPlugin(authConfig), BlitzRpcPlugin({})],
})

/app/blitz-server.ts

import { setupBlitzServer } from "@blitzjs/next"
import { AuthServerPlugin, PrismaStorage } from "@blitzjs/auth"
import { simpleRolesIsAuthorized } from "@blitzjs/auth"
import { BlitzLogger } from "blitz"
import db from "db"
import { authConfig } from "./blitz-client"
import { RpcServerPlugin } from "@blitzjs/rpc"

export const { gSSP, gSP, useAuthenticatedBlitzContext, getBlitzContext, api, invoke } =
  setupBlitzServer({
    plugins: [
      AuthServerPlugin({
        ...authConfig,
        storage: PrismaStorage(db),
        isAuthorized: simpleRolesIsAuthorized,
      }),
      RpcServerPlugin({}),
    ],
    logger: BlitzLogger({}),
  })

/app/layout.tsx

"use client"

import React from "react"

import { BlitzProvider } from "app/blitz-client"
import "./globals.css"

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ja" className="dark scroll-smooth">
      <head>
        <title>Karabina</title>
      </head>

      <body className="dark:bg-black dark:text-gray-850">
        <BlitzProvider>{children}</BlitzProvider>
      </body>
    </html>
  )
}

/app/page.tsx

import Link from "next/link"

export default function Page() {
  <Link href="/api/auth/google?scope=email" passHref legacyBehavior>Sign in with Google</Link>
}

/src/pages/api/auth/[...auth].ts

import { passportAuth } from "@blitzjs/auth"
import { api } from "app/blitz-server"
import db from "db"
import { Strategy as GoogleStrategy } from "passport-google-oauth20"
import * as process from "process"

export default api(
  passportAuth({
    successRedirectUrl: "/",
    errorRedirectUrl: "/",
    secureProxy: true,
    strategies: [
      {
        strategy: new GoogleStrategy(
          {
            clientID: process.env.GOOGLE_CLIENT_ID,
            clientSecret: process.env.GOOGLE_CLIENT_SECRET,
            callbackURL: process.env.GOOGLE_CALLBACK,
            scope: ["email"],
          },
          async function (accessToken, refreshToken, profile, done) {
            const email = profile.emails && profile.emails[0]?.value

            if (!email) {
              return done(new Error("Google response doesn't have email."))
            }

            const userIdp = await db.userIdp.upsert({
              where: {
                provider_providerId: { provider: profile.provider, providerId: profile.id },
              },
              create: {
                provider: profile.provider,
                providerId: profile.id,
              },
              update: { providerId: profile.id },
            })

            const user = await db.user.upsert({
              where: { userIdpId: userIdp.id },
              create: {
                email,
                name: email,
                userIdpId: userIdp.id,
              },
              update: { email },
            })

            const publicData = {
              userId: user.id,
              roles: [user.role],
              source: userIdp.provider,
            }
            done(undefined, { publicData })
          }
        ),
      },
    ],
  })
)

/app/secure/page.tsx

import { getBlitzContext, useAuthenticatedBlitzContext } from "app/blitz-server"

export default async function Page() {
  const ctx = await getBlitzContext()
  console.log(ctx.session.$publicData) // => { userId: null }

  await useAuthenticatedBlitzContext({
    redirectTo: "/auth/login",
    role: ["USER"],
    redirectAuthenticatedTo: "/",
  })

  return <div>Secured Content</div>
}

What are detailed steps to reproduce this?

  1. click the Sign in with Google in / with no authentication
  2. authenticate and permit to access in Google website
  3. redirect back to / from Google website
  4. go to /secure
  5. redirect to /auth/login by useAuthenticatedBlitzContext <= this is the problem.

Run blitz -v and paste the output here:

> blitz -v
Blitz version: 2.0.0-beta.20 (global)
Blitz version: 2.0.0-beta.32 (local)
macOS Monterey | darwin-arm64 | Node: v16.16.0


 Package manager: npm

  System:
    OS: macOS 12.5.1
    CPU: (8) arm64 Apple M1
    Memory: 84.44 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.16.0 - ~/.anyenv/envs/nodenv/versions/16.16.0/bin/node
    Yarn: 3.6.2 - ~/.volta/bin/yarn
    npm: 8.15.1 - ~/.anyenv/envs/nodenv/versions/16.16.0/bin/npm
  npmPackages:
    @blitzjs/auth: 2.0.0-beta.32 => 2.0.0-beta.32
    @blitzjs/next: 2.0.0-beta.32 => 2.0.0-beta.32
    @blitzjs/rpc: 2.0.0-beta.32 => 2.0.0-beta.32
    @prisma/client: ^5.2.0 => 5.2.0
    blitz: 2.0.0-beta.32 => 2.0.0-beta.32
    next: 13.4.19 => 13.4.19
    prisma: ^5.2.0 => 5.2.0
    react: 18.2.0 => 18.2.0
    react-dom: 18.2.0 => 18.2.0
    typescript: ^4.8.4 => 4.9.5

Please include below any other applicable logs and screenshots that show your problem:

No response

toofusan avatar Sep 08 '23 14:09 toofusan