Search code examples
node.jsmongodbfacebookoauthmongodb-stitch

MongoDB Stitch double encodes redirect URI during Facebook login attempt breaking the login process?


I am trying to use the MongoDB Stitch examples tutorial for the Web based Todo App. I am using Node.JS v10.14.2 on a Ubuntu 18.04 Bionic Beaver Linux station.

When I try to log in with Facebook, the login process fails with Facebook complaining that the redirect URL generated by the Stitch server is not whitelisted, and therefore has been rejected during the attempt to login into Facebook with OAuth. The URL is generated during this code block found in this Node module:

node_modules/mongodb-stitch-browser-core/dist/cjs/core/auth/internal/StitchAuthImpl.js

Here is the code that generates the URL that starts the login process. It calls the Stitch server and the Stitch server generates the correct URL to ask Facebook to login the user. Note, I did modify the code but only to show me the value the getAuthProviderRedirectRoute() call was generating. No other changes were made.

   StitchAuthImpl.prototype.loginWithRedirect = function (credential) {
        var _this = this;
        var _a = this.prepareRedirect(credential), redirectUrl = _a.redirectUrl, state = _a.state;
        this.requestClient.getBaseURL().then(function (baseUrl) {
            // ROS: We want to see the URL being created - ESM.
            let replaceUrl = baseUrl +
                _this.browserAuthRoutes.getAuthProviderRedirectRoute(credential, redirectUrl, state, _this.deviceInfo);
            _this.jsdomWindow.location.replace(replaceUrl);
        });
    };

Here is the value of replaceUrl that shows the URL that was generated at this initial stage of the Facebook login process:

   replaceUrl = https://stitch.mongodb.com/api/client/v2.0/app/my_stitch_app/auth/providers/oauth2-facebook/login?redirect=http://localhost:8001/&state=<<redacted>>&device=<<redacted>>

Stitch generates this URL for the start of the OAuth Facebook login handshake. As you can see from the code this URL is loaded into the browser's location. The stitch server then generates the URL for the next leg of the OAuth handshake. I have excerpted the redirect_uri query argument from the URL it generates and transfers control to, shown here:

redirect_uri%3Dhttps%253A%252F%252Fstitch.mongodb.com%252Fapi%252Fclient%252Fv2.0%252Fauth%252Fcallback

I then manually decoded the redirect URI because it looked wrong. If you look at the redirect_uri query argument shown above, you will see that the OAuth callback URI has been double encoded with the encodeUri() method. This causes the Facebook OAuth server to reject the callback URI because after being decoded, it looks like the URL shown next to the DECODED ONCE label shown below.

This causes the OAuth handshake to fail because it does not match the URL that you see below marked with the label "DECODED AGAIN".

That value is what I put in the Facebook OAuth "Client OAuth Settings" page in the "Valid OAuth Redirect URIs" section as instructed to by the MongoDB Stitch tutorial. Since the URL has been double encoded, the redirect URI when decoded once, doesn't match the "DECODED AGAIN" value and the login process fails. Obviously I could add the "DECODED ONCE" value to the whitelisted URLs list, but that would just kick the problem down the road because it should look like the completely decoded value in "DECODED AGAIN".

DECODED ONCE:

redirect_uri=https%3A%2F%2Fstitch.mongodb.com%2Fapi%2Fclient%2Fv2.0%2Fauth%2Fcallback

DECODED AGAIN:

redirect_uri=https://stitch.mongodb.com/api/client/v2.0/auth/callback

To recapitulate, when Facebook is asked to login in the user with the URL generated by Stitch, shown below, Facebook fails the process with the error message also shown below:

https://www.facebook.com/login.php?skip_api_login=1&api_key=<<redacted>>&kid_directed_site=0&app_id=<<redacted>>%26redirect_uri%3Dhttps%253A%252F%252Fstitch.mongodb.com%252Fapi%252Fclient%252Fv2.0%252Fauth%252Fcallback

Facebook Error:

URL Blocked

This redirect failed because the redirect URI is not whitelisted in the app’s Client OAuth Settings. Make sure Client and Web OAuth Login are on and add all your app domains as Valid OAuth Redirect URIs.

I have scoured the MongoDB Stitch control panel and I don't see anywhere I may have entered something that would lead to the callback URL being passed to Facebook by Stitch, to be double-encoded. Can anyone tell me what could cause this unwanted behavior and how to fix this?


Solution

  • Thanks for the detailed explanation. I tried reproducing your issue but I was able to login with Facebook successfully.

    I also checked the URL that the Stitch server generates when redirecting to Facebook, and it was the exact same double-encoded URI you have in your post. This means that this behavior is expected and should not affect the login flow.

    If you look at the full URL, you'll see that the main url (starting at "https://www.facebook.com/login.php") has a query parameter called "next". The "next" parameter is a URL, so it needs to be URL-encoded. This URL passed to "next" has the "redirect_uri" parameter, which is also a URL, so it needs to be URL-encoded as well. Since this is a URL in a URL in a URL, this is why you see the double-encoding.

    I formatted the URL with each parameter on a new line, and each sub-URL intended to help demonstrate this:

    https://www.facebook.com/login.php
        ?skip_api_login=1
        &api_key=<redacted>
        &kid_directed_site=0
        &app_id=<redacted>
        &signed_next=1
        &next=https%3A%2F%2Fwww.facebook.com%2Fdialog%2Foauth
            %3Faccess_type%3Doffline
            %26client_id%<redacted>
    
            // this is the double encoded URL
            %26redirect_uri%3Dhttps%253A%252F%252Fstitch.mongodb.com%252Fapi%252Fclient%252Fv2.0%252Fauth%252Fcallback
    
            %26response_type%3Dcode
            %26scope%3Demail%2Bpublic_profile
            %26state%3D<redacted>
            %26ret%3Dlogin
            %26fallback_redirect_uri%<redacted>
        &cancel_url=https%3A%2F%2Fstitch.mongodb.com%2Fapi%2Fclient%2Fv2.0%2Fauth%2Fcallback
            %3Ferror%3Daccess_denied
            %26error_code%3D200
            %26error_description%3DPermissions%2Berror
            %26error_reason%3Duser_denied
            %26state%3D<redacted>
        &display=page&locale=en_US
    

    To get Facebook login working, I would ensure the following:

    • In the Facebook console, make sure this URL is added to the list of "Valid OAuth Redirect URIs":

    • In the Stitch console, make sure that your application URL is included in the list of "Redirect URIs" for the Facebook Provider. This should include any trailing slashes.

    • In your application code, make sure you are calling the following JS code when your redirect URL is hit. This allows the the Stitch client SDK to get the result of the OAuth2 flow performed by the Stitch server:

      if (yourStitchClient.auth.hasRedirectResult()) {
        return yourStitchClient.auth.handleRedirectResult().then(user => {
            console.log("Authenticated as user: " + user);
        });
      }
    

    Check out https://docs.mongodb.com/stitch/authentication/facebook/ for more explanation on these steps.

    If you're still having trouble getting this to work after the above steps, let me know and I'll try to help you debug the issue.