Outlook add-ins desktop - show google oauth 2 dialog - javascript

I'm trying to implement the functionality to log in with Google from the Outlook add-in. From the web version of outlook, everything working well, but from the desktop, I can't find a way how to open the Sign in with Google popout. Instead, it just opened a new tab on the browser.
https://developers.google.com/identity/sign-in/web/reference
code example:
gapi.auth2.authorize({
client_id: 'CLIENT_ID.apps.googleusercontent.com',
scope: 'email profile openid',
response_type: 'id_token permission'
}, function(response) {
if (response.error) {
// An error happened!
return;
}
// The user authorized the application for the scopes requested.
var accessToken = response.access_token;
var idToken = response.id_token;
// You can also now use gapi.client to perform authenticated requests.
});
I see that zoom add-in for outlook show this popup, so any idea how to do it?
Thanks!

In order for Oauth2 to work it should always open the login and consent screen in the users installed browser on their machine. This is to give the user the opportunity to check the url bar at the top of the page.
Without having the URL bar at the top of the page someone could create a page that looks like googles login and consent screens and then the user would be typing their login and password into a potentially malicious site.
As far as I know google has shut down all options of opening the consent screen in anything other than an installed browser. it wont even work in an IFrame last i checked.

Related

How to authorise user for a web page in FB messenger, without logging in?

I am building a chat bot in FB messenger that saves user profile data, food and calorie consumption. I am using Node/Express/MongoDB for the backend and want the user to be able to open a personal dashboard page inside the chat with a link. So that URL would be something like www.myapp.com/:id where :id is a personal key.
The problem I have is how can only the user belonging to this page and data open this without having to login? Normally you would go to a website, login and be able to see the page, but this not a step I want in a chat bot. I want the user just to open the page in the chat, whether that is results in opening a browser tab or a native webview. Any advice on how I can achieve this?
To verify if the user on the page is the facebook user you intend the page to be for, add FB Messenger Extensions to the page.
When clicking a webview in your bot, Messenger extensions will be able to tell who they are logged in as, and allow you to do whatever you want with that info. In your case, checking if the userid matches the one passed by your bot in the url. There are many ways to check this, like splitting query strings, but I stuck with the example route in your question.
Use the following on your dashboard page. The below will check with FB who the logged in user is, and if it doesn't match the ID of the link they followed, deny them access with a redirect.
<script>
MessengerExtensions.getContext(<YOUR-APP-ID>,
function success(thread_context){
// User ID was successfully obtained.
var psid = thread_context.psid;
// Grab the user id from your url (assumes your url is /<USER_ID>)
var loc = window.location.pathname.replace(/^\/|\/$/g, '');
if (psid !=== loc) {
window.location.replace("http://YOUR_DOMAIN.com/error")
}
}, function error(err, errorMessage) {
// Error handling code
});
</script>
Docs on getting user id with Messenger Extensions
Try this:
Open Messenger, then open DevsConsole and go to Network tab. Now paste your link and click it. In the Network tab open the request details issued by the click. Under "Form Data" you should see this:
q:[{"user":<your_fb_id>,...
You can use this id to authenticate the user in your app - just couple it somehow with the authorized user in your app. This is just the first idea off the top of my head, it should be quite safe if you mix it e.g. with CORS security headers.

Facebook login on mobile throwing error screen instead of login screen

I'm registering users to my site via Facebook and have come across an issue on mobile. I'll start by saying i'm fairly new to the Facebook user login processes. The journey goes like so:
Firstly I call the fb.login function on click of a button to launch the facebook popup window for them to login like so:
jQuery(".welcome-cta-facebook span").on("click",function(){
FB.login(function(response) {
if (response.authResponse) {
getFbUserDetails();
} else {
console.log('User cancelled login or did not fully authorize.');
}
});
});
I then call the getFbUserDetails function once they have signed in and accepted the app like so:
function getFbUserDetails(){
FB.api(
'/me',
'GET',
{"fields":"id,name,picture{url},email"},
function(response) {
console.log(response);
fbParameters = "?facebookID=" + response.id + "&facebookName=" + response.name + "&facebookEmail=" + response.email + "&facebookProfilePictureURL=" + response.picture.url;
/* then send the fb parameters to my DB */
}
);
};
This journey works exactly as it should for desktop which is great but I encounter some problems with mobile which i'm unsure how to resolve:
if the user is not logged into their mobile browser I get the following error:
not logged in: You are not logged in. Please login and try again
if the user is logged in through their mobile browser I get the following 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."
Not sure why i'm seeing these errors if it works fine on desktop. How can I get a smooth journey for collecting someone's details on mobile? I am correct in using this approach? Worth noting I am NOT using a facebook login button.
Thanks and appreciate the help I can get!
You need to add all URI in whitelisted fied for you Facebook App
Facebook Developers -> Settings -> Advanced -> Security
In Security block you will see 'IP allowed server'
Add all URI in this field

Allowing Facebook login through Firebase on Cordova

I am attempting to implement social Facebook login (managed through firebase) on a Cordova app, by using the cordova in-app-browser plugin. When I try to login on my device (iOS), the in-app-browser correctly brings up the Facebook login, but I receive the Facebook error:
"Given URL is not allowed by the Application configuration: One or more of the given URLs is not allowed by the App's settings. It must match the Website URL or Canvas URL, or the domain must be a subdomain of one of the App's domains."
I've seen this error before and I know it's because I need to whitelist a domain in order for it to access my Facebook app, but what do I whitelist if the request is coming from a cordova app on a mobile device?
I've browsed other posts that suggested using the cordova Facebook plugin, but this would then login directly on the app, and not register that the user is facebook-logged-in on Firebase (which I need for data and user management).
Any thoughts?
Thank you!
Here is the code:
var login = function(provider) {
ref.authWithOAuthPopup(provider, function(error, authData) {
if (error) {
// an error occurred while attempting login
console.log(JSON.stringify(error));
} else {
// user authenticated with Firebase
// var message = 'User ID: ' + authData.uid + ', Provider: ' + authData.provider;
}
});
}
High five for finding my own answer by reading the documentation.
From: https://www.firebase.com/docs/web/guide/login/facebook.html#section-configure
In your Facebook app configuration, click on the Settings tab on the
left-hand navigation menu. Then go to the Advanced tab at the top and
scroll down to the Client OAuth Settings section. At the bottom of
that section, add
https://auth.firebase.com/v2/(YOUR-FIREBASE-APP)/auth/facebook/callback
to your Valid OAuth redirect URIs and click Save Changes at the bottom
of the page.

chrome.identity.launchwebauthflow fails for specific users

I've been researching this issue for quite some time now and have had no success. Hoping someone can shed some light on this!
I'm working on an Google Chrome Extension (browser action) where authentication/authorization is being done outside of Google (chrome.identity.launchwebauthflow with interactive set to true). We've had success with the authentication/authorization flow for some users but not all. Here are the interesting results:
User A clicks extension icon, clicks Authorize button, successfully gets auth code, exchanges it for access tokens, and can proceed with using the application.
User B clicks extension icon, clicks Authorize button, extension pop up closes. It fails prior to exchanging auth code for access tokens.
User B right clicks on extension icon, selects Inspect popup, clicks Authorize button, successfully gets auth code, exchanges it for access tokens, and can proceed with using the application.
User A starts up device in Safe mode with networking. User A clicks extension icon, clicks Authorize button, extension pop up closes. It fails prior to exchanging auth code for access tokens.
User A starts up device in Safe mode with networking. User A opens up a tab and loads the extension's url (chrome-extension://pathofextension). User clicks Authorize button, successfully gets auth code, exchanges it for access tokens, and can proceed with using the application.
Extension is converted to a packaged app. User A and B opens app, clicks Authorize button, successfully gets auth code, exchanges it for access tokens, and can proceed with using the application.
We think it's a client issue, but we're all using the same Chrome versions. What would cause the extension's pop up window to close when the auth code is being returned? We can't keep the developer console open to see if any errors appear because when the developer console is open it works just fine. We are using $.ajaxSetup({ cache:false }) to make sure caching is disabled for ajax requests.
Here's a snippet of the chrome.identity.launchwebauthflow call (originally called from the popup):
chrome.identity.launchWebAuthFlow({url:url,interactive:true},function(response) {
console.log('OAuth Response: '+response);
if (response) {
var authCode = encodeURIComponent(response.substring(response.indexOf('=')+1));
console.log('Auth Code: '+authCode);
userAuthorization(authCode);
} else {
authorizeButton();
}
});
Edited code after trying to apply the code-in-background solution:
Pop up script now calls background script:
chrome.runtime.sendMessage({type:'authorize',url:url},function(response) {
console.log(chrome.runtime.lastError);
console.log(response);
if (response && response.authCode) {
userAuthorization(response.authCode);
} else {
authorizeButton();
}
});
Background script responds to pop up script.
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse) {
if (message.type == 'authorize') {
var url = message.url,
authCode;
chrome.identity.launchWebAuthFlow({url:url,interactive:true},function(response) {
console.log('OAuth Response: '+response);
if (response) {
authCode = encodeURIComponent(response.substring(response.indexOf('=')+1));
console.log('Auth Code: '+authCode);
}
sendResponse({authCode:authCode});
});
}
return true;
});
Invoking launchWebAuthFlow from an extension popup is a very bad idea.
This operation is supposed to create a new window and focus on it. By Chrome UI conventions, this should close the extension popup - and with it, completely destroy the JavaScript context of that page. There will no longer be any callback to call.
This explains why "Inspect popup" helps - this prevents closing the popup on focus loss. There is no override for this mechanism outside of this debugging case.
This popup-dismissal behavior may subtly differ by OS, hence you might not have seen it on your development machine. But the convention is clear - any loss of focus should destroy the popup page.
The only truly persistent part of your extension that cannot be accidentally closed is the background script - that's where you should handle the chrome.identity authorization. Send a message from your popup code that requests it.
Update: Note that you can't return a response to sendMessage for the same reason - the popup no longer exists. Your logic should be to try to retrieve the token with interactive: false every time the popup opens - and if that fails, request the background to initiate the interactive flow (and expect to be closed, so no sendResponse).

Facebook Canvas, Unable to login from facebook on mobile devices

I have a canvas facebook application which has both a web page and a designated mobile page.
The web page works fine and also when simulating the browser to mobile with the console everything works fine.
But, when I try to run the app from the facebook mobile app the canvas app loads (which is correct), but it does not login.
I am using the FB.login function.
login: function () {
var deferred = $q.defer();
FB.login(function (response) {
if (!response || response.error) {
deferred.reject('Error occured');
} else {
deferred.resolve(response);
}
}, {
scope: 'email, user_friends'
});
return deferred.promise;
},
and in the settings > advanced - I have the:
Client OAuth Login,Web OAuth Login, Embedded Browser OAuth Login,Valid OAuth redirect URIs and Login from Devices filled correctly.
but still from the facebook mobile app the canvas app does not preform the login.
I have been trying to get this to work all day.
and I cant find a solution anywhere.
I also cant debug the mobile facebook app.
any ideas how to approach this issue?
EDIT
Also looked at my Node server logs and I see that the FB.login is not even called.
EDIT 2
I ended up replacing the login with getLoginStatus which poses no problem to me since its a facebook canvas app... but the question still remains on how to do the login.
EDIT 3 11/26/2015
well so getLoginStatus did not completely solve my issue since it does not in fact log the user in so for the canvas games you probably need to login for the first entry if you need permissions... my solution was to add the login if the getLoginStatus returns not_autorized like so:
/**
* [getLoginStatus get the FB login status]
* #return {[type]} [description]
*/
getLoginStatus: function () {
var deferred = $q.defer();
FB.getLoginStatus(function (response) {
if (response.status === 'connected') {
deferred.resolve(response);
} else if (response.status === 'not_authorized') {
_fbFactory.login().then(function (fbLoginResponse) {
deferred.resolve(fbLoginResponse);
});
} else {
deferred.reject('Error occured');
}
});
return deferred.promise;
},
But wait, there is more... the FB.login function will not work well on mobile canvas games (not sure if its just not triggered or the browsers blog the popups or both). anyway you need to actively call it via button... so for mobile canvas games I had to add a start playing button and then the login does work..
EDIT 4 (Final)
eventually I noticed that FB.login() does not get triggered unless its an external event that triggers it, so I had to make a change for Mobile canvas where if the getLoginStatus doesnt return connected then I show a login button which does the login... the rest stayed the same.
what I did for mobile was similar to the accepted answer only to suit my needs...
I hope this helps someone besides me...
Make sure you're calling FB.login() with an event triggered by the user, such as an onclick on a button, as browsers can block potentially unsafe/dangerous javascript that's called directly. This is an extra layer of security for the end-user. There's 2 ways to create a login button:
Generate a login button with facebooks login button generator:
https://developers.facebook.com/docs/facebook-login/web/login-button
The generated login button will look similar to this:
<fb:login-button scope="public_profile,email" onlogin="checkLoginState();">
</fb:login-button>
Create your own html and use an onclick event to call FB.init():
<button onclick="FB.init()">Login</button>
Notes from the Facebook developers website:
As noted in the reference docs for this function, it results in a
popup window showing the Login dialog, and therefore should only be
invoked as a result of someone clicking an HTML button (so that the
popup isn't blocked by browsers).
https://developers.facebook.com/docs/facebook-login/web
Also, FB.getLoginStatus is the correct first step in logging in to check whether your user is logged into facebook and into your app.
There are a few steps that you will need to follow to integrate
Facebook Login into your web application, most of which are included
in the quickstart example at the top of this page. At a high level
those are:
Checking the login status to see if someone's already logged into your app. During this step, you also should check to see if someone
has previously logged into your app, but is not currently logged in.
If they are not logged in, invoke the login dialog and ask for a set of data permissions.
Verify their identity.
Store the resulting access token.
Make API calls.
Log out.
I see that your game doesn't require a login anymore, but maybe others will find this answer useful. :)

Categories