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”.
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).
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 so that we can use Passport to authenticate and login.
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!