# Authentication
Migrate from JWT auth to NextAuth
Please refer to this article if you want to migrate from JWT auth to NextAuth (opens new window).
# Overview
We only provide JWT authentication with the template for now. We might integrate other authentication services in future.
# Auth Context
We have created an Authentication context that returns all the necessary functions you might need to authenticate a user like login, logout etc. Please make sure to override context and make necessary changes according to your app requirements. We have created this context for demo purpose only.
# Usage Example
import { useAuth } from 'src/hooks/useAuth'
const Component = () => {
const auth = useAuth()
const { login, logout } = auth
const handleErrCallback = err => {
console.log(err)
}
const handleLogin = () => {
login({ email, password, rememberMe }, err => handleErrCallback(err))
}
return (
<Form>
...
<Button onClick={handleLogin}>Login</Button>
<Button onClick={logout}>logout</Button>
</Form>
)
}
export default Component
# Overriding Auth
We are using localStorage
& fake-db
to store tokens and authenticate the user.
In a real application, you might store the token & user data in a session
or cookies
.
Follow these steps to override the auth context:
- Open
src/context/AuthContext.tsx
file - Now update the authentication code according to your authentication logic
- That's it now you can use your modified context.
# Auth Context Values
Property | Type | Description |
---|---|---|
user | Object | LoggedIn User Object |
setUser | Function | Function to update LoggedIn User |
isInitialized | Boolean | Returns if authentication is initialized or not |
setIsInitialized | Function | Function to update isInitialized state |
loading | Boolean | Returns if app is loading |
setLoading | Function | Function to update loading state |
login | Function | Function to login user. |
logout | Function | Function to logout user. |
# Securing Pages
We have created a wrapper that checks for the authentication status and redirects user if not logged in.
There are two types of guards:
- AuthGuard
- GuestGuard
Default value for both guards are as follows:
- authGuard: true
- guestGuard: false
User don't have to define AuthGuard
or GuestGuard
on all the pages as we have already defined default values as above.
Now let's consider scenarios where we need to override AuthGuard
& GuestGuard
.
# Guest Guard
For public pages like Login, Registration, Forgot Password, etc., we need to set GuestGuard value to true, as we don't want already logged in user to visit those pages and only guest should be able to visit those pages.
Setting GuestGuard to true in LoginPage component. Visit src/pages/login/index.tsx
to see it in the action and find out where and how to configure / override guestGuard
.
LoginPage.guestGuard = true
Setting GuestGuard to true will redirect already logged in user to home page whenever they try to visit the public pages like Login. So make sure to only change / override guestGuard when you do not want logged in users to visit that page.
# Auth Guard
Now, let's consider error pages, coming soon, under maintenance or common pages which is accessible by both guest and logged in users. User just need to set authGuard to false to do the same.
Setting authGuard to false in ComingSoon page component:
ComingSoon.authGuard = false
Setting authGuard to false will allow all the users to visit that page whether logged in or not.
If you want to show menu items in the navigation menu for the logged out user as well, it is necessary to add the auth: false
parameter in @src/navigation/vertical/index.tsx
and/or @src/navigation/horizontal/index.tsx
file(s).
If a single link is to be displayed, auth
property should be added solely to the corresponding menu link. If a link is to be displayed which is in a sub-menu, then the auth
property must be added to both the link and the submenu. Additionally, if a section title is to be displayed for number of links and/or groups, then auth
property must be added to the section title as well.
Refer to the example below:
[
{
title: 'Dashboards',
icon: 'mdi:home-outline',
badgeContent: 'new',
badgeColor: 'error',
auth: false,
children: [
{
title: 'Analytics',
path: '/dashboards/analytics'
},
{
title: 'eCommerce',
path: '/dashboards/ecommerce',
auth: false
}
]
},
{
auth: false,
sectionTitle: 'Apps & Pages'
},
{
auth: false,
title: 'Email',
icon: 'mdi:email-outline',
path: '/apps/email'
},
]
# onTokenExpiration
We provide onTokenExpiration
property in src/configs/auth
. It decides what action should take place when issued token is expired.
Value | Description |
---|---|
logout | will logout and redirect the user to /login page. |
refreshToken | will generate new token for the current user. |
Note
Because we're storing data in localStorage when you change the onTokenExpiration
you'll have to clear the localStorage and login again.
# JWT Token
We sign the user token in src/@fake-db/auth/jwt.js
file.
The jwtConfig
object contains three things expirationTime
, secret
refreshTokenSecret
.
Value | Description |
---|---|
expirationTime | User token expiration time |
secret | JWT secret to sign accessToken |
refreshTokenSecret | JWT secret to sign refreshToken |
As shown in the above section you can either logout
the user or referToken
on token expiration.
You can find the logic for that '/auth/me'
onGet request in the same file.
You can use jwt.verify
function to check for token validity and create a function according to your needs.
Here's how we have used jwt.verify
:
mock.onGet('/auth/me').reply(config => {
// Get token from header
const token = config.headers.Authorization
// Default response
let response: ResponseType = [200, {}]
// Checks if the token is valid or expired
jwt.verify(token, jwtConfig.secret, (err, decoded) => {
// If token is expired
if (err) {
// If onTokenExpiration === 'logout' then send 401 error
if (defaultAuthConfig.onTokenExpiration === 'logout') {
response = [401, { error: { error: 'Invalid User' } }]
} else {
// If onTokenExpiration === 'refreshToken' then generate the new token
const oldTokenDecoded = jwt.decode(token, { complete: true })
// Get user id from old token
const { id: userId } = oldTokenDecoded.payload
// Get user that matches id in token
const user = users.find(u => u.id === userId)
// Sign a new token
const accessToken = jwt.sign({ id: userId }, jwtConfig.secret, { expiresIn: jwtConfig.expirationTime })
// Set new token in localStorage
window.localStorage.setItem(defaultAuthConfig.storageTokenKeyName, accessToken)
const obj = { userData: { ...user, password: undefined } }
// return 200 with user data
response = [200, obj]
}
} else {
// If token is valid do nothing
const userId = decoded.id
// Get user that matches id in token
const userData = JSON.parse(JSON.stringify(users.find((u: UserDataType) => u.id === userId)))
delete userData.password
// return 200 with user data
response = [200, { userData }]
}
})
// Send Response
return response
})
# How to remove Authentication
Removing the authentication from the app is simple.
If you want to remove authentication from your project, there will be no point of giving access to users according to their role. Thus, you need to remove Access Control (ACL) from the project. Please refer to this doc to remove ACL.
Now, follow the steps given below to remove authentication from your project.
Changes in scr/pages/_app.tsx
file
Remove all Auth related import statements
import { ReactNode } from 'react' import AuthGuard from 'src/@core/components/auth/AuthGuard' import GuestGuard from 'src/@core/components/auth/GuestGuard' import Spinner from 'src/@core/components/spinner' import { AuthProvider } from 'src/context/AuthContext'
Remove the
Guard
Component and its wrapperRemove the wrapper of the
AuthProvider
componentRemove the
authGuard
&guestGuard
variablesRemove the
GuardProps
type
Changes in other files
- Remove
src/@core/components/auth
folder - Search and remove
Component.guestGuard
&Component.authGuard
methods from all the files (where Component is the name of the component) - Remove
authGuard?: boolean
andguestGuard?: boolean
from thenext.d.ts
file - Remove the
src/@fake-db/auth
folder and theimport './auth/jwt'
import statement from the filesrc/@fake-db/index.ts
- Remove
src/context/AuthContext.tsx
& all types related to the Auth from thesrc/context/types.ts
file and their import statements & their usage insidesrc
folder - Remove
src/hooks/useAuth.tsx
file and its import statements & their usage insidesrc
folder - If you want the user dropdown in the appBar, you need to override that component in
src/@core/layouts/components/shared-components/UserDropdown.tsx
file. If you do not require the user dropdown, then removesrc/@core/layouts/components/shared-components/UserDropdown.tsx
file, its import statements and its usage insrc/layouts/components/vertical/AppBarContent.tsx
andsrc/layouts/components/horizontal/AppBarContent.tsx
files
That's it. Now your app is auth free.