JavaScript Callbacks

When using JavaScript callbacks, you provide a JavaScript function defined on your website that will be called by the native app after the user has logged in. The function is called with an object containing the token and other session details. If the user has cancelled the login process, the object will contain an error message.

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

Median JavaScript Bridge Methods and Parameters:

  • callback - the JavaScript function that will be called after the Social Login Plugin completes
  • scope - determines what data your app would like access to. Check the official documentation for each of the social logins for more information.

Callback object parameters

Facebook Success:

{
    accessToken: "token string",
    userId: "1234567890",
    type: "facebook",
}

Facebook Error:

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

Google Success:

{
    idToken: "token string",
    type: "google",
}

Google Error:

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

Apple Success:

{
    idToken: "token string",
    code: "code string",
    firstName: "first name" [1],
    lastName: "last name" [1],
    type: "apple",
}

🚧

[1] User profile only sent for initial login

Apple only returns a user's complete profile with fields such as firstName and lastName the first time the user authenticates for your app. You must securely save the user profile information for future purposes as subsequent authorization requests will only contain an identity token in the form of JSON Web Token (JWT), authorization code, and user identifier to your app. Parsing the JWT will return additional fields such as email, email_verified, etc. Refer to this documentation for more info.

Apple Error:

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

Facebook 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, the Median JavaScript Bridge endpoint is activated when the anchor tag is clicked. After the user has logged in, the facebookLoginCallback() function will be called with an object argument containing the user’s token. If the user has cancelled the login process, the object argument will contain an error message.

Once you have the user’s token, you can use it to retrieve the user’s Facebook profile. You can then pass this data to your backend server for processing.

Google Example:

<div class="browser-only">
    <div id="g_id_onload"
   	 data-client_id="1038895183581-fdapcj78i25hdmvnes300nuf17top0uf.apps.googleusercontent.com"
   	 data-callback="googleLoginCallback">
    </div>

    <div class="g_id_signin"
   	  data-type="standard"
   	  data-size="large"
   	  data-theme="outline"
   	  data-text="sign_in_with"
   	  data-shape="rectangular"
   	  data-logo_alignment="left">
    </div>
</div>

<button class="google-login native-only" onclick="median.socialLogin.google.login({ 'callback' : googleLoginCallback });">
    Log in With Google
</button>

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

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

    function googleLoginCallback(response) {
   	 console.log("Google Login Callback");

   	 let idToken;
   	 if (response.credential) {
   		 // browser-only
   		 idToken = response.credential;
   	 } else {
   		 // native-only
   		 idToken = response.idToken;
   	 }

   	 if (idToken) {
   		 const { payloadObj } = KJUR.jws.JWS.parse(idToken);
   		 if (payloadObj) {
   			 const { given_name, family_name, email, sub } = payloadObj;

   			 const payload = {
   				 email,
   				 first_name: given_name,
   				 last_name: family_name,
   				 provider_type: "google",
   				 provider_token: idToken,
   				 provider_uid: sub,
   			 }

   			 fetch("users/register", {
   				 method: "POST",
   				 headers: {
   					 "Content-Type": "application/json",
   				 },
   				 body: JSON.stringify(payload),
   			 }).then(
   					 (data) => data.json()
   			 ).then((data) => {
   				 handleResponse(data);
   			 }).catch((error) => {
   				 console.error(error);
   			 });
   		 }
   	 } else {
   		 console.log("User cancelled login or did not fully authorize.");
   	 }
    }
</script>

<script src="https://accounts.google.com/gsi/client" async defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jsrsasign/8.0.20/jsrsasign-all-min.js"></script>

In this example, the Median JavaScript Bridge endpoint is activated when the anchor tag is clicked. After the user has logged in, the googleLoginCallback() function will be called with an object argument containing the user’s ID token. If the user has cancelled the login process, the object argument will contain an error message.

Once you have the user’s token, you can decode it using any general-purpose JWT library. In this example, we are using jsrsasign to retrieve the email from the token. You can then pass the decoded data to your back-end server for processing.

Apple Example:

<head>
    <!-- other head tags -->

    <meta name="appleid-signin-client-id" content="INSERT CLIENT ID">
	<meta name="appleid-signin-scope" content="name email">
	<meta name="appleid-signin-redirect-uri" content="https://median-social-logins-demo.web.app/auth/apple/redirect">
	<meta name="appleid-signin-use-popup" content="true">
</head>

<body>
<div class="browser-only">
    	<div id="appleid-signin" data-color="black" data-border="true" data-type="sign in"></div>
</div>

<button class="apple-login native-only" onclick="median.socialLogin.apple.login({ 'callback' : appleLoginCallback, 'scope': 'full_name, email' });">
    	Log in With Apple
</button>

<script>
   	 function appleLoginCallback(response) {
        	console.log("Apple Login Callback");

        	let firstName;
        	let lastName;
        	let idToken;
        	if (response.detail) {
            	// browser-only
            	if (response.detail.authorization) {
    	                	idToken = response.detail.authorization.id_token;
            	}


            	// Only shows once Apple only returns 
            	// the user object the first time
            	// the user authorizes the app.
            	// Persist this information from your app;
            	// subsequent authorization requests won’t contain the
            	// user object.
            	if (response.detail.user && response.detail.user.name) {
    	                	firstName = response.detail.user.name.firstName;
    	                	lastName = response.detail.user.name.lastName;
            	}
        	} else {
            	// native-only
            	idToken = response.idToken;
            	firstName = response.firstName;
            	lastName = response.lastName;
        	}

        	if (idToken) {
            	const { payloadObj } = KJUR.jws.JWS.parse(idToken);
            	if (payloadObj) {
                	    	const { email, sub } = payloadObj;

    	                	const payload = {
          	              	email: email,
                	        	first_name: firstName,
                      	  	last_name: lastName,
                    	    	provider_type: "apple",
                    	    	provider_token: idToken,
                    	    	provider_uid: sub,
                	    	}

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

    	document.addEventListener("AppleIDSignInOnSuccess", appleLoginCallback);
    	document.addEventListener("AppleIDSignInOnFailure", appleLoginCallback);
</script>
</body>

In this example, the Median JavaScript Bridge endpoint is activated when the anchor tag is clicked. After the user has logged in, the appleLoginCallback() function will be called with an object argument containing the user’s ID token. If the user has cancelled the login process, the object argument will contain an error message.

Once you have the user’s token, you can decode it using any general-purpose JWT library. In this example, we are using jsrsasign to retrieve the email from the token. You can then pass the decoded data to your backend server for processing.

Note that the user's name can only be retrieved the first time the user authorizes the app for privacy reasons.