Difference between `GoogleUser.getId()` (oauth) vs `app.getUser().userId` (actions-on-google) - google-oauth

The id I get from app.getUser() from the actions-on-google-nodejs app looks entirely different from the id I get from Oauth.
app.getUser() in Google Assistant
{ userId: 'KMdEs***szG-ZRQl***cU',
user_id: 'KMdEs***szG-ZRQl***cU',
userName:
{
[...]
The same id is returned with and without the app.SupportedPermissions.NAME permission.
googleUser.getBasicProfile().getId() in Google OAuth
11348***63489
Is there any way to match these users up? It's the same Google Project in the developer console, so I assume that even if Google would generate unique ID's per project it should be the same, however in this case it looks like I am getting entirely different types of id's.

They are different types of IDs.
The ID returned from app.getUser() is meant as an anonymous project-unique identifier that can be used in some of the same ways a web cookie is used. It can not be identified against a specific account - but it will be consistent across all sessions (unless reset by the user). The profile information you can get with it (their name) is also considered non-identifying. Both are intended to be used to make a more friendly interface, rather than as a firm identifier. Users are able to reset their Google Home devices, for example, and this may reset this to a different ID.
The ID returned through OAuth, however, is meant to link them to a Google Account, with all the implications that brings, including associating them with a specific identity. This Account Linking is done separately, and does not directly give you the ID - instead it gives you an OAuth Access Token (which you can get through app.getUser().accessToken) which you can use to get their Google ID and other information that you may be scoped to get.
In theory, if you have Account Linking enabled, you could match the two up. In practicality, if you have Account Linking enabled, you wouldn't care about app.getUser().userId since you have the Access Token which will get you their Google ID. If you do not have Account Linking enabled - there is no way to match up the two and you should treat the userId as an anonymous (but consistent) user.

Related

Database structure for multiple authentication sources of users in a web app

I'm trying to work out how to structure a database schema that allows me to have multiple authentication sources for the same end-user.
For example, my web app would require users to sign in to utilize many of the functionality of features of the app. However, I do not want to be responsible for storing and authenticating user passwords.
I would like to outsource this responsibility to Google, Facebook, Twitter and similar identity providers.
So I would still need a database table of users, but no column for a password. However, these are authenticated would not be my concern. But I would still need to somehow associate my user with the identity providers user id. For example, if my user signs up with Google, I would store the users Google ID and associate this with my user. Meaning next time the user makes an attempt to login and is successfully authenticated at Google, I would make an attempt to find any user in my system that has this associated user id.
I've been trying to look for some common and recommended database structures, with no luck. Maybe I'm searching for the wrong terms for this because I cannot imagine that this is an uncommon way to do it. StackOverflow seems to do something similar.
The way I imagine it, it would allow me to associated multiple authentication sources for one app user. Meaning once I've signed up with Google, I can go to my settings and associate another account, for example, a Facebook account.
How should I go about achieving this in a flexible and clean way?
Thanks.
You need to know what data you have to save in your db to authenticate a user with a third party login.
For example, once I used Google to login users in my app, I save Google user id first time a user logs in and get data the next time.
You could have an entity with third party providers, so you will create a table with 2 values, user_id (your user data) and provider_id (Google, facebook, twitter...).
If you are going to use just one provider then you could add provider_id field to your users table.

Auth0 database and social connections, unique email addresses

Maybe I am missing something here, or this is a flaw in Auth0? I'll give an example of my issue:
Let's say I have my Default App (client), hooked up to that I have Username-Password-Authentication (database connection) and google-oauth2 (social connection).
A user comes to my site, signs up via google-oauth2 (social connection) using joe#gmail.com. Once complete, he gets added to my users in Auth0, all great.
A few months later, Joe comes back to my site, and being a busy guy, he forgets he signed up to my site before. This time, he decides to sign up using my custom Email and Password form, that will add the user to the Username-Password-Authentication (database connection). so he signs up there using joe#gmail.com again, and everything goes well, he is now listed in my user's section in my Auth0 dashboard.
This is the problem, I now have two joe#gmail.com accounts, one with google-outh2 and one with Username-Password-Authentication. I really can't have this, I need a unique email address, regardless of the ID Auth0 supplies.
Does anyone know how I can make email address in my user section 100% unique? I'd think a rule would do this, but it appears rules only apply AFTER a user has been registered, so I can't run a rule before adding?
the only way I can see doing this right now is make my own checks and delete via the management API, but that is a really long and messy way to do it I feel.
Any help will be appreciated here!
Thanks!
Auth0's default behavior is to create a new account in the database for every unique entry. Since the user created using Google has a unique id (based on google-oauth2), and the user created using the sign-up form has a unique id - they will technically be considered two separate accounts. In order to resolve this disparity, you can establish a means with which the account data can be merged. In the documentation linked provided above, there are examples of three possible ways of doing this:
Automatic Linking - which involves creating a specific rule to merge users based on matching emails
User-Initiated Linking - which involves providing a UI for users to opt into merging users with matching emails
Suggested Account Linking - which involves setting up a rule that is linked into the UI
One important thing to consider is that the data returned from different social identity providers may not be normalized the way that data is normalized onto the Username-Password-Database. For example, while auth0's default for emails is to lowercase the information, google-oauth2 may return emails as Uppercased - creating the potential for non-matching emails when checks are made using strict equality
The option you are looking for is called account linking.
You can find more info at https://auth0.com/docs/link-accounts

Can email ID received from Google OpenID login be considered unique over time?

I am using Google OpenID for login to my website. I am using it through Tornado's built-in auth library. I retrieve email ID, first name, last name and name from the openID data. My question is can I use email ID retrieved in this way to remain unique over time - including its case? For e.g. Is it possible that a user may have email ID John.Doe#gmail.com today, but in future it may be john.doe#gmail.com? I cannot find any other field in the returned OpenID data that I can assume unique for a given user.
Update Maybe I should also add that I was hosting my website on Google App Engine before and was using its built-in login. When I migrated to Tornado based implementation, I used email ID from the old logins as the unique identifier of the users. In most of the cases that seems to have work, but recently I ran into a case where the user's email ID returned from OpenID was different from his email ID from GAE version only in case. Therefore I am trying to understand how this can happen.
Since it's an email address, you shouldn't consider case, as for normal email case is unimportant. So, you should be able to consider that unique in a case insensitive test.

is openid.claimed_id static?

I'm reading about Federated Login for Google Account Users to figure out how I can have a user log in to a web application using their Google Account.
So towards the end of the process, Google returns a Google supplied identifier which is appended as openid.claimed_id. This means the web application uses this identifier to recognize the user and allow access to application features and data. My question is, is this identifier static? Can I use this identifier to repeatedly id the same user?
Yes. Consider the openid.claimed_id value to be the username. Especially with Google, but this is true for any OpenID Provider that truly implements 'directed identity', don't consider this username to be correlatible with other web sites. Any other relying party besides your own web site will get a different claimed_id value for the same Google user, by design.
Also, be sure to treat this claimed_id as case sensitive.
The specific answer to your question is found in Googles OpenID API documentation:
The Google-supplied identifier, which has no connection to the user's actual Google account name or password, is a persistent value; it remains constant even if the user changes their Google user name and/or email address. This identifier is also a "directed identity", that is, Google returns a different value to each relying party. Google uses the request parameter openid.realm to recognize the relying party, so if the third-party application decides to change this value, all user identifiers will change.
In fact, I just ran into an instance where the google claimed_id had changed for my test user. I was coming to the end of implementing OpenID into my app, and for no apparently reason the claimed_id in the response data is had changed.
I've been testing with this account for the past couple weeks, and the claimed_id was the same this entire time, as expected. Then wham, changed! I looked at the response data many times to verify, and the underlying code to retrieve the data had not changed.
I'm not sure how to handle this at the moment, but I think this is going to throw me for a loop. After initial authentication, users register to the site (as you might expect) and setup a screen name. How are we to verify it is the same user if the claimed_id had changed? We certainly can't use email address, per best practices.
EDIT
Now I have pie in my face! I missed one little detail, that turned out to be a major detail. I change my development environment and was hosting on a different v-host. This effectively change the realm, and this will change the claimed_id response according to the docs.
This was a good lesson for me, as I was about to implement OID on a subdomain in which realm was being set automatically in my code. Now I saved myself a headache down the road, because I would not have been able to use the same user database across all other sub-domains without breaking identity.
updating realm
MORE INFO
Just as a side note - even if you are developing your OpenID solution for one of your subdomains, it might be prudent for you to specify realm to your top-level domain.
e.g., openid.realm = http://*.yourdomain.com
It will allow you to expand your sign-in page across all your subdomains and keep user identity across them.
(optional) Authenticated realm. Identifies the domain that the end
user is being asked to trust. (Example: "http://*.myexamplesite.com")
This value must be consistent with the domain defined in
openid.return_to. If this parameter is not defined, Google will use
the URL referenced in openid.return_to.

Best way to seamlessly & silently authenticate with a second webapp while logged in to a first?

Third party app (A) needs to link users to our app (B) and log them in behind the scenes.
Both apps work independently with their own auth systems. Users share a common unique ID, but have different authentication tokens (username/password/key etc) at each app.
The two complicating factors are as follows:
One app B user may associate with two app A users (e.g. both accounts at app B would redirect and login to the same app A account)
The app B user may not actually have any existing auth tokens, only their personal record and user ID, but we still want to be able to log them in if they are coming from app A.
My first thoughts were OAuth - but I don't think it will work as some users don't have app B accounts and thus won't be able to log in to grant app A access (see point 2 above).
The simplest way I have come up with is:
Each app has a pre-shared key e.g. "LOLS"
Common hash algo generates indepentent identical tokens e.g. hash(PSK + UID)
App B stores hashed tokens for each user
App A sends POST with UID and hashed token to App B, which uses it to identify and auth against a user
The problem with this is that it's hideously insecure. Anyone with knowledge of the pre-shared key (any system admin) and a user's ID (once again, any system admin) would be able to authenticate as ANY user, which is unacceptable.
Does anyone have any solutions? I'd prefer existing standards but am open to customised implementations. We can't really do much to app B other than to get them to use whatever API we provide.
I've faced situation similar to this many times. There have been a variety of solutions we've explored, here's one of them.
You produce a webservice for them to call. This could be something you lock down however you like, including by limiting access to their IP address at the firewall. They post the UID to your webservice, which inserts into a table on your end and hands back some sort of random token (we randomly generated a guid). Your table associates the token with the UID (in plaintext) they sent and a datestamp.
Their application sends the random token to you instead of the UID, you use it to look up the UID, and use the timestamp to make sure the random tokens are expired after a minute or so. Even if someone looks through your table somehow to get the list of UID's recently attempted, it doesn't let them authenticate unless they can pull it off real fast!