# 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:
Uninstall the
jsonwebtoken
&@types/jsonwebtoken
packages and install thenext-auth
package using the following command:Delete the
src/@fake-db/auth/jwt.ts
,src/config/auth.ts
,src/context/AuthContext.tsx
andsrc/hooks/useAuth.tsx
filesRemove the
import './auth/jwt'
import statement from thesrc/@fake-db/index.ts
fileRemove all the types related to the
AuthContext
and user data from thesrc/context/types.ts
file. If you have not added any type in this file, you may delete this fileIf the
src/context
andsrc/hooks
folders are empty, delete themUpdate the Access Control (ACL) guard as the
src/hooks/useAuth.tsx
file has been deleted. It is not recommended to make changes in thesrc/@core
folder, so create a new file (saysrc/layouts/components/auth/UserAclGuard.tsx
). Copy the code fromsrc/@core/components/auth/AclGuard.tsx
file, paste it into the new file, and make necessary modifications and replaceauth
withsession.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) ... }
As mentioned in above step, it is necessary to modify the following code in each file where the import of
useAuth
occurs. Additionally, the variableauth
should be replaced withsession.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>
Update the Authentication guard as the
src/hooks/useAuth.tsx
file has been deleted. It is not recommended to make changes in thesrc/@core
folder, so create a new file (saysrc/layouts/components/auth/UserAuthGuard.tsx
). Copy the code fromsrc/@core/components/auth/AuthGuard.tsx
file, paste it into the new file, and make necessary modificationsChange 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 }
Update the Guest guard as the
src/hooks/useAuth.tsx
file has been deleted. It is not recommended to make changes in thesrc/@core
folder, so create a new file (saysrc/layouts/components/auth/UserGuestGuard.tsx
). Copy the code fromsrc/@core/components/auth/GuestGuard.tsx
file, paste it into the new file, and make necessary modificationsChange 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 }
Update the user dropdown as the
src/hooks/useAuth.tsx
file has been deleted. It is not recommended to make changes in thesrc/@core
folder, so create a new file (saysrc/layouts/components/UserDropdown.tsx
). Copy the code fromsrc/@core/layouts/components/shared-components/UserDropdown.tsx
file, paste it into the new file, and make necessary modificationsChange 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() }
Update the import statement in
src/layouts/components/vertical/AppBarContent.tsx
and/orsrc/layouts/components/horizontal/AppBarContent.tsx
file(s) after creating the new file and making modifications for theUserDropdown
import and also modify the file according to the step 7from:
import UserDropdown from 'src/@core/layouts/components/shared-components/UserDropdown'
to:
import UserDropdown from 'src/layouts/components/UserDropdown'
Remove the
src/@core/components/auth
folder andsrc/@core/layouts/components/shared-components/UserDropdown.tsx
file from thesrc/@core
folder in order to prevent build-time errorsAs the
src/hooks/useAuth.tsx
file has been deleted, update the code in thesrc/pages/login/index.tsx
file according to the NextAuth's provider. We have demonstrated CredentialsProvider and you can find the related code in this guideUpdate the
src/pages/_app.tsx
file as the new guards have been created and theAuthContext
has been removedfrom:
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>
Change the
.env
filefrom:
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.
For
typescript-version
users, add the following in thetsconfig.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 thenext-auth.d.ts
file must be added, the following entry must be included in thetsconfig.json
file:"include": [ "next-auth.d.ts", ... ],
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 requirementsIf you get any type errors after doing the above steps, you need to refresh/reopen your editor.
This is it.