Question:
I am migrating an app from Firebase to AWS Amplify. I want to create a React context which will provide route protection if the user is not logged in.
For example, my Auth.js file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import React, { useEffect, useState, createContext } from 'react' import fire from './firebase' export const AuthContext = createContext() export const AuthProvider = ({ children }) => { const [currentUser, setCurrentUser] = useState(null) useEffect(() => { fire.auth().onAuthStateChanged(setCurrentUser) }, []) return ( {children} ) } |
And my App.js file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
import * as React from 'react' import { BrowserRouter, Switch, Route } from 'react-router-dom' import Navbar from './components/navbar/navbar' import Home from './routes/Home' import Register from './routes/Register' import Footer from './components/footer/Footer' import AlertProvider from './components/notification/NotificationProvider' import MyAlert from './components/notification/Notification' import { AuthProvider } from './Auth' import PrivateRoute from './PrivateRoute' const App = () => { return ( path="/register" exact component={Register} /> path="/forgot-password" render={(props) => Forgot Password } /> ) } export default App |
This all works fine.
How would I do something similar with AWS Amplify? Essentially how would I create a Auth.js file that would wrap around my routes and give them a user context (which would update when the authentication status for the user is changed).
Thanks!
Answer:
You can achieve this by setting up a custom protectedRoute
HOC that will be used to protect any route that requires authentication. It will check if the user is signed-in and if the user is not signed-in then it will re-direct them to a specified route.
protectedRoute.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import React, { useEffect } from 'react' import { Auth } from 'aws-amplify' const protectedRoute = (Comp, route = '/profile') => (props) => { async function checkAuthState() { try { await Auth.currentAuthenticatedUser() } catch (err) { props.history.push(route) } } useEffect(() => { checkAuthState() }) return } export default protectedRoute |
You can specify the default route or another route like the following:
1 2 3 4 5 6 |
// default redirect route export default protectedRoute(Profile) // custom redirect route export default protectedRoute(Profile, '/sign-in') |
You could also use the pre-built HOC from aws-amplify called withAuthenticator
and that provides the UI as well as checking the users authentication status.
Sample use case for a profile page:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import React, { useState, useEffect } from 'react' import { Button } from 'antd' import { Auth } from 'aws-amplify' import { withAuthenticator } from 'aws-amplify-react' import Container from './Container' function Profile() { useEffect(() => { checkUser() }, []) const [user, setUser] = useState({}) async function checkUser() { try { const data = await Auth.currentUserPoolUser() const userInfo = { username: data.username, ...data.attributes, } setUser(userInfo) } catch (err) { console.log('error: ', err) } } function signOut() { Auth.signOut() .catch(err => console.log('error signing out: ', err)) } return ( ProfileUsername: {user.username}Email: {user.email}Phone: {user.phone_number} ); } export default withAuthenticator(Profile) |
The routing for both would be the same and below I have linked a sample that I have used for both.:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
import React, { useState, useEffect } from 'react' import { HashRouter, Switch, Route } from 'react-router-dom' import Nav from './Nav' import Public from './Public' import Profile from './Profile' import Protected from './Protected' const Router = () => { const [current, setCurrent] = useState('home') useEffect(() => { setRoute() window.addEventListener('hashchange', setRoute) return () => window.removeEventListener('hashchange', setRoute) }, []) function setRoute() { const location = window.location.href.split('/') const pathname = location[location.length-1] setCurrent(pathname ? pathname : 'home') } return ( ) } export default Router |