DEV Community

Cover image for How we use a popup for Google and Outlook OAuth
Danielle
Danielle

Posted on • Originally published at blog.squarecat.io on

How we use a popup for Google and Outlook OAuth

At Leave Me Alone we use Google and Microsoft OAuth for user sign in. To do this we redirect the user to the relevant login page, the user input their details, and is then directed back to our site and logged in. An unfortunate result of this is that our analytics report a great deal of referral traffic coming from “accounts.google.com” and “login.microsoft.com”.

How we use a popup for Google and Outlook OAuth

To solve this problem, instead of redirecting it would be better if we could open a new window or popup for the OAuth flow. Also this is probably a better experience for the user than being redirected around.

How we implemented it

We use Passport for our authentication so when the user is directed back to our app after signing in the URL contains some parameters we need, including a token we use to authenticate them on our server.

Since we want to use a popup we need an additional step in the middle of the flow to catch that redirect, retrieve the URL parameters, close the popup, and use the token in the opening window (not the popup).

How we use a popup for Google and Outlook OAuth

We allow users to sign in with Google and Outlook and the implementation is the same for both. For ease of reading the example will use Google.

Step 1: Open the popup

To open a new window we use Window.open() with the passport login URL (/auth/google in our case) which opens the “Sign in to Leave Me Alone with Google” page in a new window. We also give the window a name and pass the requested features we want it to have.

We assign the window reference and record the previous URL so that the same window will be used or focused if the user tries to click the sign in button again, even if it’s for a different provider. We don’t want two popups for different providers floating around causing confusion.

Finally, we add an event listener for messages as the popup is going to send the URL parameters and auth token when it’s finished.

To get the window to open as a popup instead of a new tab we had to request the features menubar=no,toolbar=no.

Step 2: Get the OAuth callback parameters in the popup

When the OAuth flow is complete Google redirects the user to a callback URL. Usually this would be a server route which would perform the Passport authentication. Since the auth is happening in a popup we use a page in our app, which when which when loaded grabs the search parameters and sends them to the parent.

This callback page uses a React Use Effect Hook which executes when the page loads. We fetch the URL parameters which will include the auth token and send them to the opening window (the parent) using Window.postMessage().

Step 3: Authenticate the user and redirect to the app

The OAuth flow is almost complete the and the popup is now closed, we just need to authenticate the user on our server.

The receive message function needs to check the origin of the message to make sure it’s from the same domain for security. While coding this we realised that several Chrome developer tools use postMessage() from the same origin so we also check the source before trying to extract the payload.

Once we have the OAuth parameters, we redirect to the user to our own authentication endpoint o that we can use Passport to authenticate and login.

Finished!

The process is quite simple and all we have done here is add an intermediary step in the OAuth flow to pass through the callback parameters.

There are probably lots of implementations but this was the quickest and simplest for us using React.js.


Hopefully this helped you or provided some inspiration for your own solution.

Let us know if you have any questions or suggestions!

Top comments (11)

Collapse
 
jaymefrantz profile image
Jayme Frantz

Hi Danielle, I've using a modified version of your code in my nuxt project and it's about 90% there. However the issue I'm facing is while the google oauth popup is open my callback "receiveMessage" function is being called constantly. I've scattered logs around in the "openSignInWindow" function(and that's not being called in the same way), nor is my version of the "useEffect" function which is set up in my "mounted" vue hook. Can you please help me understand why my callback function is being called while this popup is open? Thanks in advance!

Collapse
 
joseat profile image
Jose Álvarez

Hello Danielle.

This article is awesome and i help full very much, but i have a question.
How can inplement this on vue or on native JS ? Because useEffect() is not available on JS only in React.
Thanks

Collapse
 
bl profile image
bl

@joseat Have you found the solution for Vue or native JS?

Collapse
 
barryrlmurphy profile image
Barry Murphy

I am currently doing an oauth integration using an Angular SPA, AWS Gateway and AWS Lambda. This article was really a lot of help with the third party consent flow. Because my app is a SPA I really didn't want to go off of the page where the user is taking the action. Thanks 👍

Collapse
 
ssimontis profile image
Scott Simontis

You could also exclude those sites as referrers to fix the analytics. This is good to know though, I can see a lot of uses for your solution!

Collapse
 
dinkydani21 profile image
Danielle

I realised that once I'd implemented the popup solution! But I think I prefer the popup now anyway :)

Collapse
 
philnash profile image
Phil Nash

I came across this article while trying to implement exactly this and it was a great help. Thank you!

Collapse
 
steeve profile image
Steeve

Thank you Danielle for this awesome article, you have helped me so much 🙏

Collapse
 
ferilevai profile image
ferilevai

Hi Danielle, I've using too a modified version of your code, but although I set the name for the popin, in message I receive data.source as undefined.

Collapse
 
danielsh28 profile image
danielsh28

Hi
great article!
just a little question:
where /when do we need to call openSignInWindow()?

Collapse
 
joseat profile image
Jose Álvarez

Hi Daniel.

You could call openSignInWindow(), for example on your login() button listening onClick event