rrsartneoai / ai-chatbot

A full-featured, hackable Next.js AI chatbot built by Vercel
https://chat.vercel.ai
Other
0 stars 0 forks source link

a #3

Open rrsartneoai opened 3 months ago

rrsartneoai commented 3 months ago

want to allow users to signup and login using their Google account

codeautopilot[bot] commented 3 months ago

Potential solution

To allow users to sign up and log in using their Google account, we need to integrate Google OAuth into our authentication system. This involves updating the UI components to include Google login/signup buttons and configuring the authentication logic to handle Google OAuth tokens and sessions.

How to implement

Step 1: Update components/login-button.tsx

Add a Google login button to the LoginButton component and handle the Google OAuth flow.

Updated components/login-button.tsx

'use client'

import * as React from 'react'
import { signIn } from 'next-auth/react'
import { cn } from '@/lib/utils'
import { Button, type ButtonProps } from '@/components/ui/button'
import { IconGitHub, IconGoogle, IconSpinner } from '@/components/ui/icons'

interface LoginButtonProps extends ButtonProps {
  provider: 'github' | 'google'
  text?: string
}

export function LoginButton({
  provider,
  text,
  className,
  ...props
}: LoginButtonProps) {
  const [isLoading, setIsLoading] = React.useState(false)

  const handleSignIn = () => {
    setIsLoading(true)
    signIn(provider, { callbackUrl: `/` })
  }

  const renderIcon = () => {
    if (isLoading) {
      return <IconSpinner className="mr-2 animate-spin" />
    }
    switch (provider) {
      case 'github':
        return <IconGitHub className="mr-2" />
      case 'google':
        return <IconGoogle className="mr-2" />
      default:
        return null
    }
  }

  return (
    <Button
      variant="outline"
      onClick={handleSignIn}
      disabled={isLoading}
      className={cn(className)}
      {...props}
    >
      {renderIcon()}
      {text || `Login with ${provider.charAt(0).toUpperCase() + provider.slice(1)}`}
    </Button>
  )
}

Step 2: Update auth.config.ts

Configure the Google OAuth provider in the auth.config.ts file.

Updated auth.config.ts

import type { NextAuthConfig } from 'next-auth'
import GoogleProvider from 'next-auth/providers/google'

export const authConfig = {
  secret: process.env.AUTH_SECRET,
  pages: {
    signIn: '/login',
    newUser: '/signup'
  },
  callbacks: {
    async authorized({ auth, request: { nextUrl } }) {
      const isLoggedIn = !!auth?.user
      const isOnLoginPage = nextUrl.pathname.startsWith('/login')
      const isOnSignupPage = nextUrl.pathname.startsWith('/signup')

      if (isLoggedIn) {
        if (isOnLoginPage || isOnSignupPage) {
          return Response.redirect(new URL('/', nextUrl))
        }
      }

      return true
    },
    async jwt({ token, user }) {
      if (user) {
        token = { ...token, id: user.id }
      }

      return token
    },
    async session({ session, token }) {
      if (token) {
        const { id } = token as { id: string }
        const { user } = session

        session = { ...session, user: { ...user, id } }
      }

      return session
    }
  },
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    })
  ]
} satisfies NextAuthConfig

Step 3: Update package.json

Add the necessary dependencies for Google OAuth.

Updated package.json

{
  "dependencies": {
    "next-auth": "5.0.0-beta.4",
    "@next-auth/google": "^1.0.0"
  }
}

Run the following command to install the new dependencies:

pnpm install

Step 4: Update components/login-form.tsx

Add a Google login button to the login form.

Updated components/login-form.tsx

'use client'

import { useFormState, useFormStatus } from 'react-dom'
import { authenticate } from '@/app/login/actions'
import Link from 'next/link'
import { useEffect } from 'react'
import { toast } from 'sonner'
import { IconSpinner } from './ui/icons'
import { getMessageFromCode } from '@/lib/utils'
import { useRouter } from 'next/navigation'
import { signIn } from 'next-auth/react'

export default function LoginForm() {
  const router = useRouter()
  const [result, dispatch] = useFormState(authenticate, undefined)

  useEffect(() => {
    if (result) {
      if (result.type === 'error') {
        toast.error(getMessageFromCode(result.resultCode))
      } else {
        toast.success(getMessageFromCode(result.resultCode))
        router.refresh()
      }
    }
  }, [result, router])

  return (
    <form
      action={dispatch}
      className="flex flex-col items-center gap-4 space-y-3"
    >
      <div className="w-full flex-1 rounded-lg border bg-white px-6 pb-4 pt-8 shadow-md  md:w-96 dark:bg-zinc-950">
        <h1 className="mb-3 text-2xl font-bold">Please log in to continue.</h1>
        <div className="w-full">
          <div>
            <label
              className="mb-3 mt-5 block text-xs font-medium text-zinc-400"
              htmlFor="email"
            >
              Email
            </label>
            <div className="relative">
              <input
                className="peer block w-full rounded-md border bg-zinc-50 px-2 py-[9px] text-sm outline-none placeholder:text-zinc-500 dark:border-zinc-800 dark:bg-zinc-950"
                id="email"
                type="email"
                name="email"
                placeholder="Enter your email address"
                required
              />
            </div>
          </div>
          <div className="mt-4">
            <label
              className="mb-3 mt-5 block text-xs font-medium text-zinc-400"
              htmlFor="password"
            >
              Password
            </label>
            <div className="relative">
              <input
                className="peer block w-full rounded-md border bg-zinc-50 px-2 py-[9px] text-sm outline-none placeholder:text-zinc-500 dark:border-zinc-800 dark:bg-zinc-950"
                id="password"
                type="password"
                name="password"
                placeholder="Enter password"
                required
                minLength={6}
              />
            </div>
          </div>
        </div>
        <LoginButton />
        <GoogleLoginButton />
      </div>

      <Link
        href="/signup"
        className="flex flex-row gap-1 text-sm text-zinc-400"
      >
        No account yet? <div className="font-semibold underline">Sign up</div>
      </Link>
    </form>
  )
}

function LoginButton() {
  const { pending } = useFormStatus()

  return (
    <button
      className="my-4 flex h-10 w-full flex-row items-center justify-center rounded-md bg-zinc-900 p-2 text-sm font-semibold text-zinc-100 hover:bg-zinc-800 dark:bg-zinc-100 dark:text-zinc-900 dark:hover:bg-zinc-200"
      aria-disabled={pending}
    >
      {pending ? <IconSpinner /> : 'Log in'}
    </button>
  )
}

function GoogleLoginButton() {
  return (
    <button
      type="button"
      className="my-4 flex h-10 w-full flex-row items-center justify-center rounded-md bg-red-600 p-2 text-sm font-semibold text-white hover:bg-red-500"
      onClick={() => signIn('google')}
    >
      Log in with Google
    </button>
  )
}

Step 5: Update components/signup-form.tsx

Add a Google signup button to the signup form.

Updated components/signup-form.tsx

'use client'

import { useFormState, useFormStatus } from 'react-dom'
import { signup } from '@/app/signup/actions'
import Link from 'next/link'
import { useEffect } from 'react'
import { toast } from 'sonner'
import { IconSpinner } from './ui/icons'
import { getMessageFromCode } from '@/lib/utils'
import { useRouter } from 'next/navigation'
import { signIn } from 'next-auth/react'

export default function SignupForm() {
  const router = useRouter()
  const [result, dispatch] = useFormState(signup, undefined)

  useEffect(() => {
    if (result) {
      if (result.type === 'error') {
        toast.error(getMessageFromCode(result.resultCode))
      } else {
        toast.success(getMessageFromCode(result.resultCode))
        router.refresh()
      }
    }
  }, [result, router])

  return (
    <form
      action={dispatch}
      className="flex flex-col items-center gap-4 space-y-3"
    >
      <div className="w-full flex-1 rounded-lg border bg-white px-6 pb-4 pt-8 shadow-md md:w-96 dark:bg-zinc-950">
        <h1 className="mb-3 text-2xl font-bold">Sign up for an account!</h1>
        <div className="w-full">
          <div>
            <label
              className="mb-3 mt-5 block text-xs font-medium text-zinc-400"
              htmlFor="email"
            >
              Email
            </label>
            <div className="relative">
              <input
                className="peer block w-full rounded-md border bg-zinc-50 px-2 py-[9px] text-sm outline-none placeholder:text-zinc-500 dark:border-zinc-800 dark:bg-zinc-950"
                id="email"
                type="email"
                name="email"
                placeholder="Enter your email address"
                required
              />
            </div>
          </div>
          <div className="mt-4">
            <label
              className="mb-3 mt-5 block text-xs font-medium text-zinc-400"
              htmlFor="password"
            >
              Password
            </label>
            <div className="relative">
              <input
                className="peer block w-full rounded-md border bg-zinc-50 px-2 py-[9px] text-sm outline-none placeholder:text-zinc-500 dark:border-zinc-800 dark:bg-zinc-950"
                id="password"
                type="password"
                name="password"
                placeholder="Enter password"
                required
                minLength={6}
              />
            </div>
          </div>
        </div>
        <LoginButton />
        <GoogleSignupButton />
      </div>

      <Link href="/login" className="flex flex-row gap-1 text-sm text-zinc-400">
        Already have an account?
        <div className="font-semibold underline">Log in</div>
      </Link>
    </form>
  )
}

function LoginButton() {
  const { pending } = useFormStatus()

  return (
    <button
      className="my-4 flex h-10 w-full flex-row items-center justify-center rounded-md bg-zinc-900 p-2 text-sm font-semibold text-zinc-100 hover:bg-zinc-800 dark:bg-zinc-100 dark:text-zinc-900 dark:hover:bg-zinc-200"
      aria-disabled={pending}
    >
      {pending ? <IconSpinner /> : 'Create account'}
    </button>
  )
}

function GoogleSignupButton() {
  return (
    <button
      type="button"
      className="my-4 flex h-10 w-full flex-row items-center justify-center rounded-md bg-red-600 p-2 text-sm font-semibold text-white hover:bg-red-500"
      onClick={() => signIn('google')}
    >
      Sign up with Google
    </button>
  )
}

Step 6: Update auth.ts

Integrate the Google OAuth provider into the authentication logic.

Updated auth.ts

import NextAuth from 'next-auth'
import Credentials from 'next-auth/providers/credentials'
import GoogleProvider from 'next-auth/providers/google'
import { authConfig } from './auth.config'
import { z } from 'zod'
import { getStringFromBuffer } from './lib/utils'
import { getUser } from './app/login/actions'

export const { auth, signIn, signOut } = NextAuth({
  ...authConfig,
  providers: [
    Credentials({
      async authorize(credentials) {
        const parsedCredentials = z
          .object({
            email: z.string().email(),
            password: z.string().min(6)
          })
          .safeParse(credentials)

        if (parsedCredentials.success) {
          const { email, password } = parsedCredentials.data
          const user = await getUser(email)

          if (!user) return null

          const encoder = new TextEncoder()
          const saltedPassword = encoder.encode(password + user.salt)
          const hashedPasswordBuffer = await crypto.subtle.digest(
            'SHA-256',
            saltedPassword
          )
          const hashedPassword = getStringFromBuffer(hashedPasswordBuffer)

          if (hashedPassword === user.password) {
            return user
          } else {
            return null
          }
        }

        return null
      }
    }),
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET
    })
  ],
  callbacks: {
    async session({ session, token, user }) {
      return session
    },
    async jwt({ token, user, account, profile, isNewUser }) {
      return token
    }
  }
})

Environment Variables

Ensure you have the following environment variables set in your .env file:

GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret

By following these steps, you will have integrated Google OAuth into your authentication system, allowing users to sign up and log in using their Google accounts.

Click here to create a Pull Request with the proposed solution

Files used for this task:

Changes on components/login-button.tsx To add a Google login button that triggers the Google OAuth flow, you will need to modify the `LoginButton` component to support Google authentication. Here’s a step-by-step guide to achieve this: 1. **Update the `LoginButton` component to support Google login:** - Add a new button for Google login. - Update the `signIn` function to handle Google OAuth. 2. **Add necessary icons for Google login:** - If you don't have an icon for Google, you might need to add one. Here is the updated code for `components/login-button.tsx`: ```typescript 'use client' import * as React from 'react' import { signIn } from 'next-auth/react' import { cn } from '@/lib/utils' import { Button, type ButtonProps } from '@/components/ui/button' import { IconGitHub, IconGoogle, IconSpinner } from '@/components/ui/icons' // Assuming IconGoogle is available interface LoginButtonProps extends ButtonProps { provider: 'github' | 'google' text?: string } export function LoginButton({ provider, text, className, ...props }: LoginButtonProps) { const [isLoading, setIsLoading] = React.useState(false) const handleSignIn = () => { setIsLoading(true) signIn(provider, { callbackUrl: `/` }) } const renderIcon = () => { if (isLoading) { return } switch (provider) { case 'github': return case 'google': return default: return null } } return ( ) } ``` ### Explanation: 1. **Dynamic Provider Handling:** - The `LoginButton` component now accepts a `provider` prop which can be either 'github' or 'google'. - The `handleSignIn` function dynamically uses the `provider` prop to initiate the sign-in process. 2. **Dynamic Icon Rendering:** - The `renderIcon` function dynamically renders the appropriate icon based on the `provider` prop. - If the `isLoading` state is true, it shows a spinner icon. 3. **Button Text:** - The button text is dynamically set based on the `provider` prop, defaulting to "Login with GitHub" or "Login with Google". ### Additional Steps: - **IconGoogle Component:** - Ensure you have an `IconGoogle` component in your `components/ui/icons` directory. If not, you will need to create one or use an existing Google icon. - **Usage Example:** - You can now use the `LoginButton` component for both GitHub and Google login buttons in your application: ```jsx ``` This update will allow users to log in using their Google account by clicking the Google login button, which triggers the Google OAuth flow.
Changes on auth.config.ts To enable Google OAuth for user signup and login, you need to configure the Google OAuth provider in the `auth.config.ts` file. Here’s a step-by-step guide to update this file: 1. **Install Dependencies**: Ensure you have `next-auth` and `@next-auth/google` installed. You can add these dependencies by running: ```bash npm install next-auth @next-auth/google ``` 2. **Update `auth.config.ts`**: Add the Google OAuth provider configuration, including the client ID and client secret. These credentials can be obtained from the Google Developer Console. Here is the updated `auth.config.ts` file with the Google OAuth provider configuration: ```typescript import type { NextAuthConfig } from 'next-auth' import GoogleProvider from 'next-auth/providers/google' export const authConfig = { secret: process.env.AUTH_SECRET, pages: { signIn: '/login', newUser: '/signup' }, callbacks: { async authorized({ auth, request: { nextUrl } }) { const isLoggedIn = !!auth?.user const isOnLoginPage = nextUrl.pathname.startsWith('/login') const isOnSignupPage = nextUrl.pathname.startsWith('/signup') if (isLoggedIn) { if (isOnLoginPage || isOnSignupPage) { return Response.redirect(new URL('/', nextUrl)) } } return true }, async jwt({ token, user }) { if (user) { token = { ...token, id: user.id } } return token }, async session({ session, token }) { if (token) { const { id } = token as { id: string } const { user } = session session = { ...session, user: { ...user, id } } } return session } }, providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, }) ] } satisfies NextAuthConfig ``` ### Steps to Follow: 1. **Set Environment Variables**: Ensure you have the following environment variables set in your `.env` file: ```env AUTH_SECRET=your_auth_secret GOOGLE_CLIENT_ID=your_google_client_id GOOGLE_CLIENT_SECRET=your_google_client_secret ``` 2. **Google Developer Console**: - Go to the [Google Developer Console](https://console.developers.google.com/). - Create a new project or select an existing one. - Navigate to the "Credentials" section. - Create OAuth 2.0 Client IDs and set the authorized redirect URIs to your application's callback URL (e.g., `http://localhost:3000/api/auth/callback/google`). By following these steps, you will have configured the Google OAuth provider in your `auth.config.ts` file, allowing users to sign up and log in using their Google accounts.
Changes on package.json To enable Google OAuth for user signup and login, we need to add the necessary dependencies to the `package.json` file. Specifically, we need to include `next-auth` and `@next-auth/google`. Here's how you can update the `package.json` file: 1. **Add `next-auth` and `@next-auth/google` to the dependencies section**: - `next-auth` is the main library for handling authentication in Next.js. - `@next-auth/google` is the provider package for Google OAuth. Here's the updated `package.json` file with the new dependencies: ```json { "private": true, "scripts": { "dev": "next dev", "build": "next build", "start": "next start", "lint": "next lint", "lint:fix": "next lint --fix", "preview": "next build && next start", "seed": "node -r dotenv/config ./scripts/seed.mjs", "type-check": "tsc --noEmit", "format:write": "prettier --write \"{app,lib,components}/**/*.{ts,tsx,mdx}\" --cache", "format:check": "prettier --check \"{app,lib,components}**/*.{ts,tsx,mdx}\" --cache" }, "dependencies": { "@ai-sdk/openai": "^0.0.9", "@radix-ui/react-alert-dialog": "^1.0.5", "@radix-ui/react-dialog": "^1.0.5", "@radix-ui/react-dropdown-menu": "^2.0.6", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-select": "^2.0.0", "@radix-ui/react-separator": "^1.0.3", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-tooltip": "^1.0.7", "@vercel/analytics": "^1.1.2", "@vercel/kv": "^1.0.1", "@vercel/og": "^0.6.2", "ai": "^3.1.5", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "d3-scale": "^4.0.2", "date-fns": "^3.3.1", "focus-trap-react": "^10.2.3", "framer-motion": "^10.18.0", "geist": "^1.2.1", "nanoid": "^5.0.4", "next": "14.2.3", "next-auth": "5.0.0-beta.4", "next-themes": "^0.2.1", "openai": "^4.24.7", "react": "^18.2.0", "react-dom": "^18.2.0", "react-intersection-observer": "^9.5.3", "react-markdown": "^8.0.7", "react-syntax-highlighter": "^15.5.0", "react-textarea-autosize": "^8.5.3", "remark-gfm": "^3.0.1", "remark-math": "^5.1.1", "sonner": "^1.4.3", "usehooks-ts": "^2.16.0", "zod": "^3.22.4", "@next-auth/google": "^1.0.0" }, "devDependencies": { "@tailwindcss/typography": "^0.5.10", "@types/d3-scale": "^4.0.8", "@types/node": "^20.11.5", "@types/react": "^18.2.48", "@types/react-dom": "^18.2.18", "@types/react-syntax-highlighter": "^15.5.11", "@typescript-eslint/parser": "^6.19.0", "autoprefixer": "^10.4.17", "dotenv": "^16.4.5", "eslint": "^8.56.0", "eslint-config-next": "14.1.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-tailwindcss": "^3.14.0", "postcss": "^8.4.33", "prettier": "^3.2.4", "tailwind-merge": "^2.2.0", "tailwindcss": "^3.4.1", "tailwindcss-animate": "^1.0.7", "typescript": "^5.3.3" }, "packageManager": "pnpm@8.6.3" } ``` After updating the `package.json` file, run the following command to install the new dependencies: ```sh pnpm install ``` This will ensure that `next-auth` and `@next-auth/google` are installed and ready to be used in your project.
Changes on components/login-form.tsx To update the `login-form.tsx` file to include a Google login option, you will need to add a button that triggers the Google OAuth flow. This button should be placed alongside the existing login form elements. Here's a step-by-step guide to achieve this: 1. **Import Necessary Modules**: Import the necessary modules for handling the Google OAuth flow. 2. **Add Google Login Button**: Add a button that users can click to initiate the Google login process. 3. **Handle Google OAuth Flow**: Ensure that clicking the button correctly initiates the Google OAuth flow. Here's the updated code for `login-form.tsx`: ```typescript 'use client' import { useFormState, useFormStatus } from 'react-dom' import { authenticate } from '@/app/login/actions' import Link from 'next/link' import { useEffect } from 'react' import { toast } from 'sonner' import { IconSpinner } from './ui/icons' import { getMessageFromCode } from '@/lib/utils' import { useRouter } from 'next/navigation' import { signIn } from 'next-auth/react' // Import signIn from next-auth export default function LoginForm() { const router = useRouter() const [result, dispatch] = useFormState(authenticate, undefined) useEffect(() => { if (result) { if (result.type === 'error') { toast.error(getMessageFromCode(result.resultCode)) } else { toast.success(getMessageFromCode(result.resultCode)) router.refresh() } } }, [result, router]) return (

Please log in to continue.

{/* Add Google login button */}
No account yet?
Sign up
) } function LoginButton() { const { pending } = useFormStatus() return ( ) } function GoogleLoginButton() { return ( ) } ``` ### Explanation: 1. **Import `signIn` from `next-auth/react`**: This function is used to initiate the OAuth flow. 2. **Add `GoogleLoginButton` Component**: This component renders a button that, when clicked, calls `signIn('google')` to start the Google OAuth process. 3. **Include `GoogleLoginButton` in the Form**: The `GoogleLoginButton` is added to the form, below the existing login button. This update will allow users to log in using their Google account by clicking the "Log in with Google" button.
Changes on components/signup-form.tsx To update the signup form to include a Google signup option, you need to add a button that triggers the Google OAuth flow. This involves integrating the Google OAuth provider into your authentication system. Here’s a step-by-step guide to achieve this: 1. **Install Dependencies**: Ensure you have `next-auth` and `@next-auth/google` installed in your project. You can add these dependencies in your `package.json` file and run `npm install` or `yarn install`. 2. **Configure Google OAuth**: Update your `auth.config.ts` file to include the Google OAuth provider configuration. 3. **Update the Signup Form**: Modify the `SignupForm` component to include a Google signup button. Here’s how you can update the `components/signup-form.tsx` file: ### Updated `components/signup-form.tsx` ```tsx 'use client' import { useFormState, useFormStatus } from 'react-dom' import { signup } from '@/app/signup/actions' import Link from 'next/link' import { useEffect } from 'react' import { toast } from 'sonner' import { IconSpinner } from './ui/icons' import { getMessageFromCode } from '@/lib/utils' import { useRouter } from 'next/navigation' import { signIn } from 'next-auth/react' // Import signIn from next-auth export default function SignupForm() { const router = useRouter() const [result, dispatch] = useFormState(signup, undefined) useEffect(() => { if (result) { if (result.type === 'error') { toast.error(getMessageFromCode(result.resultCode)) } else { toast.success(getMessageFromCode(result.resultCode)) router.refresh() } } }, [result, router]) return (

Sign up for an account!

{/* Add Google signup button */}
Already have an account?
Log in
) } function LoginButton() { const { pending } = useFormStatus() return ( ) } function GoogleSignupButton() { return ( ) } ``` ### Explanation: 1. **Import `signIn` from `next-auth/react`**: This function will be used to trigger the Google OAuth flow. 2. **Add `GoogleSignupButton` Component**: This button will initiate the Google signup process when clicked. 3. **Update the Form**: Include the `GoogleSignupButton` component within the form. This will add a Google signup option to your signup form, allowing users to sign up using their Google account. Make sure the rest of your authentication logic is set up to handle Google OAuth tokens and sessions as specified in the other files.
Changes on auth.ts To update the authentication logic in `auth.ts` to handle Google OAuth tokens and sessions, you need to integrate the Google OAuth provider using `next-auth`. Here’s a step-by-step guide to achieve this: 1. **Install Dependencies**: Ensure you have `next-auth` and `@next-auth/google` installed. You can add these dependencies in your `package.json` and run `npm install` or `yarn install`. 2. **Update `auth.config.ts`**: Make sure your `auth.config.ts` file includes the Google OAuth provider configuration with the necessary client ID and client secret. 3. **Update `auth.ts`**: Modify the `auth.ts` file to include the Google provider in the `providers` array. Here is the updated code for `auth.ts`: ```typescript import NextAuth from 'next-auth' import Credentials from 'next-auth/providers/credentials' import GoogleProvider from 'next-auth/providers/google' import { authConfig } from './auth.config' import { z } from 'zod' import { getStringFromBuffer } from './lib/utils' import { getUser } from './app/login/actions' export const { auth, signIn, signOut } = NextAuth({ ...authConfig, providers: [ Credentials({ async authorize(credentials) { const parsedCredentials = z .object({ email: z.string().email(), password: z.string().min(6) }) .safeParse(credentials) if (parsedCredentials.success) { const { email, password } = parsedCredentials.data const user = await getUser(email) if (!user) return null const encoder = new TextEncoder() const saltedPassword = encoder.encode(password + user.salt) const hashedPasswordBuffer = await crypto.subtle.digest( 'SHA-256', saltedPassword ) const hashedPassword = getStringFromBuffer(hashedPasswordBuffer) if (hashedPassword === user.password) { return user } else { return null } } return null } }), GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET }) ], callbacks: { async session({ session, token, user }) { // Add custom session handling if needed return session }, async jwt({ token, user, account, profile, isNewUser }) { // Add custom JWT handling if needed return token } } }) ``` ### Explanation: 1. **GoogleProvider**: Added `GoogleProvider` from `next-auth/providers/google` to the `providers` array. This requires `clientId` and `clientSecret` which should be stored in your environment variables (`process.env.GOOGLE_CLIENT_ID` and `process.env.GOOGLE_CLIENT_SECRET`). 2. **Callbacks**: Added `session` and `jwt` callbacks to handle custom session and JWT token logic if needed. These are optional and can be customized based on your application's requirements. ### Environment Variables: Ensure you have the following environment variables set in your `.env` file: ``` GOOGLE_CLIENT_ID=your-google-client-id GOOGLE_CLIENT_SECRET=your-google-client-secret ``` ### Next Steps: - **auth.config.ts**: Ensure this file is correctly set up to include any additional configuration required for `next-auth`. - **UI Components**: Update the UI components (`login-button.tsx`, `login-form.tsx`, `signup-form.tsx`) to include options for Google login/signup. This should enable users to sign up and log in using their Google accounts.