-
-
Save EduVencovsky/f8f6c275f42f7352571c92a59309e31d to your computer and use it in GitHub Desktop.
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 |
@hvolschenk This gist is kind of old and I made it far time ago, now what I recommend is having 2 contexts, one for checking if the user is authenticated and another to hold all the user informations. So when you call login
, it will automatically set user credentials in a use context. After that, you can just use hooks go get the user info anytime you want.
like this approach, thanks
@hvolschenk This gist is kind of old and I made it far time ago, now what I recommend is having 2 contexts, one for checking if the user is authenticated and another to hold all the user informations. So when you call
login
, it will automatically set user credentials in a use context. After that, you can just use hooks go get the user info anytime you want.
is there a way to trigger checkAuth on route change this context will keep using same isAuthenticated flag first value all the time till you refresh
Hey @hvolschenk by any chance did you find a solution for the mentioned concerns? regarding the 401 errors
is there a way to trigger checkAuth on route change this context will keep using same isAuthenticated flag first value all the time till you refresh
Yes you can, but there is alot of ways of doing this. You want on every route change to call checkAuth? Any Route should do this or only Private routes? Does nested routes count on this?
@HDaghash what you are asking is something too much specific for this generalized gist, because it will depend on your application.
But if you want to implement it, you could pass checkAuth to the context value and call it when you need it. (It will be better if you create a custom hook that does that)
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
@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
@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.
@hvolschenk Aha I see and I agree with dispatching action it's a better way than having multiple hooks traversing all these data.
thanks for the approach, well done
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.
Thanks Sir
Where is ../../services/auth file is?
awesome, thanks sir.
Where is ../../services/auth file is?
Same i also want to see how those functions atre
async await завезли пацаны
Exactly what I've been looking for, thanks!
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?
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
Thanks for the example.
I have a question though, something I have not been able to figure out.
When any API call fails with a
401
from the Backend, I would like to also log the user out.I can only see two solutions here, both of which are truly not ideal:
Wrap all API calls in Context
I could wrap all API calls in their own Context Provider and get all async methods from context,
this way if any API call fails with a
401
I can update theAuthContext
and set the user as logged out.Wrapping all API calls in Context feels a bit strange though as that might be a quite large object
being passed around instead of just importing the one(s) I need directly.
Handle
401
s in each componentThere is also the possibility of duplicating the
401
code in each Component making an API call.Obviously this is not great as I could easily miss one, and this will introduce a lot of duplicated code.
Maybe you (or someone reading this) knows something I don't and can point me in the right direction?