Next.js Discord

Discord Forum

Issues with passing props

Unanswered
Oriental Scops-Owl posted this in #help-forum
Open in Discord
Oriental Scops-OwlOP
Hi, i have modified my app.tsx file to the following:

            <ThemeProvider theme={theme}>
              <AppHeader isAuthenticated={isAuthenticated} />
              <div className="appContainer">
                <Component {...pageProps} isAuthenticated={isAuthenticated} />
              </div>
              <AppFooter />
              <AppSidebar isAuthenticated={isAuthenticated} />
            </ThemeProvider>


i am having issues with "isAuthenticated" property. it works fine for most cases and is accessible, however, when i use getServerSideProps on a child component, it is not accessible:

export async function getServerSideProps() {
  const subscriptions = await SubscriptionService.getAll()
  console.log(subscriptions)
  // Pass data to the page via props
  return { props: { subscriptions } }
}

export default Purchase


How do i make it so isAuthenticated is accessible in this case?

132 Replies

Oriental Scops-OwlOP
probably just wrong terminology
the page i am using getServerSideProps on is in the pages folder
it works fine for fetching subscriptions on the server-side. the issue is the isAuthenticated properly is not available on the pages component
this is my app.tsx
this is my page component:
when i try to access isAuthenticated inside the Purchase component, it is unavailable
seems like getServerSideProps is causing app.tsx to not pass the property down from app.tsx to the purchase component for some reason
@Oriental Scops-Owl this is my page component:
you need to return isAuthenticated in the props of getServerSideProps
Oriental Scops-OwlOP
what is the proper syntax for typescript to do this? i tried adding it into the getServerSideProps() constructor but couldnt figure it out
export async function getServerSideProps(isAuthenticated: boolean) {
  const subscriptions = await SubscriptionService.getAll()
  console.log(subscriptions)
  // Pass data to the page via props
  return { props: { subscriptions, isAuthenticated } } 
}
is this correct?
when i do that, i get a weird error in my browser
@Oriental Scops-Owl export async function getServerSideProps(isAuthenticated: boolean) { const subscriptions = await SubscriptionService.getAll() console.log(subscriptions) // Pass data to the page via props return { props: { subscriptions, isAuthenticated } } }
import { GetServerSideProps, InferGetServerSidePropsType } from "next";

type PageProps = {
    isAuthenticated: boolean
}

export default function Page({isAuthenticated}: InferGetServerSidePropsType<typeof getServerSideProps>) {

}

export const getServerSideProps = (async () => {
    const isAuthenticated = false
    return {
        props: {
            isAuthenticated
        }
    }
}) satisfies GetServerSideProps<PageProps>
Oriental Scops-OwlOP
i need the isAuthenticated value from app.tsx that was passed into the Component props
Oriental Scops-OwlOP
^^ that is my full app.tsx as it is now..
I have never use _app.tsx like that
so I can't tell will it work or not
Oriental Scops-OwlOP
it works fine mostly from what i can tell. its just the passing of isAuthenticated fails on the child component when using getServerSideProps
how do you get the value of isAuthenticated in _app.tsx
Oriental Scops-OwlOP
  useEffect(() => {
    const sub = AuthService.isAuthenticated$.subscribe(value => {
      setAuthenticated(value)
      if (isDashboard && !value) {
        void router.push('/')
      }
    })
    return () => {
      sub.unsubscribe()
    }
  // eslint-disable-next-line
  }, [])
using an Rxjs observer
that's client side
getServerSideProps is running on server side
Oriental Scops-OwlOP
im still using old nextjs with pages folder
yeah... thats why its breaking id say
so it run getServerSideProps before your AuthService
so it doesn't work and you should follow the doc and try to use the layout pattern
Oriental Scops-OwlOP
i ended up coding a workaround by adding the same code to the actual purchase component
or you could use getInitialProps in _app.js
but it is not recommend
Oriental Scops-OwlOP
the layout component doesnt really change much if you compare both approaches. <Layout> is just a wrapper. the code is cleaner for sure, but my way of loading in the layout components are fine. its just the passing of isAuthenticated to the child Component is a bit odd
but whether or not i split it into wrapper Layout components is irrelevant
not gonna change my issue with isAuthenticated
you need to run your authservice inside getServerSideProps from the page
not in the _app.tsx
Oriental Scops-OwlOP
yeah thats what i was gonna say
my current work around i just added it to the actual Purchase component and is working
but i would prefer it to be done server-side
then pass it to a layout component
Oriental Scops-OwlOP
yeah, ill clean up my layout code and add some wrappers to make it cleaner, and move the auth code over to getServerSideProps
you can see in my file i uploaded, i have multiple layouts. makes the code messy having it all in app.tsx so ill split them out into layout components to help with that bit
Oriental Scops-OwlOP
yeah thats the plan
<RegisterPageLayout>, <DashboardLayout>, <DefaultLayout> etc
my main concern was the isAuthenticated and how to get it into getServerSideProps. i just wasnt sure if moving the code there would actually work because the isAuthenticated observable is generated from the browser local storage
  public isAuthenticated$: Observable<boolean> = this.authSubject.asObservable().pipe(distinctUntilChanged())

  public isAuthenticated(): boolean {
    const isBrowser: boolean = ((): boolean => typeof window !== 'undefined')()
    if (isBrowser) {
      const token = this.getAccessToken()
      if (!token) {
        return false
      }
      if (!this.isTokenExpired()) {
        return true
      }
      return !this.isRefreshTokenExpired()
    }
    return false
  }
  public getAccessToken(): string|undefined {
    const isBrowser: boolean = ((): boolean => typeof window !== 'undefined')()
    if (isBrowser) {
      const localStorageData = localStorage.getItem('grubstackUser')
      if (localStorageData != null) {
        const parsedData:IAuthUser = JSON.parse(localStorageData)
        return parsedData.access_token
      }
    }
    return undefined
  }
Oriental Scops-OwlOP
right
thats what i figured. would need redux yeah ?
is it possible to store the token to cookie instead?
you should use cookies for server side rendering
Oriental Scops-OwlOP
yeah.. actually.. one sec
so i actually am storing a cookie and local storage. my API returns a response with set-cookie in it, and after you sign in, the cookie is set
so there is a cookie set in the browser, but not inside of nextjs server (if thats a thing)
the cookie just stores the access and refresh token, and the local storage is storing the user info
i should prob clean that up honestly
(i wrote it a while back and was porting over to cookies)
@Oriental Scops-Owl so there is a cookie set in the browser, but not inside of nextjs server (if thats a thing)
if the cookie is set in the browser, you should be able to access it in getServerSideProps
export const getServerSideProps = (async ({req}) => {
    const token = req.cookies['cookieName']

}) satisfies GetServerSideProps<PageProps>
Oriental Scops-OwlOP
ahh okay.
let me see if that works
Oriental Scops-OwlOP
tried this with no luck:

export const getServerSideProps = (async ({req}) => {
  const isAuthenticated = req.cookies['_grubstack_access_token'] != undefined ? true : false
  const subscriptions = await SubscriptionService.getAll()

  console.log(isAuthenticated)
  // Pass data to the page via props
  return { props: { subscriptions, isAuthenticated } } 

}) satisfies GetServerSideProps


export default Purchase
Oriental Scops-OwlOP
sure
@Oriental Scops-Owl Click to see attachment
yeah, your frontend domain need to be included to the domain of the cookie
localhost in this case
Oriental Scops-OwlOP
yeah so i have a software stack (nextjs with an API, then i have customer apps on react with thei own API) . everything is keyed to grubstack.app right now
i was in the process of moving everything to a shared cookie
my next app still needs some work apparently. been a while since i touched the auth code
@Oriental Scops-Owl yeah so i have a software stack (nextjs with an API, then i have customer apps on react with thei own API) . everything is keyed to grubstack.app right now
try to create a api route for login, then make the request to your api and set the cookie inside the api route
Oriental Scops-OwlOP
yeah thats what im doing right now
the cookie actually set on my production API for the nextjs site
the API returns a set-cookie header
then that cookie is used among all the other apps
it works.. mostly. but the nextjs app seems to be having some issues with it.
i have SameSite set to none
so after you fix the domain issue, you should be able to grab the cookie in getServerSideProps
because the browser only attach the cookie with the same domain to current request
Oriental Scops-OwlOP
yeah.. im curious why my react app is working locally and not the nextjs. the react app uses only cookies AFAIK to send API requests
i run that on localhost as well, and is keyed to grubstack.app and seems to work fine
fetch("https://grubstack.app") like this?
Oriental Scops-OwlOP
yeah pretty much in a nutshell
api.grubstack.app blah blah
react app is client side, when you make the request, the browser send along the cookie within the domain
Oriental Scops-OwlOP
right.. and the difference in nextjs getServerSideProps ?
@Oriental Scops-Owl right.. and the difference in nextjs getServerSideProps ?
because your nextjs currently running on localhost
Oriental Scops-OwlOP
so is my react app
🙂
yeah but the request is made to api.grubstack.app
Oriental Scops-OwlOP
ah
your nextjs server is running on localhost
the browser make the request to localhost
in your react app, the browser make the request to api.grubstack.app
that's the different
Oriental Scops-OwlOP
gotcha. yeah the nextjs under the hood confuses me sometimes
if your nextjs is hosting on next.grubstack.app, you should be able to see the cookie
Oriental Scops-OwlOP
gotcha.. interesting. so i need to run the nexst app from a local NGINX proxy ?
Oriental Scops-OwlOP
i already have a login route in my API.
do you mean inside of nextjs?
grab the Set-Cookie header from the response of your api and set the cookie with next
Oriental Scops-OwlOP
gotcha... so i need an API route inside of nextjs to be like middleware to make the request to the API instead of directly from the browser?
so you can make sure the domain of the cookie is same as the next server
client side or server side
Oriental Scops-OwlOP
right now, most of my nextjs app is fetching via client side
the login, register page etc, everything is being sent from nextjs client side over to my flask/python API
the only thing being fetched via server-side was this one route with the subscriptions call
seems like i need to rewrite the nextjs app though. i need to migrate it anyways to latest version
im still using the pages folder versus app folder
@Ray grab the `Set-Cookie` header from the response of your api and set the cookie with next
do this if you are going to fetch on the server side
Oriental Scops-OwlOP
gotcha
Oriental Scops-OwlOP
yeah i got some weird stuff going on with my auth i need to revisit.

on my react app, i have the cookie being set via API response from my production / primary API with set-cookie. so this is completely separate from the react app

then when i access the customer API (different from the API that sets the cookie), if the react app does not see a user jwt inside of local storage, it accesses the /whoami route which checks for the cookie. if it sees a cookie, it returns the user jwt, then it sets the local storage inside the react app. then the subsequent calls to the customer API uses the tokens and user info from the jwt inside of local storage. the cookie is only really being used to fetch the user jwt
seems kind of stupid really, but flask seems to only really deal with access token and refresh token out of the box
hence why i have the /whoami endpoint to fetch the user jwt with all of the user info i need for the frontend to work properly
the react app works fine. i havent had any issues with this approach, even though its not the best approach
the APIs are coded to allow either sending the access token via cookie or local storage:

    refresh_token = request.cookies.get('_grubstack_refresh_token') or request.headers['Authorization'].split(None, 1)[1].strip()
etc etc
anyways.. i have some things to refactor and redesign. thanks for your input