How do I force oauth authentication to be against a specific user - oauth-2.0

I'm following the client side authentication as described at https://developers.google.com/accounts/docs/OAuth2UserAgent
I am routinely signed on to multiple Google accounts. Normally, the flow will prompt me to choose which account I want to authenticate with. However there are sometimes instances where it assumes the first account I signed in with, which is not the account I wish to use.
When users register with my service, they do so with a specific email address (and google id).
How do I qualify the oauth dialogue such that it will always take place using only the specified user?
On https://developers.google.com/drive/about-auth I can see a comment...
Note: If you want to use the user_id parameter to select the current user from
(potentially) multiple logged-in accounts,
also add https://www.googleapis.com/auth/userinfo.email.
The implies that there is a user_id parameter I can include in the oauth call, but I can't see it documented anywhere, and there is nowhere in the Javascript API where I can inject a user_id.

Add the user_id parameter to your Authorization URI.
gapi.auth.authorize({..., user_id: 'ali#gmail.com'}, handleAuthResult);

Related

As administrator, get access token on behalf of another user

I'm trying to implement IdentityServer4. We need to functionality to login as another user, when we're administrators.
I've already setup the login functionality for regular users, but I'd like a specific endpoint where an administrator can enter the username/id of a regular user.
How would one go about implementing this in IdentityServer4, as well as regular oauth2?
This is outside the scope of OIDC/OAuth2 interactions but there are some conventions for how to respresent such a scenario in the result token/claims. Have a read of https://www.rfc-editor.org/rfc/rfc8693 (in particular the act claim bits) for some inspiration.
We did this via the sign in UI flow but the model was that users could grant other users impersonation permissions explicitly. If when signing in you had valid impersonation grants then you'd be prompted as part of the sign in flow to choose a different account or continue as yourself. In your case you can identify admin users and give them the option to impersonate anyone you like.
If the user choses an impersonatee then it would change the current session to respresent that user but also store claims relating to the original user/session in the actor claim (act) and also add an amr claim of imp. We then made these claims available to clients so that they'd be aware of the fact impersonation was used and could then for example add that info to audit logs etc. We also notify the impersonated user via email and restrict access to account settings - i.e. impersonators can only sign into clients as other users, they cannot change their account settings.

Using OAuth but store extra information in my own DB

I've been looking into OAuth for a while, but haven't implemented it in any of my applications yet. I'm having trouble really understanding the full concept, so I still have a few questions that I haven't found an answer to, so I hope that anyone can help me.
I want a user to be able to start my application (WP8), login to facebook / twitter / microsoft / ... .
When he gets authenticated, I want to actually save this user to my own DB so I can add some user specific stuff like preferences, posts, ... .
What do I need to save in my own DB to specify a user?
Do I need to save the token itself or is this something that will be invalidated after a while? Or do I need to specify the user's name? With other words: What can I use as a unique identifier?
And what happens when a user would authenticate with for example facebook and he deletes his account?
And one more question, would you ever allow a user to connect to an application with 2 different service providers? If so, how would you make the coupling of these 2 providers to 1 user in your own DB?
I hope my questions are clear enough!
If not, don't hesitate to ask for more information!
Kind regards,
Gert
I assume that you have your own back-end where you authenticate your own users and your WP8 application is just a client.
First, let me distinguish between a user credential and a user profile. User credential is something that validates who the user is, e.g. username/password, facebook user id supplied with a valid auth token. User profile, is what you store in your own database about the user.
You also need to distinguish between a token you use to authenticate the user and the AccessToken Facebook needs to grant you access to user's data.
So... to answer your questions:
What do I need to save in my own DB to specify a user?
Create a record with user data (like preferences, and your unique user ID), and user's login method (e.g. Facebook) and credential (e.g. Facebook's user ID). This is your user's profile.
Do I need to save the token itself or is this something that will be invalidated after a while?
You can also store the Facebook AccessToken here if you've been granted "offline access" privileges by Facebook, but that is used for Facebook's access by you... not by the user's access to your app/back-end. For user's access you could just use a mechanism similar to cookie-based authentication - it's up to you. You could use the AccessToken as a kind of a "cookie", but you would need to always check against Facebook that it's valid.
With other words: What can I use as a unique identifier?
You could treat Facebook's ID as unique (so long as you never allow another account in your user profile DB to link with the same Facebook account)
And what happens when a user would authenticate with for example facebook and he deletes his account?
It's a good idea to have users still create a username/password combination that works with you site and only rely on Facebook login for convenience. In any case, Facebook provides a "Deauthorize Callback URL" when you create an app profile on Facebook. This is called when a user deactivates your app or deletes an account with Facebook. When you receive this call, you could send your user an email when an auth link to setup a different credential so as to not lose access.
would you ever allow a user to connect to an application with 2 different service providers? If so, how would you make the coupling of these 2 providers to 1 user in your own DB?
Sure, you could do that. Say you'd want to allow a Twitter account as well. You'd need to add a Twitter user ID field to your user profile database.
Here's another tip: create an ASP.NET MVC4 project in Visual Studio - the template includes an example of how to set up a user profile database with OAuth login.
Hope it gives you the high-level overview to investigate further.

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.

With Twitter oAuth authorization, how do you specify what twitter username?

Developing a web application that I've registered with Twitter. In this app, I might have 10 different Twitter Identities that I want to either Allow or Deny access for the application to.
For example:
https://api.twitter.com/oauth/authorize?oauth_token=XXXXXXXXXXXXXXXXXXXXXXXX&oauth_callback=http:://localhost:24649/TwitterIdentity/GetTwitterAuthorizationCallback/
It always just defaults to whatever my twitter account is logged in as and I have to specify Logout, then sign-in with new account. Its almost like I need an extra querystring parameter such as
https://api.twitter.com/oauth/authorize?oauth_token=XXXXXXXXXXXXXXXXXXXXXXXX&oauth_callback=http:://localhost:24649/TwitterIdentity/GetTwitterAuthorizationCallback/&ForUsername=billgates
Actually, you can pass in an extra parameter with the callback url, like so:
https://api.twitter.com/oauth/authorize?oauth_token=XXX&oauth_callback=http:://localhost:24649/TwitterIdentity/GetTwitterAuthorizationCallback?ForUsername=billgates
and the parameter will be sent back to you when Twitter calls the return url, like this:
http:://localhost:24649/TwitterIdentity/GetTwitterAuthorizationCallback?ForUsername=billgates&oauth_token=XXX&access_token=YYY
You can read more about this in the documentation - http://dev.twitter.com/pages/auth:
Always use an explicit oauth_callback
- It is recommended that you specify a default OAuth callback in your client
record, but explicitly declare your
oauth_callback on each request token
fetch request your application makes.
By dynamically setting your
oauth_callback, you can pass
additional state information back to
your application and control the
experience best.
Note that in the general scope of authorization, the authorized agent does not necessarily know the identity of the user on whose behalf it acts. In other words, there could be an implementation where your app can be authorized to read the Twitter stream of updates, while still not knowing which identity that stream belongs to. Adding the parameter you ask for would be information disclosure in this case, as your app will need a piece of information that the system is designed not to provide.
Or to put it in a real life example - imagine a valet parking, where instead of giving you a parking ticket and taking the keys to the car, the valet would ask you for your SSN just to park the car, just because the valet parks cars for other people too.

How to uniquely identify someone in oAuth

I'm currently creating a web app using Google's oAuth. I was wondering how I can uniquely identify an authenticated user so I don't accidentally add duplicates.
Doesn't Google give you other unique params like user name or user ID?
For example, Twitter and Facebook, give you user name and a unique url that identifies user's profile picture. If you save that params on server-side you can identify user next time that he comes on your site.
The best way to do this would be to use OpenID with the oAuth extension (aka hybrid).
I am currently using OAuth exclusively and I am requesting the https://www.googleapis.com/auth/userinfo#email scope as described on http://sites.google.com/site/oauthgoog/Home/emaildisplayscope to get the email address of the authenticated user. I am using the email address to uniquely identify the user. This should be good enough for now.
Edited:
According to a recent Google developer comment (https://groups.google.com/group/oauth2-dev/browse_thread/thread/cf5c137f872f9932), they are currently working on this problem, but for anything production ready, you should use OpenID authentication.
You should save somewhere the user_id you have for your users in your site, along with the corresponding access_token and access_token_secret.
Then you can query that table (or wherever you save that information) with the user_id and obtain the proper tokens
Regards

Resources