Skip to content

Commit 98a1ea2

Browse files
authored
Merge pull request #259 from CodeForPhilly/198-UI
UI for login refresh (198 UI)
2 parents 1ee2ef0 + c30b3ac commit 98a1ea2

File tree

6 files changed

+111
-12
lines changed

6 files changed

+111
-12
lines changed

src/client/src/App.js

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ import Search360 from './pages/DataView360/Search/Search';
1010
import View360 from './pages/DataView360/View/View';
1111
import About from './pages/About';
1212
import Login from './components/Login/Login';
13+
import RefreshDlg from './components/RefreshDlg';
1314
import Check from './pages/Check/Check';
15+
import Refresh from './components/Refresh';
16+
1417
import useToken from './components/Login/useToken';
1518
var jwt = require('jsonwebtoken');
1619

@@ -68,26 +71,32 @@ function useAuthState() {
6871

6972

7073
function AuthenticatedApp() {
71-
74+
7275
const { access_token, setToken } = useToken();
7376

74-
7577
var decoded = jwt.decode(access_token, { complete: true });
7678

7779
const userRole = decoded?.payload.role;
7880
var expTime = decoded?.payload.exp - Date.now()/1000;
79-
8081
const jwtExpired = expTime <= 0
8182

83+
const popRefreshAlert = expTime > 0 && expTime < 30; // Time in secs to pop up refresh dialog
84+
8285
const hdr = userRole === 'admin' ? <AdminHeader /> : <Header /> // If we're going to display a header, which one?
8386

8487
const history = useHistory();
8588

8689
return (
8790
<>
8891
<Router>
92+
93+
{ !jwtExpired && hdr ? hdr : '' /* Above-chosen header, or if logged out, no header */ }
94+
95+
{popRefreshAlert && <RefreshDlg shouldOpen={true} setToken={setToken} /> } {/* Pop up the refresh dialog */}
96+
97+
{jwtExpired && <RefreshDlg shouldOpen={false} setToken={setToken} /> } { /* Too late, expired: close the dialog */}
98+
8999

90-
{ !jwtExpired && hdr ? hdr : '' /* Above-chosen header, or if logged out, no header */ }
91100

92101
{ /* If not logged in, show login screen */
93102
(!access_token | jwtExpired) ? <Login setToken={setToken} /> : <Switch>
@@ -113,13 +122,18 @@ function AuthenticatedApp() {
113122
<Search360/>
114123
</Route>
115124

116-
<Route path="/360view/view">
117-
<View360/>
118-
</Route>
125+
<Route path="/360view/view">
126+
<View360/>
127+
</Route>
128+
129+
<Route path="/check">
130+
<Check access_token = {access_token}/>
131+
</Route>
119132

120-
<Route path="/check">
121-
<Check />
133+
<Route path="/ref">
134+
<Refresh />
122135
</Route>
136+
123137
</Switch>
124138
}
125139

src/client/src/components/Login/useToken.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export default function useToken() {
44
const getToken = () => {
55
const tokenString = sessionStorage.getItem('access_token'); // getItem(key)
66
const userToken = JSON.parse(tokenString);
7+
78
return userToken?.access_token
89
};
910

src/client/src/components/Refresh.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
export default async function Refresh(old_token) {
2+
3+
// Use exisiting token to get a new fresh token
4+
5+
const new_at = await fetch('http://localhost:5000/api/user/refresh',
6+
{
7+
method: 'GET',
8+
headers: {
9+
'Content-Type': 'application/json',
10+
'Authorization': 'Bearer ' + old_token
11+
}
12+
})
13+
14+
.then((response) => {
15+
if (!response.ok) {
16+
//throw (String(response.status + ':' + response.statusText))
17+
throw (response)
18+
}
19+
return response.json()
20+
} )
21+
22+
.catch((e) => {
23+
// If it failed there's not much to do, probably got here after expiration
24+
return '{}'
25+
});
26+
27+
28+
return(new_at);
29+
30+
}
31+
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import React from 'react';
2+
import Button from '@material-ui/core/Button';
3+
import Dialog from '@material-ui/core/Dialog';
4+
import DialogActions from '@material-ui/core/DialogActions';
5+
import DialogContent from '@material-ui/core/DialogContent';
6+
import DialogContentText from '@material-ui/core/DialogContentText';
7+
import DialogTitle from '@material-ui/core/DialogTitle';
8+
9+
import useToken from './Login/useToken';
10+
11+
import Refresh from './Refresh';
12+
13+
export default function RefreshDlg(props) {
14+
const [open, setOpen] = React.useState(props.shouldOpen);
15+
const { access_token } = useToken(); // We want to use the passed-in top-level setToken
16+
17+
const handleClose = async (shouldRefresh) => {
18+
// Could be closed with Yes, No, outclick (which equals No)
19+
setOpen(false);
20+
if (props.shouldOpen){
21+
const new_at = await Refresh(access_token);
22+
props.setToken(new_at);
23+
}
24+
};
25+
26+
27+
28+
return (
29+
<div>
30+
<Dialog
31+
open={open}
32+
onClose={() => handleClose(false)}
33+
aria-labelledby="alert-dialog-title"
34+
aria-describedby="alert-dialog-description"
35+
>
36+
<DialogTitle id="alert-dialog-title">{"You are about to be logged out!"}</DialogTitle>
37+
<DialogContent>
38+
<DialogContentText id="alert-dialog-description">
39+
Stay logged in to keep working?
40+
</DialogContentText>
41+
</DialogContent>
42+
<DialogActions>
43+
<Button onClick={() => handleClose(false)} color="primary">
44+
No
45+
</Button>
46+
<Button onClick={() => handleClose(true)} color="primary" autoFocus>
47+
Yes
48+
</Button>
49+
</DialogActions>
50+
</Dialog>
51+
</div>
52+
);
53+
}

src/client/src/pages/Check/Check.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ var jwt = require('jsonwebtoken');
66
// const { DateTime } = require("luxon"); /* Enable if you enable console logging below */
77

88

9-
export default function Check() {
9+
export default function Check({access_token}) {
1010

11-
const { access_token, setToken } = useToken();
11+
const { setToken } = useToken();
1212

1313
const [processStatus, setProcessStatus] = React.useState('loading');
1414
const [error, setError] = React.useState('');

src/server/app.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
app.config["JWT_MAX_TIMEOUT"] = 7200 #Seconds
1414

1515
# We'll use max for default but can be reduced for testing
16-
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = app.config["JWT_MAX_TIMEOUT"]
16+
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = 60 # app.config["JWT_MAX_TIMEOUT"]
1717

1818
jwt = JWTManager(app)
1919

0 commit comments

Comments
 (0)