skip to Main Content

I developed an API using Django-REST Framework and am trying to connect it with my frontend.

I have an endpoint to get the last four winners, and when I try it works alright

async function getLastFourWinners() {
  const url = 'http://127.0.0.1:8000/bets/get_last_four_winners'
  const response = await fetch(url)
  if (!response.ok) {
    throw new Error('Failed to fetch data')
  }
 
  return response.json()
} 

export default async function Home() {

  const winners = await getLastFourWinners()

  return (
    <main>
        {winners.map((winner, index) => (
        <LastWinnerItem 
          key={index} 
          username={winner.username} 
          roundName={winner.round} 
          leagueName={winner.league}
          nPoints={winner.points} 
          nPlayers={winner.n_players} 
          pool={winner.pool} 
          imagePath={winner.profile_image} 
        /> 
      ))}
    </main>
    
  )
}

However, when I login from /login and then try to get the current logged user from my home, I get an error saying that I am not authenticated. But when I do the same using Postman it returns the user properly.

This is my /login:

'use client'
import { useState } from 'react'
import { useRouter } from 'next/navigation'
import './login.css'

export default function Login() {
    const [username, setUsername] = useState('')
    const [password, setPassword] = useState('')
    const router = useRouter()

    const url = 'http://127.0.0.1:8000/user/login/'
    const handleLogin = async(e) => {
        e.preventDefault();

        try {
            const response = await fetch(url, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({username, password}),
                credentials: 'include',
            })

            console.log(response)

            if (response.ok) {
                // router.push('/')
                console.log('ok')
            } else {
                console.error('Login failed')
            }

        } catch(error) {
            console.error('Error during login')
        }
    }

    return (
        <main className='container__main py-4'>
            <div className="card o-hidden border-0 shadow-lg w-75 mx-auto my-4">
                <div className="card-header py-3 login__header">
                    <h4 className="m-0 font-weight-bold">Log in</h4>
                </div>
                <div className="card-body">
                    <form onSubmit={handleLogin}>
                        <input 
                            type="text" 
                            id="username" 
                            name="username" 
                            value={username}
                            onChange={(e) => setUsername(e.target.value)}
                            className="form-control mb-4" 
                            placeholder="Username..." 
                            required 
                        />
                        <input 
                            type="password" 
                            id="password" 
                            name="password" 
                            value={password}
                            onChange={(e) => setPassword(e.target.value)}
                            className="form-control mb-4"
                            placeholder="Password..." 
                            required 
                        />
                        <small>Do not have a user? <a href="/signup" className='signup__btn'>Sign up</a></small>
                        <div className="login__button d-flex justify-content-center">
                            <button type="submit" className="btn text-center px-5 py-2 align-items-center">LOG IN</button>
                        </div>
                    </form>
                </div>
            </div>
        </main>
        
    )
}

And this is what I am trying to do from my homepage

async function getUser() {
  const response = await fetch('http://127.0.0.1:8000/user/user', {
      method: 'GET',
      credentials: 'include'
  })

  if(!response.ok) {
      throw new Error('Failed to fetch data')
  } else {
      return response.json()
  }

}


export default async function Home() {

  const user = await getUser()

  return (
      <main>
          <p>{user.username}</p>
      </main>
  )
}

The sessionid is created rightly when I make the post request to /user/login, and when I go to 127.0.0.1:8000/user/user in my browser I get the logged user, that is why I believe the problem is in getUser(), but am not being able to solve it

Please tell me if I was clear or if more information is needed to help me. Thank you in advance

2

Answers


  1. Chosen as BEST ANSWER

    I found the solution. The cookies were not being sent, so I was not sending the sessionid and the csrftoken to the server.

    This is the solution using the app directory structure:

    import { cookies } from 'next/headers'
    
    async function isLogged() {
      const cookieStore = cookies()
      const csrftoken = cookieStore.get('csrftoken')
      const sessionid = cookieStore.get('sessionid')
      const response = await fetch('http://127.0.0.1:8000/user/user', {
          method: 'GET',
          credentials: 'include', 
          headers: {
            'Content-Type': 'application/json',
            'Cookie': `csrftoken=${csrftoken.value}; sessionid=${sessionid.value}`
          }
      })
    
      try {
        if(!response.ok) {
          console.log('Failed to fetch data')
        } else {
          // return response.json()
          console.log('User obtained properly')
        }
      } catch(error) {
        console.log('Error during request')
      }
      
    
    }


  2. The issue is likely that the CORS policy is not properly configured on the Django backend to allow cross-origin requests with credentials from the Next.js frontend.

    There are a few things to check:

    In your Django settings, make sure you have the CORS middleware installed and configured to allow the Next.js origin/domain with credentials:

    CORS_ALLOW_CREDENTIALS = True
    
    CORS_ORIGIN_WHITELIST = [
        "http://localhost:3000" 
    ] 
    
    CORS_ALLOW_METHODS = [
        "DELETE",
        "GET",
        "OPTIONS",
        "PATCH",
        "POST",
        "PUT",
    ]
    

    In your view that serves /user/user, set the headers to allow credentials and expose response headers:

    response = JsonResponse({'username': user.username})
    response["Access-Control-Allow-Credentials"] = "true"  
    response["Access-Control-Expose-Headers"] = "*"
    return response
    

    On the Next.js side, ensure your fetch request has credentials: ‘include’ set, which you have.

    This enables the CORS policy to pass the session cookie on. Without it, cross-origin requests are blocked from sending or receiving cookies by default.

    Let me know if this helps explain the issue! The key is enabling credentials properly on both the Django and Nextjs side for the CORS policy.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search