Google+ sign in session state - oauth-2.0

It isn't clear to me how the Google+ API platform deals with sessions. My web app uses the Google+ sign in button and after signing the person in I receive an authentication code that I can use for API calls. But the Google+ API docs don't indicate how to handle the sign in session from the server side. What they do mention is how to handle it in Javascript as outlined at:
https://developers.google.com/+/web/signin/session-state
They indicate to check the status.signed_in state which will be set to true if the user is signed in and then my client script is suppose to customize the UI accordingly. But that is nonsense for parts of the UI that require proof the user has signed in. A hacker could just as well put a breakpoint on the callback from Google's authentication, and change status.signed_in to true making the UI think the user is signed in. I need a way to verify on the server every time the page is reloaded to determine if the user is signed in. How am I suppose to do that?

how to handle it in Javascript as outlined at
The session state on the page you referenced refers to the state represented in the button.
From a server-side perspective, Google does not provide a state associated with users on a per-site basis.
A hacker could just as well put a breakpoint on the callback from Google's authentication, and change status.signed_in to true making the UI think the user
This would present the signed-in UI, but should not have access to actual user details.
The way that your site should probably be authorizing the user server-side is to validate an ID token or Access token that is securely passed from the client. All of the Google+ quickstarts show you how to do this and include instructions for getting started.

Related

Dropbox OAuth2 API always prompts user for permission when a refresh token is requested

I'm writing an offline application that uses the Dropbox API. When a user comes to the application, I'm using the https://api.dropbox.com/oauth2/token (docs) to get a refresh_token, which I store for later use.
I am calling the same endpoint every time the user logs in (unless I've already got the user's data in a cookie). I'm not sure that this is the best way to go about it: I at least need to get the user's account_id, so that I can look up their refresh_token in the database if I already have it. But every time I call https://api.dropbox.com/oauth2/token, the user is redirected to the Dropbox app authorization interface, as if they've never approved the app before.
So I would either like to know how to stop Dropbox from forcing the user to re-authorize an app every time. Or, if that is just how https://api.dropbox.com/oauth2/token is supposed to work, I'd instead like to be able to get their account_id somehow when they visit my page.
(In case it's relevant, the app is still in development mode at this point.)
The https://api.dropbox.com/oauth2/token endpoint is an OAuth endpoint that the app can call to get an access token/refresh token. Being an API endpoint, it does not itself redirect the user to the Dropbox app authorization page.
The Dropbox app authorization page is at https://www.dropbox.com/oauth2/authorize (documented here), and the app decides if/when to direct the user there to authorize the app.
You generally only need to send the user through the app authorization flow (sending them to https://www.dropbox.com/oauth2/authorize and then calling https://api.dropbox.com/oauth2/token) once per user for an "offline" application. Once you do so, you should store the resulting refresh token for that user. You'll typically store the refresh token for that user tied to their user account in your own app.
Exactly how you manage the user accounts in your own app will depend on how it's built, but, as it sounds like this is a web app, typically you would use the user's browser cookies to identify the user when they return to your page so that you can look them up in your database and retrieve their details, such as their corresponding refresh token. (Or, if they're not already signed in to your web app, you would have them do so first.)
Greg's answer is very helpful, and very politely addresses my misunderstanding of the auth flow. (I was revisiting old code I'd written years previously—obviously I should have documented it better than I had!)
In the end I believe that Dropbox was forcing me to reauthorize because my application was in development mode, and had a small user base. When I used the identical code in an app set to production mode, it stopped forcing me to reauthorize. So the “problem” is really a Dropbox security feature, and the solution was just to use production mode.

Via the api, can I force the user to login to reddit?

I am writing a Reddit client that uses OAuth to authenticate the user. One of the features I would like to implement is the ability to use multiple accounts simultaneously. This requires the user to authorize my client on each account they want to use. The problem I'm running into is that if the user is already logged into Reddit in their browser, when I pop a browser to perform the auth, it will have them authenticate my client against their currently logged in user.
Is there a way to force the user to re-enter their credentials? I would rather not have to put some kind of disclaimer on my Add Account screen that says "Please log out of Reddit in any open browser windows".
I tried opening the Reddit login page in a WebView so the request is sandboxed, and while that worked, it gives the user access to the entire login page (including all the links that navigate to elsewhere on the site). I don't mind that experience when I'm popping an external browser, but in an embedded WebView I really just want to present a username and password box along with the OAuth validation prompt.
Note: I do kind of prefer the embedded experience because it doesn't interfere with the users existing browser cookies, I just don't like how cluttered the login page is this way and I'm not sure how to prevent the user from navigating away from login. Also, for completeness, this is a UWP app, though this problem is largely technology independent.
The problem I'm running into is that if the user is already logged into Reddit in their browser, when I pop a browser to perform the auth, it will have them authenticate my client against their currently logged in user.
It may be caused by the authorization server. If so, we can not do anything in our client app.
But if it is not the server issue, in UWP, there is a WebAuthenticationBroker class witch can help you to authorize your app to access the user info from Resource server by getting a token. You can try to use the class to implement OAuth authorization. You don't need to use the in a WebView so that you can authorize your app with multiple users if you can manage all the user with the token properly in your code logic.
See the Web authentication broker topic and the sample to learn more details.

How do I get the ID of the currently authenticated Twitter user in a web application without using OAuth?

*Apologies in advance for the long background but I think it is necessary and helpful to other devs once this is answered.
Background
I am building a very social web-application in which there are several events that trigger social actions such as updating the user's Twitter status.
Currently, I use a library called "TweetMoaSharp" (.NET) to handle the Oauth workflows and events that trigger a status update or follow action work brilliantly as long as the user is briefly redirected to the Twitter authentication page.
To clarify, the user is not asked to re-authorize my app each time, but there is an unsightly flicker that lasts for 1-2 seconds while the user is directed to Twitter and then back to my app. This will annoy the end user as there are frequent Twitter interactions.
So--to relieve the situation, I use TweetMoaSharp to obtain an OAuth Access Token via the server and then store that token along with the user id returned from Twitter in my database. I then set a cookie on the client that contains the user's Twitter Id so that for future requests I can simply pass that ID to the server, grab the OAuth token form the database and do my business. No redirect required!
Problem Solved, Right?
Well, no. Stupidly, I overlooked the fact that this can cause a collision with multiple Twitter Accounts being used on the same page and ended up tweeting test-tweets to a second twitter account I own because I had changed Twitter sessions. This could happen to any user(s) who access multiple Twitter accounts from the same browser; a husband and wife for example.
Back to the Drawing Board
I thought to myself, "The Facebook JavaScript API" makes it super easy to get the id of the currently logged in user without going through a bunch of server-side token steps so I am sure Twitter offers the same approach." Ha! I haven't found one yet.
Bottom Line / Question
How do I get the ID of the currently authenticated Twitter user without redirecting them to Twitter (even for just a second)? If I can do this, then I can compare the returned ID to the one in my cookie and know if it is valid for my application's current session or if I need to have that (new) user authenticate as well so that I avoid "Tweeting" under the wrong account.
Thanks in advance.
Use your app tokens to do a verify credentials call
https://api.twitter.com/1.1/account/verify_credentials.json
The returned info is the logged in user.
Unfortunately limited to 15 calls per 15 minute window!

Soundcloud as Oauth Provider: How to make it connect only one time

I'm currently implementing an Oauth consumer service which is going to use Soundcloud as an Oauth service provider as well. But I'm having the following issue with it: Taking Facebook or Twitter example, you go there, you sign in, you fill up the permission form, and you are redirected back to your app. If you go there a second time, and given you are already sign in, you basically skip all steps and are redirected back instantly. That means, Facebook recognized that you already gave permission to that 3rd party service, so it doesn't ask your permission constantly.
And that's what's happening when I use Soundcloud. Basically everytime I redirected the user to the Soundcloud Oauth connect endpoint, the permission form always shows up, even though I already gave permission to that 3rd party service previously. I'm forced to press "connect" every single time, which is a drag from the user perspective (how many times can you give permission to the same entity). My question is: is there a parameter I can use to make soundcloud recognize/validate the previous permission from the user account to that specific 3rd party service? Or is this Soundcloud Oauth design implementation and we have to live with it?
Edit:
Maybe this wasn't clear, but each time I press "connect" in soundcloud, a new access token is being generated and delivered. Since my app uses this access token to identify its users, it doesn't work very well for me that the access token is getting updated everytime I want to log in, making me effectively "sign up" everytime. To sum it up, I want to get the previously attributed token to my account, so I can look up in my database, identify it and log him in.
I'm also looking for a solution which doesn't involve storing state in the client that might get cleaned up.
What you can do is store the user's oauth token in local storage and reuse it in future sessions. That's what happens on soundcloud.com.
A longer explanation:
When you use the Connect flow, the user is authenticated by SoundCloud (either by using username/password, Facebook Connect, or an already-existing session on soundcloud.com), and then when it is successful, your app is given an oauth token for that user. This is passed to the callback page which is registered for your app.
That token is the only piece of information needed to have the user be "logged in". Unless the token expires (by time, or by the user manually revoking it), then you can reuse that in future sessions.
I think I'm a bit confused about your application's design: where and how is the oauth token being used? I think that instead of using the token as an identifier, perhaps the user's permalink might be better? If you have the oauth token, you can find out the permalink by querying api.soundcloud.com/me.

Is it possible to be able to correctly select any available Google account to use when using authorisation via the JS client library for Drive?

I've got an existing Google Drive enabled application that's using the Google Java client library and server flow auth.
If you're not logged into the application and navigate to the URL AND you have logged into more than one google account on that browser (only one personal Google account is possible, any additional ones have to be Google business accounts) the OAuth callback offers the options to select which Google Account to use.
However, whilst testing a switch to using the JavaScript client library I'm not able to activate the multiple account selection screen using gapi.auth.authorize. Is it possible to handle multiple accounts using the JS library?
Update : I tried with the immediate parameter false. I can log in as long as I don't change account in the popup. If I do change account, I get to:
https://accounts.google.com/o/oauth2/auth?client_id=433863057149.apps.googleusercontent.com&scope=https://www.googleapis.com/auth/drive.file+https://www.googleapis.com/auth/drive.install+https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profile&immediate=false&redirect_uri=postmessage&origin=https://drivedrawio.appspot.com&proxy=oauth2relay593063763&response_type=token&state=701344514&authuser=1
in a new tab and nothing happens. I've made a video to demonstrate.
Update 2 : This bug against the JS client library for the need for double selection of mulitple account has been accepted.
You are not getting the multi user selection screen because of the following parameter: authuser=0
This automatically selects the first account you are signed-in with (authuser=1 would select the second etc...).
It's currently not possible to remove that param using the client library because the client library sets it automatically to 0 (this is why it claims not to handle multi-accounts) if there is no value so one way is to override it to -1 for example, this will show the multi-account chooser. Then you could also ask to access the user's profile or email at the same time you ask access to other APIs and fetch either the email of the user or its ID. Then on subsequent auth you can specify the user_id param which wil bypass the user-selection screen.
So in practice, first authorize like this:
gapi.auth.authorize({client_id: <Your Client ID>,
scope: 'https://www.googleapis.com/auth/drive openid', // That requires access to Google Drive and to the UserInfo API
authuser: -1});
The only problem with the above is that the auto-refresh of the client library will not work because every auth will by blocked at the multi-account selection screen.
The trick is to get the ID of the user using the UserInfo API, save that ID in a session cookie and use it on subsequent auth like that:
gapi.auth.authorize({client_id: <Your Client ID>,
scope: 'https://www.googleapis.com/auth/drive openid',
user_id: <The User ID>,
authuser: -1});
Specifying the User's ID will make sure the multi-account chooser is bypass and will allow the auto-refresh of the token from the client lib to work again.
For reference, other URL param that impact the User flow are:
user_id: similar than authuser (bypasses the multi-account selection screen) but you can use email address (e.g. bob#gmail.com) or the User ID you get from our Open ID Connect endpoint/Google+ API/UserInfo API
approval_prompt: default is auto, can be set to force to make sure that the approval/grant screen gets shown. This makes sure that the gant screen is not bypassed on subsequent auth (after first time).
immediate: immediate is a bit tricky, when set to true it will bypass the grant screen (kinda like approval_prompt=auto) if the user already granted approval previously, but if the user has not granted approval previously you will get redirected with an error: error=immediate_failed. If set to false it won't add special behavior and therefore fallback on the behavior setup by the approval_prompt value.
Note: immediate=true and approval_prompt=force is an invalid combination.
I think the client library is using the immediate param so that if he gets the error=immediate_failed it will restart an auth flow without the authuser param, but that's only speculations :)
The OAuth grant access page is only shown when not in immediate mode, does it work as expected if you set the immediate parameter to false?
According to http://code.google.com/p/google-api-javascript-client/issues/detail?id=11
multi-login isn't supported by the Javascript client
Pay attention to authuser parameter. Set this to "2" for example and you will be prompted for login even if you are authenticated already.

Resources