Search code examples
next.jsmobxnext-auth

Need help to figure out Mobx with Next-Auth


Here are my core dependencies and it's versions from my package.json file:

"mobx": "^6.5.0", "mobx-react": "^7.3.0", "next": "12.1.6", "next-auth": "4.2.1", "react": "17.0.1",

I am using next-auth to handle authentication im my next.js app, specifically to get and store my api accessToken. The thing is, next-auth needs the app to be wrapped inside a SessionProvider. So that we can access session object later via the useSession hook from next-auth, to get the accessToken to make authenticated requests to my API.

This is the hook i made to make use of session's accessToken to make authenticated requests:


import { setupAuthAPI } from '@/services/authAPI'
import { useSession } from 'next-auth/react'
import { useEffect } from 'react'

const useAuthAPI = () => {
  const { data: session } = useSession()

  useEffect(() => {
    const requestIntercept = setupAuthAPI().interceptors.request.use(
      config => {
        if (!config.headers.Authorization) {
          config.headers.Authorization = `Bearer ${session?.accessToken}`
        }
        return config
      },
      error => Promise.reject(error)
    )

    return () => {
      setupAuthAPI().interceptors.request.eject(requestIntercept)
    }
  }, [session])

  return setupAuthAPI
}

export default useAuthAPI

Consider also that setupAuthAPI is simply an Axios Instance.

And here is my Mobx store:

import { observer } from 'mobx-react'
import { makeAutoObservable } from 'mobx'
.....
.....
import { toast } from 'react-toastify'
import useAuthAPI from '@/hooks/useAuthAPI'

......
......

class ResellerStore implements ResellerStoreInterface {
  resellerOptions: ResellerOption[]
  loading = false

  constructor() {
    makeAutoObservable(
      this,
      {},
      {
        autoBind: true
      }
    )
  }

  async loadAll() {
    const setupAuthAPI = useAuthAPI()
    this.loading = true
    this.resellerOptions = []
    setupAuthAPI()
      .get('Reseller/all')
      .then(response => {
        const newResellerOptions = []
        response.data.forEach(reseller => {
          newResellerOptions.push({
            label: reseller.companyName,
            value: reseller.id
          })
        })

        this.resellerOptions = newResellerOptions
        this.loading = false
      })
  }

  
}

export { observer }
const resellerStore = new ResellerStore()

export { resellerStore }

But with this implementation, i am getting the error: Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

I need some help trying to figure out the correct flow to use my accessToken that is managed by next-auth and to use it to make authenticated requests inside my mobx store. Thank you in advance.

I tried the implementation already described in the question. What I'm expecting is to use next-auth to handle authentication in my next.js app, and also be able to use the accessToken managed by it inside my mobx store to make authenticated requests.


Solution

  • What I did that solved my problem was to put my API interceptor in a HOC that wraps my app, one layer below my SessionProvider. This way, my interceptor can access useSession data, since it is now in a React Component.