# How to migrate from JWT Auth to NextAuth

Prerequisite

It is required to have sufficient knowledge of NextAuth.js (opens new window) before reading this migration guide

How to secure API routes?

As the official guide from NextAuth for securing API routes (opens new window) is sufficient, we have not made any separate doc showing the same.

How to refresh a token?

If in case you need to implement refresh token functionality in your app, please refer to this (opens new window) guide from NextAuth.

To remove JWT authentication and implement NextAuth, please follow these steps:

  1. Uninstall the jsonwebtoken & @types/jsonwebtoken packages and install the next-auth package using the following command:

  2. Delete the src/@fake-db/auth/jwt.ts, src/config/auth.ts, src/context/AuthContext.tsx and src/hooks/useAuth.tsx files

  3. Remove the import './auth/jwt' import statement from the src/@fake-db/index.ts file

  4. Remove all the types related to the AuthContext and user data from the src/context/types.ts file. If you have not added any type in this file, you may delete this file

  5. If the src/context and src/hooks folders are empty, delete them

  6. Update the Access Control (ACL) guard as the src/hooks/useAuth.tsx file has been deleted. It is not recommended to make changes in the src/@core folder, so create a new file (say src/layouts/components/auth/UserAclGuard.tsx). Copy the code from src/@core/components/auth/AclGuard.tsx file, paste it into the new file, and make necessary modifications and replace auth with session.data as follows:

    For example, change the code from:

     
     


     
     



    import { useAuth } from 'src/hooks/useAuth'
    const auth = useAuth()
    
    // User is logged in, build ability for the user based on his role
    if (auth.user && !ability) {
      ability = buildAbilityFor(auth.user.role, aclAbilities.subject)
      ...
    }
    

    to:

     
     


     
     



    import { useSession } from 'next-auth/react'
    const session = useSession()
    
    // User is logged in, build ability for the user based on his role
    if (session.data && session.data.user && !ability) {
      ability = buildAbilityFor(session.data.user.role, aclAbilities.subject)
      ...
    }
    
  7. As mentioned in above step, it is necessary to modify the following code in each file where the import of useAuth occurs. Additionally, the variable auth should be replaced with session.data in most of the files.

    Change the code from:

    import { useAuth } from 'src/hooks/useAuth'
    const auth = useAuth()
    
    auth.<something>
    

    to:

     import { useSession } from 'next-auth/react'
     const session = useSession()
    
     session.data.<something>
    
  8. Update the Authentication guard as the src/hooks/useAuth.tsx file has been deleted. It is not recommended to make changes in the src/@core folder, so create a new file (say src/layouts/components/auth/UserAuthGuard.tsx). Copy the code from src/@core/components/auth/AuthGuard.tsx file, paste it into the new file, and make necessary modifications

    Change the code from:

     
     





     








     


     



    import { useAuth } from 'src/hooks/useAuth'
    const auth = useAuth()
    
    useEffect(
      () => {
        ...
    
        if (auth.user === null && !window.localStorage.getItem('userData')) {
          if (router.asPath !== '/') {
            ...
          } else {
            ...
          }
        }
      },
      // eslint-disable-next-line react-hooks/exhaustive-deps
      [router.route]
    )
    
    if (auth.loading || auth.user === null) {
      return fallback
    }
    

    to:

     
     





     








     


     



    import { useSession } from 'next-auth/react'
    const session = useSession()
    
    useEffect(
      () => {
        ...
    
        if (session.status === 'unauthenticated') {
          if (router.asPath !== '/') {
            ...
          } else {
            ...
          }
        }
      },
      // eslint-disable-next-line react-hooks/exhaustive-deps
      [router.route, session.status]
    )
    
    if (session.status !== 'authenticated') {
      return fallback
    }
    
  9. Update the Guest guard as the src/hooks/useAuth.tsx file has been deleted. It is not recommended to make changes in the src/@core folder, so create a new file (say src/layouts/components/auth/UserGuestGuard.tsx). Copy the code from src/@core/components/auth/GuestGuard.tsx file, paste it into the new file, and make necessary modifications

    Change the code from:

     
     




     



     

     
     
     

     

    import { useAuth } from 'src/hooks/useAuth'
    const auth = useAuth()
    
    useEffect(() => {
      ...
    
      if (window.localStorage.getItem('userData')) {
        ...
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [router.route])
    
    if (auth.loading || (!auth.loading && auth.user !== null)) {
      return fallback
    }
    
    return <>{children}</>
    

    to:

     
     




     



     

     
     
     
     
     

    import { useSession } from 'next-auth/react'
    const session = useSession()
    
    useEffect(() => {
      ...
    
      if (session.status === 'authenticated' && !router.query.returnUrl) {
        ...
      }
      // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [router.route, session.status])
    
    if (session.status === 'unauthenticated') {
      return <>{children}</>
    } else {
      return fallback
    }
    
  10. Update the user dropdown as the src/hooks/useAuth.tsx file has been deleted. It is not recommended to make changes in the src/@core folder, so create a new file (say src/layouts/components/UserDropdown.tsx). Copy the code from src/@core/layouts/components/shared-components/UserDropdown.tsx file, paste it into the new file, and make necessary modifications

    Change the code from:

     
     


     



    import { useAuth } from 'src/hooks/useAuth'
    const { logout } = useAuth()
    
    const handleLogout = () => {
      logout()
      handleDropdownClose()
    }
    

    to:

     


     
     
     



    import { signOut } from 'next-auth/react'
    
    const handleLogout = () => {
      signOut({ callbackUrl: '/', redirect: false }).then(() => {
        router.asPath = '/'
      })
      handleDropdownClose()
    }
    
  11. Update the import statement in src/layouts/components/vertical/AppBarContent.tsx and/or src/layouts/components/horizontal/AppBarContent.tsx file(s) after creating the new file and making modifications for the UserDropdown import and also modify the file according to the step 7

    from:

    import UserDropdown from 'src/@core/layouts/components/shared-components/UserDropdown'
    

    to:

    import UserDropdown from 'src/layouts/components/UserDropdown'
    
  12. Remove the src/@core/components/auth folder and src/@core/layouts/components/shared-components/UserDropdown.tsx file from the src/@core folder in order to prevent build-time errors

  13. As the src/hooks/useAuth.tsx file has been deleted, update the code in the src/pages/login/index.tsx file according to the NextAuth's provider. We have demonstrated CredentialsProvider and you can find the related code in this guide

  14. Update the src/pages/_app.tsx file as the new guards have been created and the AuthContext has been removed

    from:

     
     
     
     

     

     

    import AclGuard from 'src/@core/components/auth/AclGuard'
    import AuthGuard from 'src/@core/components/auth/AuthGuard'
    import GuestGuard from 'src/@core/components/auth/GuestGuard'
    import { AuthProvider } from 'src/context/AuthContext'
    
    <AuthProvider>
      {...}
    </AuthProvider>
    

    to:

     
     
     
     

     

     

    import AclGuard from 'src/layouts/components/auth/UserAclGuard'
    import AuthGuard from 'src/layouts/components/auth/UserAuthGuard'
    import GuestGuard from 'src/layouts/components/auth/UserGuestGuard'
    import { SessionProvider } from 'next-auth/react'
    
    <SessionProvider session={pageProps.session}>
      {...}
    </SessionProvider>
    
  15. Change the .env file

    from:

    NEXT_PUBLIC_JWT_SECRET= YOUR_SECRET_GOES_HERE
    NEXT_PUBLIC_JWT_EXPIRATION= YOUR_EXPIRATION_DURATION_GOES_HERE
    NEXT_PUBLIC_JWT_REFRESH_TOKEN_SECRET= YOUR_REFRESH_TOKEN_SECRET_GOES_HERE
    

    to:

    API_URL=http://localhost:3000
    NEXTAUTH_URL=http://localhost:3000
    NEXTAUTH_SECRET= YOUR_SECRET_GOES_HERE
    

    You can refer to this (opens new window) guide for generating your own secret.

  16. For typescript-version users, add the following in the tsconfig.json file:



     
     
     




    "compilerOptions": {
      "paths": {
        "next-auth": [
          "./node_modules/next-auth"
        ],
        ...
      }
    },
    

    You may require the addition of the next-auth.d.ts file to your project's root directory to modify certain types specified by NextAuth. A tutorial on how to alter these types is available through the link provided in the next step. If the next-auth.d.ts file must be added, the following entry must be included in the tsconfig.json file:


     



    "include": [
      "next-auth.d.ts",
      ...
    ],
    
  17. Create the src/pages/api/auth/[...nextauth].ts file. Please refer to this article on how to implement authentication using CredentialsProvider (opens new window). You may customize this file according to your requirements

  18. If you get any type errors after doing the above steps, you need to refresh/reopen your editor.

This is it.

Last Updated: 5/8/2024, 7:58:27 AM