aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Tuomi <jan.tuomi@eficode.com>2020-04-26 19:24:57 +0300
committerJan Tuomi <jan.tuomi@eficode.com>2020-04-26 19:24:57 +0300
commit7e057c8a56b51bdd7e95b3919d013ac0edd481e9 (patch)
treeafaeed8947e201102b80547f5105725a6fe383ce
parent449ebe5164ad9d2ba1e7d61bbae8e4101b703490 (diff)
Get user&pass and google auth working
-rw-r--r--docker-compose.yml4
-rw-r--r--frontend/package-lock.json51
-rw-r--r--frontend/package.json1
-rw-r--r--frontend/src/index.html19
-rw-r--r--frontend/src/login.html26
-rw-r--r--frontend/src/main.js39
-rw-r--r--login-service/package-lock.json31
-rw-r--r--login-service/package.json1
-rw-r--r--login-service/src/index.js35
9 files changed, 166 insertions, 41 deletions
diff --git a/docker-compose.yml b/docker-compose.yml
index 31b19f1..d73f254 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -34,6 +34,10 @@ services:
frontend:
build: ./frontend
+ environment:
+ GOOGLE_OAUTH_ID: ${GOOGLE_OAUTH_ID}
+ LOGIN_API_URL: http://localhost:4000
+ POSTGREST_API_URL: http://localhost:3000
depends_on:
- login_service
ports:
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index cab98f4..3fd9a1f 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -4,6 +4,27 @@
"lockfileVersion": 1,
"requires": true,
"dependencies": {
+ "@auth0/auth0-spa-js": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-1.7.0.tgz",
+ "integrity": "sha512-OAeNUI0bTBdk3cIWJMBLgf4B1DvyPXmbBBDQI7EpGR3pU0/+9d19sDCPC1b9epp6Aa7pnd4OR5u9JIQCc3eSKw==",
+ "requires": {
+ "abortcontroller-polyfill": "^1.4.0",
+ "browser-tabs-lock": "^1.2.8",
+ "core-js": "^3.6.4",
+ "es-cookie": "^1.3.2",
+ "fast-text-encoding": "^1.0.1",
+ "promise-polyfill": "^8.1.3",
+ "unfetch": "^4.1.0"
+ },
+ "dependencies": {
+ "core-js": {
+ "version": "3.6.5",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz",
+ "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA=="
+ }
+ }
+ },
"@babel/code-frame": {
"version": "7.8.3",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
@@ -1078,6 +1099,11 @@
"integrity": "sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg==",
"dev": true
},
+ "abortcontroller-polyfill": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/abortcontroller-polyfill/-/abortcontroller-polyfill-1.4.0.tgz",
+ "integrity": "sha512-3ZFfCRfDzx3GFjO6RAkYx81lPGpUS20ISxux9gLxuKnqafNcFQo59+IoZqpO2WvQlyc287B62HDnDdNYRmlvWA=="
+ },
"acorn": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz",
@@ -1537,6 +1563,11 @@
"integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==",
"dev": true
},
+ "browser-tabs-lock": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/browser-tabs-lock/-/browser-tabs-lock-1.2.8.tgz",
+ "integrity": "sha512-Xrj33YUTltPDoGrD1KnaAn5ZuxnnlJFcIW9srVTPHbMNPd9MlcnBCWaGV0STlvGKu8Ok0ad5qxyx5sIwFTr/Ig=="
+ },
"browserify-aes": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
@@ -2722,6 +2753,11 @@
}
}
},
+ "es-cookie": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/es-cookie/-/es-cookie-1.3.2.tgz",
+ "integrity": "sha512-UTlYYhXGLOy05P/vKVT2Ui7WtC7NiRzGtJyAKKn32g5Gvcjn7KAClLPWlipCtxIus934dFg9o9jXiBL0nP+t9Q=="
+ },
"es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
@@ -2998,6 +3034,11 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
+ "fast-text-encoding": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.2.tgz",
+ "integrity": "sha512-5rQdinSsycpzvAoHga2EDn+LRX1d5xLFsuNG0Kg61JrAT/tASXcLL0nf/33v+sAxlQcfYmWbTURa1mmAf55jGw=="
+ },
"fastparse": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
@@ -5827,6 +5868,11 @@
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"dev": true
},
+ "promise-polyfill": {
+ "version": "8.1.3",
+ "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.1.3.tgz",
+ "integrity": "sha512-MG5r82wBzh7pSKDRa9y+vllNHz3e3d4CNj1PQE4BQYxLme0gKYYBm9YENq+UkEikyZ0XbiGWxYlVw3Rl9O/U8g=="
+ },
"psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@@ -7015,6 +7061,11 @@
}
}
},
+ "unfetch": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.1.0.tgz",
+ "integrity": "sha512-crP/n3eAPUJxZXM9T80/yv0YhkTEx2K1D3h7D1AJM6fzsWZrxdyRuLN0JH/dkZh1LNH8LxCnBzoPFCPbb2iGpg=="
+ },
"unicode-canonical-property-names-ecmascript": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
diff --git a/frontend/package.json b/frontend/package.json
index 5c07804..05e2489 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -16,6 +16,7 @@
"parcel-bundler": "^1.12.4"
},
"dependencies": {
+ "@auth0/auth0-spa-js": "^1.7.0",
"axios": "^0.19.2",
"jquery": "^3.5.0",
"js-cookie": "^2.2.1"
diff --git a/frontend/src/index.html b/frontend/src/index.html
index f3e9d0e..7ffb08f 100644
--- a/frontend/src/index.html
+++ b/frontend/src/index.html
@@ -6,14 +6,23 @@
</head>
<body>
<div>
- <span>
- <a href="/index.html">Index</a>
- <a href="/login.html">Login</a>
- <a id="logout" href="">Logout</a>
- </span>
+ <button id="logout">Logout</button>
+ </div>
+ <div>
+ <form id="loginForm">
+ <label>Username
+ <input type="text" name="username" id="username">
+ </label>
+ <label>Password
+ <input type="password" name="password" id="password">
+ </label>
+ <button role="submit">Log in</button>
+ </form>
+ <button id="google-login">Login with Google</button>
</div>
<button id="fetchTodosBtn">Fetch TODOs</button>
<div id="todos"></div>
<script src="./main.js"></script>
+ <script src="https://apis.google.com/js/platform.js?onload=gapiInit" async defer></script>
</body>
</html> \ No newline at end of file
diff --git a/frontend/src/login.html b/frontend/src/login.html
deleted file mode 100644
index abae4f8..0000000
--- a/frontend/src/login.html
+++ /dev/null
@@ -1,26 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>PostgREST demo</title>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- </head>
- <body>
- <div>
- <span>
- <a href="/index.html">Index</a>
- <a href="/login.html">Login</a>
- <a id="logout" href="">Logout</a>
- </span>
- </div>
- <form id="loginForm">
- <label>Username
- <input type="text" name="username" id="username">
- </label>
- <label>Password
- <input type="password" name="password" id="password">
- </label>
- <button role="submit">Log in</button>
- </form>
- <script src="./main.js"></script>
- </body>
-</html> \ No newline at end of file
diff --git a/frontend/src/main.js b/frontend/src/main.js
index 79ed47e..3deeda3 100644
--- a/frontend/src/main.js
+++ b/frontend/src/main.js
@@ -3,10 +3,11 @@ import axios from 'axios';
import $ from 'jquery';
import cookie from 'js-cookie';
-const LOGIN_API_URL = 'http://localhost:4000';
-const POSTGREST_API_URL = 'http://localhost:3000';
+const LOGIN_API_URL = process.env.LOGIN_API_URL;
+const POSTGREST_API_URL = process.env.POSTGREST_API_URL;
+const GOOGLE_OAUTH_ID = process.env.GOOGLE_OAUTH_ID;
-$('a#logout').click(function(event) {
+$('button#logout').click(function(event) {
event.preventDefault();
cookie.remove('jwt');
alert('Logged out.');
@@ -29,8 +30,8 @@ $('button#fetchTodosBtn').click(async function() {
});
}
} catch (err) {
+ console.error(err);
$('div#todos').html(String(err));
- alert(err);
}
});
@@ -39,13 +40,37 @@ $('form#loginForm').submit(async function(event) {
const username = $(this).find('input#username').val();
const password = $(this).find('input#password').val();
try {
- const resp = await axios.post(`${LOGIN_API_URL}/login`, { username, password });
+ const resp = await axios.post(`${LOGIN_API_URL}/login/userpass`, { username, password });
const payload = resp.data;
- const jwt = payload.jwt;
+ const { jwt, displayName } = payload;
cookie.set('jwt', jwt);
- alert(`Logged in as ${username}.`);
+ alert(`Logged in as ${displayName}.`);
} catch (err) {
cookie.remove('jwt');
alert(err);
}
});
+
+$('button#google-login').click(async function() {
+ const GoogleAuth = gapi.auth2.getAuthInstance();
+ try {
+ const user = await GoogleAuth.signIn();
+ const authResponse = user.getAuthResponse(true);
+ const resp = await axios.post(`${LOGIN_API_URL}/login/google`, { accessToken: authResponse.access_token });
+ const payload = resp.data;
+ const { jwt, displayName } = payload;
+ cookie.set('jwt', jwt);
+ alert(`Logged in as ${displayName}.`);
+ } catch (err) {
+ console.error(err);
+ }
+});
+
+window.gapiInit = () => {
+ console.log('gapiInit');
+ gapi.load('auth2', function() {
+ gapi.auth2.init({
+ client_id: GOOGLE_OAUTH_ID,
+ });
+ });
+};
diff --git a/login-service/package-lock.json b/login-service/package-lock.json
index 0cc44b6..7af7e7d 100644
--- a/login-service/package-lock.json
+++ b/login-service/package-lock.json
@@ -93,6 +93,14 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
+ "axios": {
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.2.tgz",
+ "integrity": "sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==",
+ "requires": {
+ "follow-redirects": "1.5.10"
+ }
+ },
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@@ -542,6 +550,29 @@
}
}
},
+ "follow-redirects": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
+ "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
+ "requires": {
+ "debug": "=3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ }
+ }
+ },
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
diff --git a/login-service/package.json b/login-service/package.json
index 87f5bb6..0815794 100644
--- a/login-service/package.json
+++ b/login-service/package.json
@@ -15,6 +15,7 @@
"nodemon": "^2.0.3"
},
"dependencies": {
+ "axios": "^0.19.2",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1"
}
diff --git a/login-service/src/index.js b/login-service/src/index.js
index 0de5931..248c269 100644
--- a/login-service/src/index.js
+++ b/login-service/src/index.js
@@ -1,4 +1,5 @@
const express = require('express');
+const axios = require('axios');
var jwt = require('jsonwebtoken');
const app = express();
@@ -13,7 +14,17 @@ const port = 4000;
const JWT_SECRET = process.env.JWT_SECRET;
-const loginWithUsernameAndPassword = (username, password) => {
+const authorizeUserNamePassword = (username, password) => {
+ // TODO
+ const now = Math.round(new Date().getTime() / 1000);
+
+ return {
+ role: 'todo_user',
+ exp: now + 30 * 60, // 30 minutes
+ };
+};
+
+const authorizeGoogle = googleUser => {
// TODO
const now = Math.round(new Date().getTime() / 1000);
@@ -24,12 +35,30 @@ const loginWithUsernameAndPassword = (username, password) => {
};
app.get('/', (req, res) => res.send('Login service API'));
-app.post('/login', (req, res) => {
+
+// Username + Password login
+app.post('/login/userpass', (req, res) => {
const payload = req.body;
const { username, password } = payload;
const claims = loginWithUsernameAndPassword(username, password);
const signedJWT = jwt.sign(claims, JWT_SECRET);
- res.json({ jwt: signedJWT });
+ res.json({ jwt: signedJWT, displayName: username });
+});
+
+// Google access token login
+app.post('/login/google', async (req, res) => {
+ const payload = req.body;
+ const { accessToken } = payload;
+ try {
+ const resp = await axios.get(`https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=${accessToken}`);
+ const payload = resp.data;
+ const { email } = payload;
+ const claims = authorizeGoogle(payload);
+ const signedJWT = jwt.sign(claims, JWT_SECRET);
+ res.json({ jwt: signedJWT, displayName: email });
+ } catch (err) {
+ console.error(err);
+ }
});
app.listen(port, () => console.log(`Listening at http://localhost:${port}`));