Skip to content

Instantly share code, notes, and snippets.

@EduVencovsky
Last active February 20, 2024 03:28
Show Gist options
  • Save EduVencovsky/f8f6c275f42f7352571c92a59309e31d to your computer and use it in GitHub Desktop.
Save EduVencovsky/f8f6c275f42f7352571c92a59309e31d to your computer and use it in GitHub Desktop.
Private Routes with Auth using react-router and Context API
import React, { useState, useEffect } from 'react'
import PropTypes from 'prop-types'
import { checkIsAuthenticated, authSignUp, authLogin, authLogout } from '../../services/auth'
export const AuthContext = React.createContext({})
export default function Auth({ children }) {
const [isAuthenticated, setIsAuthenticated] = useState(false)
const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
checkAuth()
}, [])
const checkAuth = () => checkIsAuthenticated()
.then(() => setIsAuthenticated(true))
.catch(() => setIsAuthenticated(false))
.then(() => setIsLoading(false))
const login = credentials => authLogin(credentials)
.then(setIsAuthenticated(true))
.catch(error => {
alert(error)
setIsAuthenticated(false)
})
const logout = () => {
authLogout()
setIsAuthenticated(false)
}
const signUp = credentials => authSignUp(credentials)
.then(setIsAuthenticated(true))
.catch(error => {
alert(error)
setIsAuthenticated(false)
})
return (
<AuthContext.Provider value={{ isAuthenticated, isLoading, login, logout, signUp }}>
{children}
</AuthContext.Provider>
)
}
Auth.propTypes = {
children: PropTypes.oneOfType([
PropTypes.func,
PropTypes.array
])
}
import React from 'react'
import { Switch, Route } from 'react-router-dom'
import PrivateRoute from './components/PrivateRoute/PrivateRoute'
import Auth from './components/Auth/Auth'
import Header from './components/Header/Header'
import HomePage from './views/HomePage/HomePage'
import SignUp from './views/SignUp/SignUp'
import SignIn from './views/SignIn/SignIn'
import FormList from './views/FormList/FormList'
import PageNotFound from './views/PageNotFound/PageNotFound'
export default function App() {
return (
<div>
<Auth>
<Header />
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/signup" component={SignUp} />
<Route path="/signin" component={SignIn} />
<PrivateRoute path="/forms" component={FormList} />
<Route component={PageNotFound} />
</Switch>
</Auth>
</div>
)
}
import React, { useContext } from 'react'
import { Route, Redirect } from 'react-router-dom'
import PropTypes from 'prop-types'
import { AuthContext } from '../Auth/Auth'
import Loading from '../../views/Loading/Loading'
const PrivateRoute = ({ component: Component, ...otherProps }) => {
const { isAuthenticated, isLoading } = useContext(AuthContext)
return (
<Route
{...otherProps}
render={props => (
!isLoading
?
(
isAuthenticated
?
<Component {...props} />
:
<Redirect to={otherProps.redirectTo ? otherProps.redirectTo : '/signin'} />
)
:
<Loading />
)}
/>
)
}
PrivateRoute.propTypes = {
component: PropTypes.func.isRequired
}
export default PrivateRoute
@EduVencovsky
Copy link
Author

When any API call fails with a 401 from the Backend, I would like to also log the user out.

What do you mean by "log the user out"? Now reading you question again I can see that if you want, you can add some logic in checkAuth's .then or .catch that will check for 401 status and call logout

@HDaghash
Copy link

@EduVencovsky thank you for your response, I meant return user back to the sign-in page and wipe the current token, now I solve it by dispatching an action by redux to do that since the Hook Context will not be available everywhere for example (inside Axios interceptor) when I catch the 401 error of any request.

Regarding the checking on each private route, I think this is should be a generic case since we don't want to a user browsing the private pages while his token has been expired, that's why we need each page change for a private route to check if the token still valid that's part I didn't figure it out yet

@hvolschenk
Copy link

@EduVencovsky thank you for your response, I meant return user back to the sign-in page and wipe the current token, now I solve it by dispatching an action by redux to do that since the Hook Context will not be available everywhere for example (inside Axios interceptor) when I catch the 401 error of any request.

Yeah I am doing exactly the same. I use redux solely for this purpose (Also using axios).
There is another way, by wrapping all API calls in context and making them available through a hook or such,
but I have been trying this and it feels rather messy to be honest.

@HDaghash
Copy link

@hvolschenk Aha I see and I agree with dispatching action it's a better way than having multiple hooks traversing all these data.

@farhanasif
Copy link

thanks for the approach, well done

@NabinOjha
Copy link

NabinOjha commented Sep 18, 2020

However, when we reload the protected route page the initial value of isAuthenticated is false and we are redirected to /signin directly ......But when isAuthenticated is set to true after some time it has no effect on the current route since we are already on '/signin'.......Correct me if i am wrong but this approach does not seem to be working for me since checking isAuthenticated is a time consuming task????
Thank You.

@iqbalnur32
Copy link

Thanks Sir

@OmanCoding
Copy link

Where is ../../services/auth file is?

@aacassandra
Copy link

awesome, thanks sir.

@DisasterNatsu
Copy link

Where is ../../services/auth file is?

Same i also want to see how those functions atre

@IDONTSUDO
Copy link

async await завезли пацаны

@jakerich1
Copy link

Exactly what I've been looking for, thanks!

@DisasterNatsu
Copy link

DisasterNatsu commented Oct 26, 2021 via email

@ravikant-pal
Copy link

However, when we reload the protected route page the initial value of isAuthenticated is false and we are redirected to /signin directly ......But when isAuthenticated is set to true after some time it has no effect on the current route since we are already on '/signin'.......Correct me if i am wrong but this approach does not seem to be working for me since checking isAuthenticated is a time consuming task???? Thank You.

I have the same issue @NabinOjha did you find any solution?
@EduVencovsky what's your thought on this?

@DisasterNatsu
Copy link

However, when we reload the protected route page the initial value of isAuthenticated is false and we are redirected to /signin directly ......But when isAuthenticated is set to true after some time it has no effect on the current route since we are already on '/signin'.......Correct me if i am wrong but this approach does not seem to be working for me since checking isAuthenticated is a time consuming task???? Thank You.

I have the same issue @NabinOjha did you find any solution? @EduVencovsky what's your thought on this?

https://medium.com/@dennisivy/creating-protected-routes-with-react-router-v6-2c4bbaf7bc1c

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment