useLogin and useAuth do not work together to update `isAuthenticated`/`viewer`
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.
- [X] Yes
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])