Skip to content

Instantly share code, notes, and snippets.

@Nithanim
Created May 6, 2021 10:26
Show Gist options
  • Save Nithanim/1c0d65be62292d2e30b8415b5c9e5f50 to your computer and use it in GitHub Desktop.
Save Nithanim/1c0d65be62292d2e30b8415b5c9e5f50 to your computer and use it in GitHub Desktop.
OAuth login via popup
// These are some methods from a VUE SFC serving as examples
// Called when user wants to login
private doLogin(provider: AvailableProvider) {
const popup = Login.openPopup();
if (popup == null) {
// Could fall back to full-redirect instead of popup, theoretically
alert("Please allow popups!");
} else {
popup.focus();
// This fetches the full OAuth auth url from the server (e.g. when different providers are used, or the client id is not known in the frontend)
// Since the redirect url (where the user is redirected after making his choice) is opened in the popup, it points to an html file that posts the js-message to our main window.
this.loginApi.oauthLoginStart1(provider.id).then(r => {
const url = r.data;
const w: Window = popup as Window;
w.document.body.innerText = "Redirecting to " + provider.name + "..."; // This is just a placeholder text shortly visible before the redirect kicks in. Could be fancier of course.
w.location.href = url;
});
}
}
private static openPopup() {
const w = 400;
const h = 600;
const y = window.top.outerHeight / 2 + window.top.screenY - h / 2;
const x = window.top.outerWidth / 2 + window.top.screenX - w / 2;
return window.open(
"",
"login-popup",
"menubar=no,toolbar=no,scrollbars=1,height=" +
h +
",width=" +
w +
",copyhistory=no,width=" +
w +
", height=" +
h +
", top=" +
y +
", left=" +
x
);
}
// These are some methods from a VUE SFC serving as examples
mounted() {
this.reset();
// Essentially only needed directly before auth process is started
// We want to be notified from the popup when the user returnes
window.addEventListener("message", this.windowMessageListener);
}
beforeDestroy() {
window.removeEventListener("message", this.windowMessageListener);
}
private windowMessageListener(event: MessageEvent): void {
// When a message is received for this window (our main window),
// we filter only for our popup events
if (event.data instanceof Object && event.data.type === "login-result") {
const result = event.data as Message;
this.loginStatus = result.data as OauthLoginResultStateEnum; // The popup tells us if the user authorized access to his account
this.updateAvailableProviders();
}
}
<!--
This is the popup html that is loaded after the user makes a choice at the oauth provider side.
It certainly could be designed fancier but from the technical side its only job is to tell the main page
if the user authorized our app or not.
So it just posts a message to the main window and then closes itself.
To not startle the user as much, a success message could be displayed for a couple of seconds before closing.
Paypal does that, for example, having a big green animated checkmark for a successful transaction.
To avoid having translation of the server side (which is most likely just an api),
it could be implemented that the main window takes control over the popup again and
writes the success page in there, completely replacing this generic html.
-->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Please wait...</title>
</head>
<body>
<script th:inline="javascript">
/*<![CDATA[*/
var message = {
type: "login-result",
data: [[${state}]]
};
window.opener.postMessage(message, "*");
window.close();
/*]]>*/
</script>
<script>
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment