How to allow signing-up through multiple authentication-providers, while sharing the same email-address? - authentication

This is probably a question a bit in between SO and UX.se.
I'm implementing a signup/login sytem which allows for multiple ways of authentication: social signups using Facebook, Twitter, Github and a local (username + password) signup.
In the backend I'm having a User model and a Passport model. A User may have multiple Passports, meaning a User may authenticate through different means (e.g.: through local signin,. or through facebook for example)
For good measure: the Passports of a particular User will always be from a different provider (facebook, twitter, local). I.e.: a Facebook-passport, a Local-passport, etc.
This seems like a good way and would allow me to have a User account connected to multiple ways of authentication.
I'm familiar with the security issues this might raise, so for passports to be combined/merged a User has to be logged in to both.
Ok on to the problem. Consider the following flow:
user-a signs up with a provider, say local, with email user-a#gmail.com
user-a signs out (or has it's session expired).
user-a signs in using another provider, say facebook. Chances are the facebook account has a email-record of user-a#gmail.com
Currently, I've defined email to be unique on the User-model. This would mean the above signup would fail, because there's already a User-account that, by means of the local Passport, has the mentioned email-address.
What would be considered a best practice in a situation like this? I trust there must be many implementations floating around that must have seen this problem pop-up.
Options:
Warn the user the authentication isn't possible and mention the user that the current email-address is already registered by means of another authentication mechanism? This would be reasonably user-friendly.
Note that a User-account, by means of a different provider exists with the same email-address and as a consequence merge the new Passport with the User.. I just put this in for good measure: this is a pretty big attack-vector and would allow a user-b to get access to an account by faking the email-address (through a social provider which doesn't do email-validation)
Don't have a uniqueness constraint on <user,email>, but on <passport, email>. This would allow a new User and associated Passport to be created and all goes well. Now the same actual person probably has 2 User Accounts: 1 for each authentication provider. As a next stage allow the User-accounts to be merged, by signing in to both and acknowledging the merge.
I'm leaning towards 3, but 1 is simpler. I'm not sure, what do you think?
Have you encountered this before?

Yes, #3. I have implemented this myself. The concept you're looking at is: Associate multiple SSO accounts. My user structure is as follows:
name : {
first: { type: String},
last: { type: String }
},
emails: [{ type: String, unique: true, 'index': true }], //all known emails as provided by SSO services. we use this to cross ref when the user uses a different SSO to login after initial setup. this avoids account dupes
sso: [{
provider: { type: String, required: true}, //matches the name of passport strategy name employed
userid: { type: String, required: true } //the specific SSO provider userID that's unique in the provider's realm
}]
So, in your auth sequence, you look it up by email OR provider+userid combo, if you don't find the SSO provider, you attach it. The reason for or, someone may update their email but the specific SSO provider ID never changes.
Another common practice (if it makes sense in your app) is to allow the user to "link" SSO accounts. That allows you to handle different email addresses. Example: user FB email is a personal one but in LinkedIn he lists as primary the business one. LinkedIn sadly gives you only the primary via their OAuth2 call.

Related

Does / can Alexa replace its generated UserId for a linked user?

We have an application utilizing Alexa skill with account linking for user details.
According to Alexa's account linking documentation:
Our skill is set up for Account Linking which in turn refers to a 3rd party (or it could be internal) Identity Management System (IMS) for user authentication. Our application (as well as our organization) does NOT internally maintain the app's user identities.
Let's say the user enabled our skill on her device, at which point (according to the above docs) she was issued an Alexa generated userId, something like:
"userId": "amzn1.ask.account.AFMWOL5WIGQZLYYEMM2IJL2BJ26ICPQHBPR2DSLRX46CHW36R6CPVH7RZTUZMBCHHJLQQNU3YO2BWZWNIRTM3PCAGTNZKILK33PM2XVI36H4RSINFH2A26OLURAIB2RVPV6GMK56BR5BLBIFNJKT64EANASM7IDTQJBQLGDIEUZHUIM6VSHTTOUPVPITIPOIOPESUK53TSALU5I"
Consequently, upon further interaction with the skill, she wanted to access some more personalized information which triggered account linking so her identity was confirmed and re-established via provided account linking details (OAuth 2 Authorization Code Profile), which, while doing so, as mentioned before contacted the 3rd party Identity Management System (not LWA) to verify the user identity:
the user is presented with a login screen,
she enters her credentials, say: "alice"/"password123"
she answers the relevant questions to permit certain actions that our app can do on her behalf and
is allowed to further interact with the system on a more personalized basis
Let's say that inside our app, we want to be able to identify the user by her real userId: alice and NOT the one auto-assigned by Amazon, as described above.
Does Alexa allow for this?
Upon successful account linking, does Alexa overwrite in its JSON request (or can it somehow pass it through, along with now embedded accessToken field) the userId it receives from the 3rd party Identity Provider) so that that "real" userId (is it called subjectId in OAuth parlance?)can then be used to identify the user actions during her further interactions with the app?
If yes, how can we obtain the user details from JSON via Alexa Java API?
If no, what would be possible ways to facilitate such ability?
Can the real userId be obtained from the accessToken that Alexa puts in its request after authenticating a user? If so, how?
I'm not sure if it's related to this, seems to be a similar request, has it been put on Alexa's roadmap or became a feature already?
This seems to be a detailed version of How to obtain userId specified by Alexa user during account linking
Generally speaking, after the user complete the OAuth authentication, the application (i.e. Alexa in this case) would receive a access_token and refresh_token. If you want any additional data, e.g. username alice, email, phone, address...etc., you would need to check with your OAuth provider and see if they have an API to retrieve those based on the access_token with the appropriate scope.

Anonymous login using OpenID or OAuth

In short: Can I use OpenID oder OAuth for anonymous logins on my web service?
Described in more detail:
Scenario/Background: I'm going to provide online-tools for mental health related exercises. The users should be able to see their completed exercises after each login, but I don't want them to register at my service—because I don't want to store their e-mail adresses, passwords, not even nicknames or anything like that (not even hashed!), because it could reveal the users' identities. I want to keep their privacy perfectly safe by not storing anything that relates to the offline identity.
Problem: How to perform the login (or how to recognize recurring users) without credentials?
Approach(?): When I use my Google account to log in at some third-party web services, I'm asked wether I want to share my profile data, e-mail adress—and what else. Would it here be possible to reveal nothing? The only thing, the service would know, is that somebody has a google account and knows the password. To me, it's completely unimportant who the owner is, it's just important to recognize the same owner after each login—let's say by some kind of anonymous token id.
Is this approach working?
Are there other approaches for anonymous user logins—without storing data?
Use OpenID Connect. OpenID Connect is a specification built on top of OAuth 2.0 (RFC 6749). You can delegate user authentication to an Identity Provider (such as Google) that supports OpenID Connect.
An IdP will issue an ID token to you after successful user authentication. You can find the user's attributes such as name, email address, etc. in the ID token. So, you don't have to manage users' attributes any more if you use an external Identity Provider that supports OpenID Connect.
(Addition for the comment)
OpenID Connect Core 1.0 has defined 6 standard scopes as listed below. These values can be included in scope parameter of an authorization request.
openid
profile
email
address
phone
offline_access
Among the above, profile, email, address and phone are defined in "5.4. Requesting Claims using Scope Values". They can be used to request some attributes of a user to be included in an ID token which will be issued by an authorization server. For example, when email is included in scope parameter, the ID token issued based on the request will contain values of email and email_verified (if the authorization server supports the attributes).
So, if you want to minimize the number of attributes contained in an ID token, avoid including profile, email, address and phone in scope parameter. In other words, scope parameter should contain only openid.

How to link different authentication providers in azure mobile services

What is the best practice in azure mobile services to use different authentication providers (Facebook, Google, Windows e.t.c.) and understand that this three logins belong to the same user.
Out of the box if a user1 choose to use Facebook for authentication on his mobile phone and add some information to the app, and later he (user1) try to login with Google on his tablet, he will not see his information. Because they are two different users with different tokens. And I want to take some additional information from authentication providers (email) and has my own user table which contains email and other profile info shared for user no matter what provider he uses. How could I achieve it?
P.S. I use .NET as a backend and Windows Phone as a client
There isn't an out-of-the-box solution here. You would probably be best served by using a lookup table which maps a static user ID that you define to different identity provider IDs. Then, everywhere that you take a dependency on the user ID, you would do a lookup to match the current user identity to your static identifier. Your user ID is what gets stored everywhere else in the database.
The important detail here is that a Mobile Services token maps to a single provider identity. If you look at the user ID, it is actually provider:providerID. So we need to obtain two tokens and validate both together in order to associate two IDs.
On the client, you would have to manually prompt the user to link accounts. You would stash the current token in memory during this process, log in with the new provider, then call and API on the backend which does the association.
string existingToken = App.MobileService.CurrentUser.MobileServiceAuthenticationToken;
App.MobileService.Logout(); // allows login with new provider
await App.MobileService.LoginAsync("google");
await App.MobileService.InvokeApiAsync("associateToken", existingToken);
On the server, you need to be able to validate existingToken (the new one being implicitly validated by restricting the API to AuthorizationLevel.User)
Within that API, you can validate the token using:
IServiceTokenHandler handler = this.Request.GetConfiguration().DependencyResolver.GetServiceTokenHandler()
ClaimsPrincipal claimsPrincipal;
bool didValidate = handler.TryValidateLoginToken(existingToken, ConfigurationManager.AppSettings["MS_MasterKey"], claimsPrincipal);
You should probably also look up the user ID in your lookup table to avoid conflicts.
So overall that's a rough sketch of a possible solution. Unfortunately there isn't anything more turnkey.

Retrieving email: OpenId vs. classical authentication

I need to implement authentication for the project I am working on. But I can't make the choice: to use OpenId or not. The main question for me is how to retrieve user's email (it is critical for sending notifications) if user has logged in by OpenId. Of course, most OpenId providers return this information but I can't trust them (as anybody can set up an OpenId provider).
The ways I currently see are:
1. Support only OpenId providers that always return user email and to whom I can trust (it would be awkward to activate email in OpenId authentication scenario).
2. Forget about OpenId and use classical authentication.
What do you think?
Actually, the best idea would be to implement OpenID, but verify the email addresses anyway (or ask the user to provide them if the OP doesn't).
It's not awkward to require an user to verify their email if they're using OpenID -- the data returned by OP isn't guaranteed to be true.
And whatever you do, don't limit OpenID providers -- it'll only cause confusion. You could simply not verify the address if it comes from a known provider.

What are the advantages and disadvantages to using OpenID?

I'm currently debating whether I should use OpenID login for one of my websites. OpenID may be harder for me to implement because I already have registration and login code written, but this is just a time consideration. What advantages and disadvantages are there to using OpenID in contrast to, say, a traditional website user account system.
Advantages
you have a single sign-on which is actually pretty cool, in particular for people having a lot of accounts here and there.
The openid server provides basic info about the user, saving the need to write down the usual basic info every time. In this sense you save the hassle to your users.
It enhances the traditional user/pass mechanism pretty well. There are many sites around providing both systems at the same time.
Moves trust of honesty from multiple parties to only one. At the moment, I don't know if any of the sites I am registered on stores my password in clear text to steal it and tries to use it on other sites assuming that I have the same password.
The technical advantage of delegation. You are not forced to use the same provider. You can switch.
Disadvantages
You still have to provide user/password to those who don't understand the new paradigm or they don't have an openid (maybe they have it, but they don't know). If it's a broad range of people your are trying to address, then you could scare them away.
Also, I would not use it for anything serious. I would not trust my bank asking me to login with my openid, but also many e-commerce sites as well. It's ok for unimportant things.
The openid provider can track user's habits, as they receive all the auth requests. That's why I deployed my personal provider.
Finally, as far as I saw, many cases of openid servers move the password in cleartext, but this is my understanding and I could be wrong. I deployed my own openid provider, and I went to great deal so that the password was transported via https, even if my openid is marked as http
The main advantage that I see, although not necessarily applicable in your case if you want keep your existing system, is that I don't have to worry about storing passwords.
Too many people use the same password (or a small set of passwords) for everything, so if my site was compromised (and I'd hope I was sufficiently skilled enough to prevent that, but security is a multi-layers beast, so anything to add extra security in is good in my book) then the attacker couldn't get hold of the password.
For the user, they can now legitimately have just one password for everything. They use an OpenID Provider that they trust rather than having to trust any tom dick or harry on the internet with a website.
Well taking SO as an example it supports both. I login using my Google Account through OpenID but I still need to have an account/username to link to my OpenID. I assume that you're only allowing logins through OpenID but not for your users to login using your site as an OpenID server.
So to clear things up; You can use a lot of your login/logout code and you will need it because the only difference is that you authenticate through a third-party instead of your own database. In pseudo-code imagine this:
authenticate_from_db(String username, String password)
{
fetch username and password where username = username
if username = username and password = hash_of(password)
{
return true;
}
else
{
return false;
}
}
authenticate_from_openid(String openId_provider)
{
provider = contact_openID_provider(openID_provider)
if(provider)
{
login.username = map(returned_user, your_db)
return true
}
else
{
return false;
}
}
So you see, mostly the authentication process is changed while your own is still also used.
The advantage is pretty clear:
Allowing users to login with existing accounts through their OpenID provider.
Your existing users could optionally login through their OpenID provider
The disadvantages are (I could imagine):
Hostile OpenID providers (spam?) authenticating their spambots etc
Other security concerns by allowing a third party to authenticate your users
I want to underline that supporting OpenID should not change anything for your existing users.
OpenID users still need to have an account, they're just authenticated through a third-party.