JavaScript Callbacks

Overview

This guide shows you how to implement social login using JavaScript callbacks with the Median JavaScript Bridge. This approach keeps everything in the browser and works well for single-page apps and client-side authentication flows.

How it works

JavaScript callbacks let you access authentication tokens directly in your webpage's JavaScript code, without URL redirects or server-side token validation.

Here's the flow:

  • A user clicks your login button, triggering the Median JavaScript Bridge
  • The native social login UI appears (Facebook, Google, or Apple)
  • After the user authenticates (or cancels), your JavaScript callback function runs
  • The callback receives an object with the authentication token and user details
  • You can immediately process this data client-side or send it to your backend

Before you start

You'll need:

  • The ability to process authentication tokens through JavaScript
  • Your social login providers already configured (Facebook, Google, or Apple)

Understanding the parameters

Each social login method accepts these parameters:

callback (required) — The JavaScript function that runs after login completes. It receives an object with the authentication token and user details.

scope (optional) — Defines what user data your app can access. Each provider has different scope options:

forceLimitedLogin (Facebook only) — Set to true to use Limited Login mode even when App Tracking Transparency is enabled.

nonce (Facebook only) — A string value used to verify the authenticity of the login when using Limited Login mode.

median.socialLogin.facebook.login({ 'callback' : <function>, 'scope' : '<text>', forceLimitedLogin: true | false, nonce: '<text>' });
median.socialLogin.google.login({ 'callback' : <function> });
median.socialLogin.apple.login({ 'callback' : <function>, 'scope' : '<text>' });

Provider-specific implementation

The following sections provide complete implementation details for each social login provider. Each section includes response objects, platform-specific requirements (where applicable), and a working code example. You can implement one or more providers based on your needs.

Response objects

Here's what your callback function receives for Facebook.

Success response

{
    "accessToken": "token string",
    "userId": "1234567890",
    "type": "facebook",
    "userDetails": {
      "userID": "<string>",
      "name": "<string>",
      "email": "<string>",
      "imageURL": "<string>",
      "friendIDs": "<string>",
      "birthday": "<string>",
      "ageRangeMin": "<number>",
      "ageRangeMax": "<number>",
      "hometown": "<string>",
      "location": "<string>",
      "gender": "<string>"
    },
    "authToken": "<limited-login-token>",
    "nonce": "<text>",
    "limitedLogin": true | false
}

Note: Keys in userDetails may be unavailable or null based on the scope you requested.

Error response

{
    "error": "error description",
    "type": "facebook"
}

Platform-specific requirements

Facebook on iOS

When users decline App Tracking Transparency (ATT), or tracking isn't enabled, Facebook uses "Limited Login" mode. You can also force this mode by setting forceLimitedLogin: true.

What changes in Limited Login mode:

  • The accessToken won't be returned
  • You'll get an authToken (a JWT) instead — this can't be used for Graph API calls
  • A nonce value is available to verify login authenticity
  • The limitedLogin key will be set to true

Read Facebook's documentation on validating Limited Login tokens

Implementation

Use the Median JavaScript Bridge method to trigger native login from your website. When a user clicks the button, the native login flow starts. After they authenticate, your callback function runs with the response object.

Here's an example:

<button class="facebook-login browser-only" onclick="facebookLogin()">
    Log In With Facebook
</button>

<button class="facebook-login native-only" 
  onclick="median.socialLogin.facebook.login({ 'callback' : facebookLoginCallback, 'scope' : 'public_profile, email' });">
    Log in With Facebook
</button>

<script>
    const isMedian = navigator.userAgent.indexOf("median") >= 0;

    if (isMedian) {
        // Remove browser-only buttons
        const elements = document.getElementsByClassName("browser-only")
        while(elements.length > 0) {
            elements[0].parentNode.removeChild(elements[0]);
        }
    } else {
        // Remove native-only buttons
        const elements = document.getElementsByClassName("native-only")
        while(elements.length > 0) {
            elements[0].parentNode.removeChild(elements[0]);
        }
    }

    function facebookLoginCallback(response) {
        console.log("Facebook Login Callback");

        let accessToken;
        if (response.status === "connected") {
            // browser-only
            accessToken = response.authResponse.accessToken;
        } else if (response.type === "facebook") {
            // native-only
            accessToken = response.accessToken;
        }

        if (accessToken) {
            FB.api("/me", "get", { fields: "id, email, first_name, last_name", access_token: accessToken }, function(response) {
                const { id, email, first_name, last_name } = response;

                const payload = {
                    email,
                    first_name,
                    last_name,
                    provider_type: "facebook",
                    provider_token: accessToken,
                    provider_uid: id,
                }

                // Call your backend's register endpoint
                fetch("users/register", {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                    },
                    body: JSON.stringify(payload),
                }).then(
                    (data) => data.json()
                ).then((data) => {
                    console.log("User is registered.");
                }).catch((error) => {
                    console.error(error);
                });
            })
        } else {
            console.log("User cancelled login or did not fully authorize.");
        }
    }

    function facebookLogin() {
        FB.login(function(response) {
            facebookLoginCallback(response);
        }, {
            scope: "email, public_profile",
        });
    }

    window.fbAsyncInit = function() {
        FB.init({
            appId            : "INSERT_FACEBOOK_APP_ID",
            autoLogAppEvents : true,
            xfbml            : true,
            version          : "v12.0"
        });
    };
</script>

<script async defer crossorigin="anonymous" src="https://connect.facebook.net/en_US/sdk.js"></script>

In this example, clicking the button activates the Median JavaScript Bridge and launches Facebook's native login. After the user authenticates, facebookLoginCallback() runs with an object containing the user's token. If they cancel, you'll get an error message instead.

Once you have the token, you can use it to fetch the user's Facebook profile. Then pass this data to your backend for processing.