Skip to content

Commit bd6c0ae

Browse files
authored
Merge pull request #7 from es-hackathon/feature/0auth
Feature/0auth
2 parents 4cf51eb + 7471de0 commit bd6c0ae

File tree

10 files changed

+782
-30
lines changed

10 files changed

+782
-30
lines changed

package-lock.json

Lines changed: 593 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
"@testing-library/jest-dom": "^4.2.4",
77
"@testing-library/react": "^9.5.0",
88
"@testing-library/user-event": "^7.2.1",
9+
"auth0-js": "^9.13.4",
10+
"auth0-lock": "^11.25.1",
911
"axios": "^0.20.0",
1012
"bootstrap": "^4.5.2",
1113
"multiselect-react-dropdown": "^1.5.7",
1214
"prop-types": "^15.7.2",
15+
"jwks-rsa": "^1.3.0",
1316
"react": "^16.13.1",
1417
"react-datepicker": "^3.1.3",
1518
"react-dom": "^16.13.1",

src/components/App.js

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { Component } from 'react';
22
import { Route, Switch } from "react-router-dom";
33
import HomePage from "./home/HomePage";
44
import AboutPage from "./about/AboutPage";
@@ -11,26 +11,45 @@ import "react-toastify/dist/ReactToastify.css";
1111
import GroupsPage from "./groups/GroupsPage";
1212
import ManageGroupPage from './groups/ManageGroupPage';
1313
import CardView from "./cardview/cardview";
14+
import AuthContext from "./AuthContext";
15+
import Auth from './auth/Auth';
16+
import Callback from './Callback';
1417

15-
function App() {
16-
return (
18+
class App extends Component {
19+
20+
constructor(props) {
21+
super(props);
22+
this.state = {
23+
auth: new Auth(this.props.history),
24+
25+
};
26+
}
27+
28+
render() {
29+
const { auth } = this.state;
30+
return (
31+
<AuthContext.Provider value={auth}>
1732
<div className="container-fluid padding-align ">
18-
<Header />
33+
<Header auth={auth} />
1934
<Switch>
20-
<Route exact path="/" component={HomePage} />
21-
<Route exact path="/about" component={AboutPage} />
22-
<Route exact path="/groups" component={GroupsPage} />
23-
<Route exact path="/group/:id" component={ManageGroupPage} />
24-
<Route exact path="/group" component={ManageGroupPage} />
25-
<Route exact path="/cards" component={CardPage} />
26-
<Route exact path="/card/:id" component={ManageCardPage} />
27-
<Route exact path="/card" component={ManageCardPage} />
28-
<Route exact path="/cardview/:id" component={CardView} />
29-
<Route exact component={PageNotFound} />
35+
<Route exact path="/home" auth={auth} component={HomePage} />
36+
<Route path="/callback"
37+
render={props => <Callback auth={auth} {...props} />}/>
38+
<Route exact auth={auth} path="/" component={AboutPage} />
39+
<Route exact auth={auth} path="/groups" component={GroupsPage} />
40+
<Route exact auth={auth} path="/group/:id" component={ManageGroupPage} />
41+
<Route exact auth={auth} path="/group" component={ManageGroupPage} />
42+
<Route exact auth={auth} path="/cards" component={CardPage} />
43+
<Route exact auth={auth} path="/card/:id" component={ManageCardPage} />
44+
<Route exact auth={auth} path="/card" component={ManageCardPage} />
45+
<Route exact auth={auth} path="/cardview/:id" component={CardView} />
46+
<Route exact auth={auth} component={PageNotFound} />
3047
</Switch>
3148
<ToastContainer autoClose={3000} hideProgressBar />
3249
</div>
50+
</AuthContext.Provider>
3351
);
52+
}
3453
}
3554

3655
export default App;

src/components/AuthContext.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import React from "react";
2+
const AuthContext = new React.createContext();
3+
export default AuthContext;

src/components/Callback.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React, { Component } from 'react'
2+
3+
class Callback extends Component {
4+
5+
componentDidMount() {
6+
7+
if (/access_token|id_token|error/.test(this.props.location.hash)) {
8+
this.props.auth.handleAuthentication();
9+
}
10+
else {
11+
// throw new Error("Invalid callback URL")
12+
console.log("Invalid callback URL")
13+
// alert("Invalid callback URL")
14+
}
15+
}
16+
17+
render() {
18+
return (
19+
<h1>Loading...</h1>
20+
)
21+
}
22+
}
23+
24+
export default Callback;

src/components/about/AboutPage.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import React, { Component } from 'react'
33
class AboutPage extends Component {
44
render() {
55
return (
6-
<div>
6+
<div className="home-page">
77
<h2>About</h2>
88
<p>
9-
Bookmark application
9+
Bookmark-Dashboard which help to bookmark URL based on to group in terms of tribes, feature teams, platforms or application
1010
</p>
1111
</div>
1212
)

src/components/auth/Auth.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import auth0 from "auth0-js";
2+
3+
const REDIRECT_ON_LOGIN = "redirect_on_login";
4+
5+
let _expiresAt = null;
6+
7+
export default class Auth {
8+
constructor(history) {
9+
this.history = history;
10+
this.userProfile = null;
11+
this.requestedScopes = "openid profile email read:courses";
12+
this.auth0 = new auth0.WebAuth({
13+
domain: process.env.REACT_APP_AUTH0_DOMAIN,
14+
clientID: process.env.REACT_APP_AUTH0_CLIENT_ID,
15+
redirectUri: process.env.REACT_APP_AUTH0_CALLBACK_URL,
16+
audience: process.env.REACT_APP_AUTH0_AUDIENCE,
17+
responseType: "token id_token",
18+
scope: this.requestedScopes
19+
});
20+
}
21+
22+
login = () => {
23+
localStorage.setItem(REDIRECT_ON_LOGIN, JSON.stringify(this.history.location))
24+
this.auth0.authorize();
25+
}
26+
27+
handleAuthentication = () => {
28+
this.auth0.parseHash((err, authResult) => {
29+
if (authResult && authResult.accessToken && authResult.idToken) {
30+
this.setSession(authResult);
31+
const redirectLocation =
32+
localStorage.getItem(REDIRECT_ON_LOGIN) === "undefined"
33+
? "/" :
34+
JSON.parse(localStorage.getItem(REDIRECT_ON_LOGIN))
35+
this.history.push(redirectLocation); // redirect to home page
36+
}
37+
else if (err) {
38+
this.history.push("/");
39+
alert(`Error: ${err.error}`);
40+
}
41+
localStorage.removeItem(REDIRECT_ON_LOGIN);
42+
});
43+
};
44+
45+
setSession = authResult => {
46+
console.log(authResult);
47+
const expiresAt = JSON.stringify(
48+
authResult.expiresIn * 1000 + new Date().getTime()
49+
);
50+
51+
const scopes = authResult.scope || this.requestedScopes || "";
52+
53+
localStorage.setItem("access_token", authResult.accessToken);
54+
localStorage.setItem("id_token", authResult.idToken);
55+
localStorage.setItem("expires_at", expiresAt);
56+
localStorage.setItem("scopes", JSON.stringify(scopes));
57+
};
58+
59+
isAuthenticated() {
60+
const expiresAt = JSON.parse(localStorage.getItem("expires_at"));
61+
return new Date().getTime() < expiresAt;
62+
}
63+
64+
logout = () => {
65+
localStorage.removeItem("access_token");
66+
localStorage.removeItem("id_token");
67+
localStorage.removeItem("expires_at");
68+
localStorage.removeItem("scopes");
69+
70+
this.auth0.logout({
71+
clientID: process.env.REACT_APP_AUTH0_CLIENT_ID,
72+
returnTo: "http://localhost:3000"
73+
});
74+
};
75+
76+
getAccessToken = () => {
77+
const accessToken = localStorage.getItem("access_token");
78+
if (!accessToken) {
79+
throw new Error("No access token found.");
80+
}
81+
return accessToken;
82+
};
83+
84+
getProfile = cb => {
85+
if (this.userProfile) {
86+
cb(this.userProfile);
87+
}
88+
89+
this.auth0.client.userInfo(this.getAccessToken(), (err, profile) => {
90+
if (profile) {
91+
this.userProfile = profile;
92+
}
93+
cb(profile, err);
94+
});
95+
};
96+
97+
userHasScopes(scopes) {
98+
const grantedScopes = (
99+
JSON.parse(localStorage.getItem("scopes")) || ""
100+
).split(" ");
101+
return scopes.every(scope => grantedScopes.includes(scope));
102+
}
103+
}

src/components/common/Header.js

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,38 @@
11
import React, { Component } from 'react'
22
import { NavLink, Link } from "react-router-dom";
33

4-
const Header = () => {
4+
export default class Header extends Component {
5+
render() {
56
const activeStyle = { color: "#F15B2A" };
7+
const { isAuthenticated, login, logout, userHasScopes } = this.props.auth;
68
return (
79
<nav >
810
<ul>
11+
{isAuthenticated() && (
912
<li>
10-
<Link to="/" activestyle={activeStyle}>Home</Link>
13+
<Link to="/home" activestyle={activeStyle}>Home</Link>
1114
</li>
15+
)}
16+
{isAuthenticated() && (
1217
<li>
1318
<Link to="/cards" activestyle={activeStyle}>Cards</Link>
1419
</li>
20+
)}
21+
{isAuthenticated() && (
1522
<li>
1623
<Link to="/groups" activestyle={activeStyle}>Groups</Link>
1724
</li>
25+
)}
1826
<li>
19-
<Link to="/about" activestyle={activeStyle}>About</Link>
27+
<Link to="/" activestyle={activeStyle}>About</Link>
28+
</li>
29+
<li>
30+
<button onClick={isAuthenticated() ? logout : login}>
31+
{isAuthenticated() ? "Log Out" : "Log In"}
32+
</button>
2033
</li>
2134
</ul>
2235
</nav>
2336
);
24-
};
25-
26-
export default Header;
37+
}
38+
}

src/components/home/HomePage.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,6 @@ const HomePage = () => {
3535

3636
<div className="col-lg-4 ">
3737
<div className="form-group d-flex">
38-
{/* <label htmlFor="groupBySelect" className="col-form-label text-nowrap">Group by</label> */}
39-
{/* <select id="groupBySelect" className="form-control form-control-sm">
40-
<option value="date">date added</option>
41-
<option value="name">name</option>
42-
</select> */}
43-
4438
<SelectInput
4539
name="groupBySelect"
4640
label=""

src/index.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import React from 'react';
22
import ReactDOM from 'react-dom';
3+
import { BrowserRouter as Router, Route } from "react-router-dom";
34
import App from './components/App';
45
import * as serviceWorker from './serviceWorker';
5-
import { BrowserRouter as Router } from "react-router-dom";
6+
67
import "bootstrap/dist/css/bootstrap.min.css";
78
import "./index.css";
89
import configureStore from "./redux/configureStore";
@@ -14,7 +15,7 @@ ReactDOM.render(
1415
<React.StrictMode>
1516
<ReduxProvider store={store} >
1617
<Router>
17-
<App />
18+
<Route component={App} />
1819
</Router>
1920
</ReduxProvider>
2021
</React.StrictMode>,

0 commit comments

Comments
 (0)