pilcrowOnPaper / arctic

OAuth 2.0 clients for popular providers

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Invalid Code Verifier when using Google oAuth with Next.js

karyanayandi opened this issue · comments

this the error logs:

2024-02-02_16-53

and this is my code:

import { cookies } from "next/headers"
import { generateCodeVerifier, generateState } from "arctic"

const google = new Google(
  env.GOOGLE_CLIENT_ID,
  env.GOOGLE_CLIENT_SECRET,
  "http://localhost:3000/login/google/callback",
)

export async function GET(): Promise<Response> {
  const state = generateState()
  const codeVerifier = generateCodeVerifier()

  const url = await google.createAuthorizationURL(state, codeVerifier)

  cookies().set("state", state, {
    path: "/",
    // secure: process.env.NODE_ENV === "production",
    secure: false,
    httpOnly: true,
    maxAge: 60 * 10,
    sameSite: "lax",
  })

  cookies().set("code_verifier", state, {
    path: "/",
    // secure: process.env.NODE_ENV === "production",
    secure: false,
    httpOnly: true,
    maxAge: 60 * 10,
    sameSite: "lax",
  })

  return Response.redirect(url)
}

and this is code for callback

import { cookies } from "next/headers"
import { OAuth2RequestError } from "arctic"
import { google } from "../route.ts"

export async function GET(request: Request): Promise<Response> {
  const url = new URL(request.url)
  const code = url.searchParams.get("code")
  const state = url.searchParams.get("state")

  const storedState = cookies().get("state")?.value ?? null
  const storedCodeVerifier = cookies().get("code_verifier")?.value ?? null

  if (
    !code ||
    !state ||
    !storedState ||
    !storedCodeVerifier ||
    state !== storedState
  ) {
    return new Response("Invalid Request", {
      status: 400,
    })
  }

  try {
    const tokens = await google.validateAuthorizationCode(
      code,
      storedCodeVerifier,
    )

    const googleUserResponse = await fetch(
      "https://openidconnect.googleapis.com/v1/userinfo",
      {
        headers: {
          Authorization: `Bearer ${tokens.accessToken}`,
        },
      },
    )

    await googleUserResponse.json()

    const session = await lucia.createSession(userId, {})
    const sessionCookie = lucia.createSessionCookie(session.id)

    cookies().set(
      sessionCookie.name,
      sessionCookie.value,
      sessionCookie.attributes,
    )
    return new Response(null, {
      status: 302,
      headers: {
        Location: "/",
      },
    })
  } catch (e) {
    console.log(e)
    // the specific error message depends on the provider
    if (e instanceof OAuth2RequestError) {
      // invalid code
      return new Response(null, {
        status: 400,
      })
    }
    return new Response(null, {
      status: 500,
    })
  }
}