Skip to content

Commit

Permalink
Migrate to server-side flow instead
Browse files Browse the repository at this point in the history
Thanks Google for making me waste half my day on this unnecessary
work. Really appreciate it.

google/google-api-javascript-client#260
#21
  • Loading branch information
raxod502 committed Feb 6, 2021
1 parent 03c97db commit 1984f1c
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 50 deletions.
5 changes: 5 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ def get_index():
return flask.render_template("dist/index.html", analytics_enabled=ANALYTICS_ENABLED)


@app.route("/oauth")
def get_oauth_redirect():
return flask.send_file("dist/oauth.html")


@app.route("/admin")
def get_admin():
if ADMIN_ENABLED:
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"redux-thunk": "^2.3.0",
"regenerator-runtime": "^0.13.3",
"reselect": "^4.0.0",
"usa-states": "^0.0.5"
"usa-states": "^0.0.5",
"uuid": "^8.3.2"
},
"babel": {
"plugins": [
Expand Down
1 change: 0 additions & 1 deletion static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
// has been fixed, but clearly not.
console.clear = () => {};
</script>
<script defer src="https://apis.google.com/js/api.js"></script>
<script
defer
src="https://api.tiles.mapbox.com/mapbox-gl-js/v1.6.1/mapbox-gl.js"
Expand Down
7 changes: 0 additions & 7 deletions static/js/index/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,7 @@ function cleanResponses(responses) {
export const fetchAction = thunk(async (dispatch) => {
dispatch({ type: "FETCHING_DATA" });

// Skip getting OAuth token if it is already stored as a cookie
let oauthToken = Cookies.get("oauthToken");
if (oauthToken === undefined) {
const GoogleAuth = gapi.auth2.getAuthInstance();
oauthToken = GoogleAuth.currentUser.get().getAuthResponse().id_token;
// OAuth tokens are persisted in cookies for one month
Cookies.set("oauthToken", oauthToken, { expires: 31 });
}
const response = await fetch("/api/v1/data", {
method: "POST",
headers: {
Expand Down
73 changes: 32 additions & 41 deletions static/js/index/oauth.js
Original file line number Diff line number Diff line change
@@ -1,63 +1,54 @@
"use strict";

import Cookies from "js-cookie";
import { v4 as getUUID } from "uuid";

import { fetchAction } from "./api";
import { thunk } from "./util";

// Check if the session is currently authenticated with the necessary
// permissions. If it is and the UI is currently in an OAuth state,
// move on to fetching the API data. If the UI has already moved on
// from the OAuth states, do nothing. If the session isn't
// authenticated, display the login screen so the user can trigger an
// OAuth flow.
const oauthCheckAuthAction = thunk((dispatch) => {
dispatch({ type: "VERIFYING_OAUTH" });

// Only get auth instances if OAuth token isn't in cookie
if (Cookies.get("oauthToken") === undefined) {
const GoogleAuth = gapi.auth2.getAuthInstance();
if (GoogleAuth.currentUser.get().hasGrantedScopes("email")) {
dispatch(fetchAction);
} else {
dispatch({ type: "PROMPT_FOR_LOGIN" });
}
} else {
dispatch(fetchAction);
}
});

// Set up OAuth, check auth status, and arrange for auth status to be
// re-checked when the Google client library says the user has logged
// in.
export const oauthSetupAction = thunk(async (dispatch) => {
dispatch({ type: "VERIFYING_OAUTH" });

// Only get auth instances if OAuth token isn't in cookie
if (Cookies.get("oauthToken") === undefined) {
// https://developers.google.com/identity/protocols/OAuth2UserAgent
await new Promise((resolve) => gapi.load("client:auth2", resolve));
await gapi.client.init({
clientId:
"548868103597-3th6ihbnejkscon1950m9mm31misvhk9.apps.googleusercontent.com",
scope: "email",
});
const GoogleAuth = gapi.auth2.getAuthInstance();
GoogleAuth.isSignedIn.listen(() => dispatch(oauthCheckAuthAction));
dispatch(oauthCheckAuthAction);
dispatch({ type: "PROMPT_FOR_LOGIN" });
} else {
dispatch(oauthCheckAuthAction);
dispatch(fetchAction);
}
});

// Start the OAuth login flow, and update the UI to have some helpful
// info in case the user closes the popup.
export const oauthLoginAction = thunk(async (dispatch) => {
dispatch({ type: "WAIT_FOR_LOGIN" });
const GoogleAuth = gapi.auth2.getAuthInstance();
try {
await GoogleAuth.signIn({ prompt: "select_account" });
} catch (error) {
// e.g., user closed login popup

// https://developers.google.com/identity/protocols/oauth2/javascript-implicit-flow#javascript-sample-code
//
// We're making a GET request using a <form> element because... some
// kind of bizarre hack around CORS restrictions? Dunno, that's what
// Google told me to do.

const form = document.createElement("form");
form.setAttribute("method", "GET");
form.setAttribute("action", "https://accounts.google.com/o/oauth2/v2/auth");

const params = {
client_id:
"548868103597-3th6ihbnejkscon1950m9mm31misvhk9.apps.googleusercontent.com",
redirect_uri: document.location.origin + "/oauth",
response_type: "id_token",
nonce: getUUID(),
scope: "email",
};

for (const [key, value] of Object.entries(params)) {
const input = document.createElement("input");
input.setAttribute("type", "hidden");
input.setAttribute("name", key);
input.setAttribute("value", value);
form.appendChild(input);
}

document.body.appendChild(form);
form.submit();
});
11 changes: 11 additions & 0 deletions static/js/oauth/redirect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"use strict";

import Cookies from "js-cookie";

const oauthToken = new URLSearchParams(
decodeURIComponent(document.location.hash.slice(1)),
).get("id_token");

Cookies.set("oauthToken", oauthToken, { expires: 999999 });

window.location.replace("/");
8 changes: 8 additions & 0 deletions static/oauth.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Redirecting...</title>
</head>
<script defer src="./js/oauth/redirect.js"></script>
</html>
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6455,6 +6455,11 @@ uuid@^3.3.2:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866"
integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==

uuid@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==

v8-compile-cache@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e"
Expand Down

0 comments on commit 1984f1c

Please sign in to comment.