Skip to content

Commit 586bccd

Browse files
committed
Working authentication with Auth0
1 parent b6705fc commit 586bccd

File tree

9 files changed

+266
-43
lines changed

9 files changed

+266
-43
lines changed

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515
"@coreui/coreui": "^2.0.0-beta.10",
1616
"@coreui/coreui-plugin-chartjs-custom-tooltips": "^1.2.0",
1717
"@coreui/react": "^2.0.0-beta.1",
18+
"auth0-js": "^9.0.0",
19+
"auth0-lock": "^11.6.1",
1820
"bootstrap": "^4.1.0",
1921
"chart.js": "^2.7.2",
2022
"classnames": "^2.2.5",
2123
"flag-icon-css": "^3.0.0",
2224
"font-awesome": "^4.7.0",
25+
"history": "^4.6.1",
2326
"prop-types": "^15.6.1",
2427
"react": "^16.3.2",
2528
"react-chartjs-2": "^2.7.0",
@@ -39,7 +42,7 @@
3942
"scripts": {
4043
"build-css": "node-sass-chokidar --include-path ./node_modules ./src/scss -o ./src/scss",
4144
"watch-css": "npm run build-css && node-sass-chokidar --include-path ./node_modules ./src/scss -o ./src/scss --watch --recursive",
42-
"start-js": "PORT=3006 react-scripts start",
45+
"start-js": "PORT=3013 react-scripts start",
4346
"start": "npm-run-all -p watch-css start-js",
4447
"build-js": "react-scripts build",
4548
"build": "npm-run-all build-css build-js",

src/App.js

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { Component } from 'react';
2-
import { HashRouter, Route, Switch } from 'react-router-dom';
2+
import { Router, Route, Switch } from 'react-router-dom';
33
import './App.css';
44
// Styles
55
// Import Flag Icons Set
@@ -19,18 +19,38 @@ import { Login, Page404, Page500, Register } from './views/Pages';
1919

2020
// import { renderRoutes } from 'react-router-config';
2121

22+
// auth0
23+
import { Redirect} from 'react-router-dom';
24+
import Callback from './Callback/Callback';
25+
import Auth from './Auth/Auth';
26+
import history from './history';
27+
28+
const auth = new Auth();
29+
30+
const handleAuthentication = ({___location}) => {
31+
if (/access_token|id_token|error/.test(___location.hash)) {
32+
auth.handleAuthentication();
33+
}
34+
};
35+
2236
class App extends Component {
2337
render() {
2438
return (
25-
<HashRouter>
39+
<Router history={history}>
2640
<Switch>
27-
<Route exact path="/login" name="Login Page" component={Login} />
28-
<Route exact path="/register" name="Register Page" component={Register} />
41+
{/*<Route exact path="/login" name="Login Page" component={Login} />*/}
42+
{/*<Route exact path="/register" name="Register Page" component={Register} />*/}
2943
<Route exact path="/404" name="Page 404" component={Page404} />
3044
<Route exact path="/500" name="Page 500" component={Page500} />
31-
<Route path="/" name="Home" component={Full} />
45+
<Route path="/callback" render={(props) => {
46+
handleAuthentication(props);
47+
return <Callback {...props} />
48+
}}/>
49+
<Route path="/" name="Home" render={(props) =>{
50+
return <Full auth={auth} {...props} />}
51+
}/>
3252
</Switch>
33-
</HashRouter>
53+
</Router>
3454
);
3555
}
3656
}

src/Auth/Auth.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import auth0 from 'auth0-js';
2+
import { AUTH_CONFIG } from './auth0-variables';
3+
import history from '../history';
4+
5+
export default class Auth {
6+
auth0 = new auth0.WebAuth({
7+
___domain: AUTH_CONFIG.___domain,
8+
clientID: AUTH_CONFIG.clientId,
9+
redirectUri: AUTH_CONFIG.callbackUrl,
10+
audience: AUTH_CONFIG.apiUrl,
11+
// responseType: 'token id_token',
12+
responseType: 'code',
13+
scope: 'openid profile read:messages'
14+
});
15+
16+
userProfile;
17+
18+
constructor() {
19+
this.login = this.login.bind(this);
20+
this.logout = this.logout.bind(this);
21+
this.handleAuthentication = this.handleAuthentication.bind(this);
22+
this.isAuthenticated = this.isAuthenticated.bind(this);
23+
this.getAccessToken = this.getAccessToken.bind(this);
24+
this.getProfile = this.getProfile.bind(this);
25+
}
26+
27+
login() {
28+
this.auth0.authorize();
29+
}
30+
31+
handleAuthentication() {
32+
console.log('called handleAuthentication');
33+
this.auth0.parseHash((err, authResult) => {
34+
if (authResult && authResult.accessToken && authResult.idToken) {
35+
this.setSession(authResult);
36+
history.replace('/');
37+
} else if (err) {
38+
history.replace('/');
39+
console.log(err);
40+
alert(`Error: ${err.error}. Check the console for further details.`);
41+
}
42+
});
43+
}
44+
45+
setSession(authResult) {
46+
console.log('called setSession');
47+
// Set the time that the access token will expire at
48+
let expiresAt = JSON.stringify(
49+
authResult.expiresIn * 1000 + new Date().getTime()
50+
);
51+
localStorage.setItem('access_token', authResult.accessToken);
52+
localStorage.setItem('id_token', authResult.idToken);
53+
localStorage.setItem('expires_at', expiresAt);
54+
// navigate to the home route
55+
history.replace('/home');
56+
}
57+
58+
getAccessToken() {
59+
const accessToken = localStorage.getItem('access_token');
60+
if (!accessToken) {
61+
throw new Error('No access token found');
62+
}
63+
return accessToken;
64+
}
65+
66+
getProfile(cb) {
67+
let accessToken = this.getAccessToken();
68+
this.auth0.client.userInfo(accessToken, (err, profile) => {
69+
if (profile) {
70+
this.userProfile = profile;
71+
}
72+
cb(err, profile);
73+
});
74+
}
75+
76+
logout() {
77+
// Clear access token and ID token from local storage
78+
localStorage.removeItem('access_token');
79+
localStorage.removeItem('id_token');
80+
localStorage.removeItem('expires_at');
81+
this.userProfile = null;
82+
// navigate to the home route
83+
history.replace('/home');
84+
}
85+
86+
isAuthenticated() {
87+
// Check whether the current time is past the
88+
// access token's expiry time
89+
let expiresAt = JSON.parse(localStorage.getItem('expires_at'));
90+
return new Date().getTime() < expiresAt;
91+
}
92+
}

src/Auth/auth0-variables.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export const AUTH_CONFIG = {
2+
___domain: 'drivemotors.auth0.com',
3+
clientId: 'pfLIwsWrtUoFg63I5o7k3JPS7hOAB1cf',
4+
callbackUrl: 'http://localhost:3013',
5+
apiUrl: 'https://dev.drive:3000'
6+
}

src/Callback/Callback.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import React, { Component } from 'react';
2+
import loading from './loading.svg';
3+
4+
class Callback extends Component {
5+
render() {
6+
const style = {
7+
position: 'absolute',
8+
display: 'flex',
9+
justifyContent: 'center',
10+
height: '100vh',
11+
width: '100vw',
12+
top: 0,
13+
bottom: 0,
14+
left: 0,
15+
right: 0,
16+
backgroundColor: 'white',
17+
}
18+
19+
return (
20+
<div style={style}>
21+
<img src={loading} alt="loading"/>
22+
</div>
23+
);
24+
}
25+
}
26+
27+
export default Callback;

src/Callback/loading.svg

Lines changed: 1 addition & 0 deletions
Loading

src/containers/Full/Full.js

Lines changed: 100 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -22,43 +22,108 @@ import FullAside from './FullAside';
2222
import FullFooter from './FullFooter';
2323
import FullHeader from './FullHeader';
2424

25+
import { Auth0Lock} from 'auth0-lock';
26+
import history from '../../history';
27+
import Auth from "../../Auth/Auth";
28+
2529
class Full extends Component {
30+
constructor(props){
31+
super(props);
32+
console.log('Full constructor');
33+
this.lock = new Auth0Lock(
34+
'pfLIwsWrtUoFg63I5o7k3JPS7hOAB1cf',
35+
'drivemotors.auth0.com',{
36+
theme:{
37+
logo: 'https://www.drivemotors.com/assets/logos/drive_logo_march_14.svg'
38+
}
39+
40+
}
41+
);
42+
this.lock.on("authenticated", function(authResult) {
43+
// Use the token in authResult to getUserInfo() and save it to localStorage
44+
console.log('called loked.on');
45+
console.log(this);
46+
this.getUserInfo(authResult.accessToken, function(error, profile) {
47+
if (error) {
48+
// Handle error
49+
console.log('error');
50+
console.log(error);
51+
return;
52+
}
53+
console.log(authResult);
54+
localStorage.setItem('accessToken', authResult.accessToken);
55+
localStorage.setItem('profile', JSON.stringify(profile));
56+
57+
const auth = new Auth();
58+
auth.setSession(authResult);
59+
console.log(auth.isAuthenticated());
60+
});
61+
});
62+
}
63+
64+
login() {
65+
// this.props.auth.login();
66+
this.lock.show();
67+
}
2668
render() {
27-
return (
28-
<div className="app">
29-
<AppHeader fixed>
30-
<FullHeader />
31-
</AppHeader>
32-
<div className="app-body">
33-
<AppSidebar fixed display="lg">
34-
<AppSidebarHeader />
35-
<AppSidebarForm />
36-
<AppSidebarNav navConfig={navigation} {...this.props} />
37-
<AppSidebarFooter />
38-
<AppSidebarMinimizer />
39-
</AppSidebar>
40-
<main className="main">
41-
<AppBreadcrumb appRoutes={routes}/>
42-
<Container fluid>
43-
<Switch>
44-
{routes.map((route, idx) => {
45-
return route.component ? (<Route key={idx} path={route.path} exact={route.exact} name={route.name} render={props => (
46-
<route.component {...props} />
47-
)} />)
48-
: (null);
49-
},
50-
)}
51-
<Redirect from="/" to="/dashboard" />
52-
</Switch>
53-
</Container>
54-
</main>
55-
<AppAside fixed hidden>
56-
<FullAside />
57-
</AppAside>
58-
</div>
59-
<AppFooter>
60-
<FullFooter />
61-
</AppFooter>
69+
const { isAuthenticated } = this.props.auth;
70+
console.log('render');
71+
console.log(this.props.auth.isAuthenticated());
72+
return (<div className="container">
73+
{
74+
isAuthenticated() && (
75+
<div className="app">
76+
<AppHeader fixed>
77+
<FullHeader auth={this.props.auth} />
78+
</AppHeader>
79+
<div className="app-body">
80+
<AppSidebar fixed display="lg">
81+
<AppSidebarHeader />
82+
<AppSidebarForm />
83+
<AppSidebarNav navConfig={navigation} {...this.props} />
84+
<AppSidebarFooter />
85+
<AppSidebarMinimizer />
86+
</AppSidebar>
87+
<main className="main">
88+
<AppBreadcrumb appRoutes={routes}/>
89+
<Container fluid>
90+
<Switch>
91+
{routes.map((route, idx) => {
92+
return route.component ? (<Route key={idx} path={route.path} exact={route.exact} name={route.name} render={props => (
93+
<route.component {...props} />
94+
)} />)
95+
: (null);
96+
},
97+
)}
98+
<Redirect from="/" to="/dashboard" />
99+
</Switch>
100+
</Container>
101+
</main>
102+
<AppAside fixed hidden>
103+
<FullAside />
104+
</AppAside>
105+
</div>
106+
<AppFooter>
107+
<FullFooter />
108+
</AppFooter>
109+
</div>
110+
)
111+
}
112+
{
113+
!isAuthenticated() && (
114+
<h4>
115+
You are not logged in! Please{' '}
116+
<a
117+
style={{ cursor: 'pointer' }}
118+
// onClick={this.login.bind(this)
119+
onClick={this.login.bind(this)}
120+
>
121+
Log In
122+
</a>
123+
{' '}to continue.
124+
</h4>
125+
)
126+
}
62127
</div>
63128
);
64129
}

src/containers/Full/FullHeader.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,17 @@ const propTypes = {
1111
const defaultProps = {};
1212

1313
class FullHeader extends Component {
14+
15+
logout() {
16+
this.props.auth.logout();
17+
}
18+
1419
render() {
1520

1621
// eslint-disable-next-line
1722
const { children, ...attributes } = this.props;
1823

24+
1925
return (
2026
<React.Fragment>
2127
<AppSidebarToggler className="d-lg-none" display="md" mobile />
@@ -63,7 +69,7 @@ class FullHeader extends Component {
6369
<DropdownItem><i className="fa fa-file"></i> Projects<Badge color="primary">42</Badge></DropdownItem>
6470
<DropdownItem divider />
6571
<DropdownItem><i className="fa fa-shield"></i> Lock Account</DropdownItem>
66-
<DropdownItem><i className="fa fa-lock"></i> Logout</DropdownItem>
72+
<DropdownItem onClick={this.logout.bind(this)}><i className="fa fa-lock"></i> Logout</DropdownItem>
6773
</DropdownMenu>
6874
</AppHeaderDropdown>
6975
</Nav>

src/history.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import createHistory from 'history/createBrowserHistory'
2+
3+
export default createHistory()

0 commit comments

Comments
 (0)