After importing many users and a few days of testing I have made the following critical-level discovery:
A user authenticates with a email-password firstname.lastname@example.org. Auth0 returns an object with user_id: auth0|asdfqwer1234
- Auth0 creates a record in the database.
- Django authenticates this user using that id; if not found then creates a fresh user profile. Cool.
Same user later logs in using our newly crafted Auth0 Facebook login feature. Their email address is the same email@example.com, but here’s what happens:
- Auth0 creates a new record in the database
- Auth0 returns user_id: facebook|zxcvyuio4321
- Django looks for this user_id, doesn’t find it, and creates a new fresh user profile. Not cool.
So, Auth0 has two users with the same email address and my application has two distinct users who don’t share information. Strangely, when authenticating using the spa sdk, the user_id prefix is whatever the connection method is - however when you export these users, the user_id prefix is now auth0 for every user, no matter their connection/creation method.
Unfortunately this is a show stopper to using Auth0. Modifying the Django auth seems a ridiculous solution, and could introduce new security flaws. I wanted to put this info out there in case a solution is available, and also to warn others of the behavior.
I might be worth separating some concerns here to clear out some of the confusion.
- Auth0 considers each users coming in from different identity providers as different identities, even if they share the email address. So, like you say, firstname.lastname@example.org coming from a database connection is different from email@example.com coming from Facebook and is different from firstname.lastname@example.org coming from Google. Each will have its individual user profile entry in Auth0 and each will receive its own user id.
- What an application does with a new user id is received is pretty much the responsibility of the application. For example, an app might say “Hey, you previously logged in using a Facebook identity. Would you like to create a separate identity or use the previous one?”. There are different use cases and requirements so I would be impossible to come up with a solution that works for everyone.
- Having said that, Auth0 provides the Account linking feature that can link two different identities into one, so that a user can use either authentication method but the application sees only one user ID (and only one user profile remains in the Auth0 side).
Account linking can happen either automatically via a rule (i.e. it detects two identities with the same verified email address so it automatically links the two identities) or can be used from an application (e.g. the application presents the facts to the user and lets the user chose if they want a linked identity or not). Be sure to read the linked doc for details.
- I’m not familiar with the specifics of the Django SDK, maybe someone can provide alternative solution (like using the email as the ID).
Hope that helps!
The separation of identities can be a good one, and judging from the forum otherwise no one else has really found this to be an issue. Perhaps there’s some mechanics in the Django auth system I’m not understanding that is really the root of the issue.
There are methods to use email auth with Django and Django Rest Framework, and they are documented on SO pretty well, however my concern is that rolling my own auth solution removes Django’s updates and moves the auth security once again into my hands. I’m just trying to stay as lean as possible, so this particular solution may not work for me.
Very quick response, which I do appreciate.
The automatic linking if identities by using an Auth0 rule might be a good solution for you. It’s a way of keeping the solution on the identity provider side, without having to touch the application (because the application will always receive the same user id, regardless of the authentication method used).
Note that the default linking rule checks that the user has a verified email address, otherwise it won’t attempt to link the identities (for security reasons). You might want to couple that set up with another rule that prevents authentication if the email address is not verified, to prevent the app from ever getting user information that could be just transient.