Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useLogin and useAuth do not work together to update isAuthenticated/viewer #1923

Open
1 task done
bpkennedy opened this issue Aug 1, 2024 · 1 comment
Open
1 task done
Labels
needs: reproduction This issue needs to be reproduced independently

Comments

@bpkennedy
Copy link

bpkennedy commented Aug 1, 2024

Description

In this example code I'm trying to login the user with useLogin and then wait to see them become authenticated by using useAuth. I can confirm after login that a cookie is created in the browser and I see a GET request completed to url http://localhost:3000/api/faust/auth/token?code=1PrSDHzvYuNSANI47ZiP%2BvyRwEbQ8eihr7rq5gI3fpok%2FXY%2FP%2BwsJovxj4aW3tYHmE1PFLx%2FC%2BjnxwJo8TiUvg%3D%3D with output like this:

{
  accessToken: "yAJXMIslG6TucsCZQDyzq3ycLT6VaejoGvUEQrT7KVdChwUzbnt1rKU/2fL1u/HTuxspAdALbpDNc85P2ThRvw=="
  accessTokenExpiration: 1722542440
  refreshToken: "UlS1wyVXj/+XR/6jxavbjjxq9bS8Yy15N/9WWQJxbZ6c0prFKNhta/V2BBgZPTC7CUEQGGING1IPFw5+vJYDqA=="
  refreshTokenExpiration: 1723751740
}

Furthermore, I can soft refresh the browser page and if I were to console.log viewer from useAuth on the next page load then it would recognize the logged in user. So I know that it's successfully logging me in as the user.

The issue is that useAuth is never updating either isAuthenticated or viewer right after a successful login() with useLogin. Here is the Next.js component that demonstrates how I'm trying to get access to isAuthenticated after successful login:

import CloseButton from '@/components/CloseButton'
import GravityForm from '@/components/GravityForm'
import { GRAVITY_FORM_IDS } from '@/lib/constants'
import { useAuth, useLogin } from '@faustwp/core'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'

const MultiStepRegistration = () => {
  const [step, setStep] = useState(1)
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [isLoggingIn, setIsLoggingIn] = useState(false)
  const router = useRouter()

  const { login } = useLogin()
  const { viewer, isAuthenticated } = useAuth()

  useEffect(() => {
    let checkAuthInterval
    if (isLoggingIn) {
      checkAuthInterval = setInterval(() => {
        console.log('Checking authentication status...')
        if (isAuthenticated) {
          console.log('User is now authenticated')
          clearInterval(checkAuthInterval)
          setIsLoggingIn(false)
          setStep(2)
        }
      }, 1000) // Check every second
    }
    return () => {
      if (checkAuthInterval) clearInterval(checkAuthInterval)
    }
  }, [isLoggingIn, isAuthenticated])

  const handleStep1Success = async (queryResult, formData) => {
    const emailField = queryResult.data.submitGfForm.entry.formFields.nodes.find((field) => field.type === 'EMAIL')
    const passwordField = queryResult.data.submitGfForm.entry.formFields.nodes.find((field) => field.type === 'PASSWORD')

    const submittedEmail = formData[emailField.id]
    const submittedPassword = formData[passwordField.id]

    setEmail(submittedEmail)
    setPassword(submittedPassword)

    try {
      setIsLoggingIn(true)
      login(submittedEmail, submittedPassword)
    } catch (error) {
      console.error('Login error:', error)
      setIsLoggingIn(false)
      // Handle login error (e.g., show an error message)
    }
  }

  const handleStep2Success = (queryResult, formData) => {
    // Handle step 2 form submission
  }

  return (
    <main className="flex min-h-full flex-1 flex-col justify-center px-6 lg:px-8 relative">
      <CloseButton onClick={() => router.push('/')} className="absolute top-4 right-4" ariaLabel="Close" />

      <div className="sm:mx-auto sm:w-full sm:max-w-sm">
        <h2 className="text-center text-2xl font-bold leading-9 tracking-tight text-gray-900">Create New Account</h2>
        <p className="mt-2 text-center text-sm text-gray-600">Step {step} of 2</p>
      </div>

      <div className="mt-8 sm:mx-auto sm:w-full sm:max-w-sm">
        {step === 1 && (
          <GravityForm
            formId={GRAVITY_FORM_IDS.registrationStepOne}
            showLabels={true}
            submitButtonText="Next"
            submittingButtonText="Submitting..."
            onSubmitSuccess={handleStep1Success}
            className="mt-4 space-y-6"
          />
        )}
        {step === 2 && (
          <GravityForm
            formId={GRAVITY_FORM_IDS.registrationStepTwo}
            showLabels={true}
            submitButtonText="Complete Registration"
            submittingButtonText="Submitting..."
            onSubmitSuccess={handleStep2Success}
            className="mt-4 space-y-6"
          />
        )}
        {isLoggingIn && <p className="mt-4 text-center text-sm text-gray-600">Logging in...</p>}
      </div>
    </main>
  )
}

export default MultiStepRegistration

What happens instead is that it will wait forever for isAuthenticated (or viewer) to change, logging 'Checking authentication status...' to the console every second, but it never changes.

Steps to reproduce

See description

Additional context

No response

@faustwp/core Version

^3.0.1

@faustwp/cli Version

^3.0.2

FaustWP Plugin Version

1.3.2

WordPress Version

6.6.1

Additional environment details

No response

Please confirm that you have searched existing issues in the repo.

  • Yes
@bpkennedy
Copy link
Author

bpkennedy commented Aug 1, 2024

Here is a minimal example. Create a user with email [email protected] and password pass. Then try this (ensure you've cleared your browser cache):

import { useAuth, useLogin } from '@faustwp/core'
import { useEffect, useState } from 'react'

const Example = () => {
  const { login } = useLogin()
  const { viewer, isAuthenticated } = useAuth()
  const [isLoggingIn, setIsLoggingIn] = useState(false)

  useEffect(() => {
    console.log('Auth state changed - isAuthenticated:', isAuthenticated, 'viewer:', viewer)
  }, [isAuthenticated, viewer])

  useEffect(() => {
    let checkAuthInterval
    if (isLoggingIn) {
      checkAuthInterval = setInterval(() => {
        console.log('Checking authentication status...')
        console.log('isAuthenticated:', isAuthenticated)
        console.log('viewer:', viewer)
        if (isAuthenticated) {
          console.log('User is now authenticated')
          setIsLoggingIn(false)
          clearInterval(checkAuthInterval)
        }
      }, 1000) // Check every second
    }
    return () => {
      if (checkAuthInterval) clearInterval(checkAuthInterval)
    }
  }, [isLoggingIn, isAuthenticated, viewer])

  const handleLogin = async () => {
    try {
      setIsLoggingIn(true)
      console.log('Attempting login...')
      await login('[email protected]', 'pass')
      console.log('Login function called')
    } catch (error) {
      console.error('Login error:', error)
      setIsLoggingIn(false)
    }
  }

  return (
    <div>
      <button onClick={handleLogin}>
        {isLoggingIn ? 'Logging in...' : 'Click Me to Login'}
      </button>
      <p>Authentication status: {isAuthenticated ? 'Authenticated' : 'Not authenticated'}</p>
      {viewer && <p>Logged in as: {viewer.username}</p>}
    </div>
  )
}

export default Example

This useEffect is never triggered:

  useEffect(() => {
    console.log('Auth state changed - isAuthenticated:', isAuthenticated, 'viewer:', viewer)
  }, [isAuthenticated, viewer])

@josephfusco josephfusco added the needs: reproduction This issue needs to be reproduced independently label Aug 2, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs: reproduction This issue needs to be reproduced independently
Projects
None yet
Development

No branches or pull requests

2 participants