Registering user against custom database connection with auto-migration doesn't work

I feel I’ve missed some vital piece of information here. I’m currently using the Username-Password-Authentication connection with custom database to auto-migrate users when they first login. I have the Login and GetUser scripts working great.

My login page uses the auth0.js library with the Username-Password-Authentication realm.

I’m struggling to understand how registering new or existing users (in my local DB due to unable to auto-migrate; forgotten password, bulk import etc). Is this possible using that same connection?

If I sign them up to a new connection, it will be different to the one I’m using for logging in and as I’m no longer storing password, they can’t migrate into that connection, behaviour I wouldn’t want anyway.

I understand that the GetUser scripts will execute each time, so if I first try to save to auth0, I get a 404 User not found. So I switch this and save locally first. I then get the user already exists error. I’m unable to register new users or manually migrate users to this connection.

How am I supposed to tackle this? Again, I’m sure I’ve missed something obvious.

Hi Josh,

This should just work. If you try the connection you should see the Auth0 login page, with a tab for “Sign Up”. Click on that and you can register a new user in that connection.

John

Hi John,

Nope, this doesn’t work. For both new users and those within my DB I get the generic “WE’RE SORRY, SOMETHING WENT WRONG WHEN ATTEMPTING TO SIGN UP.” error. The logs tell me if I try to signup for an existing user I get the log error of type ‘Failed Signup’ ‘The user already exists.’ But for those users that don’t exist in my DB I get a nice 404 html page returned.

Again, these actions are taken against a custom DB connection with auto-migration enabled.

At this point I can only suggest checking the tenant logs for the details of the error, and putting some debug info in the scripts to figure out what is going on.

John

1 Like

Are you saying that registering to the database should not trigger the GetUser scripts? Because that’s not the case. I should note that I’m doing handling the login and getuser script via API. From my GetUser endpoint I return a 404 if the email is not found, or the user profile info.

Only write your custom login script in connection ->login tab only. Don’t write any piece of code in get User tab.
Try and let us know if works.

1 Like

Thanks for help on this front @rashid779939!

1 Like

So the I’ve been reading the documentation on this: https://auth0.com/docs/connections/database/custom-db/templates/get-user and it says for legacy authentication any operation such as create user, change email etc with fire this script. We don’t want legacy authentication, only the ability to migrate users across.

So here are my findings: If I simply return the callback directly without any custom code using this script: function getUser(email, callback) { // TODO: implement your script return callback(null); } I get the following response { "error": "access_denied", "error_description": "Cannot read property 'email' of undefined" } and the log Failed Login with error ‘Cannot read property ‘email’ of undefined’. But the user is created.

Next if I simply have no script I get Failed Signup with error ‘Invalid response code from the auth0-sandbox: HTTP 400. Unexpected token )’ and no user gets created.

I also followed this guide: https://auth0.com/docs/users/guides/configure-automatic-migration and swapped out the GetUser action script with the one described once migration is complete and get the same access_denied error.

So I think, the error "Cannot read property 'email' of undefined" may have been caused by an error in a rule. Although I swear I disabled rules when trying this. So I corrected the error and simply return the callback from GetUser and I can now register. Is this the correct approach because I will proceed accordingly if it is.

Hey @JoshB2B I’m a little confused on what’s your current status. But, just to be clear, when you are doing a lazy migration (custom dB with import mode ON) then the get user script is supposed to retrieve the user profile from the custom DB, if the user exists.
When someone tries to use the Signup endpoint (which would create a user in Auth0) Auth0 will execute the get user script, to make sure you won’t end up with a duplicate entry for the user, one in the custom db and one in Auth0 (which possibly different passwords). If the Get User returns undefined, then the user can be created in Auth0. If the Get User returns a profile, then the user is expected to log in once so that the user can be automatically migrated.

Does that make sense?

Thanks. The GetUser implementation our side is done via API and returns a 404 response if the user profile with the provided email cannot be found. This doesn’t allow the user to be added to Auth0.

At the moment we are still storing the user profile (excluding passwords) in our custom DB, so when the user signs up I register them in the custom DB first. I then use the ManagementAPI to register them within auth0. I could also do the reverse and add them to auth0 first, then create them locally (incase the email already exists from having migrated or registered in another one of our applications). We will also be bulk migrating users and generating a random password for auth0, then triggering the reset password email, or if possible a custom email template.

I’m not sure I’m following this. The GetUser script (on the Auth0 side) is supposed to return either a user profile (if the user exists) or null if the user doesn’t exist. Is that what you are doing? If that’s the case, Auth0 should allow creating new users.

That’s bound to cause problems: if you create the user in the external DB first, then a properly written Get User script would return that profile, meaning that the Management API would reject the creation of the user (“User already exists”).

We could also do the reverse and add them to auth0 first, then create them locally (incase the email already exists from having migrated or registered in another one of our applications). We will also be bulk migrating users and generating a random password for auth0, then triggering the reset password email, or if possible a custom email template.

I feel that, at this point, I’m kind of lost in terms of whether you are having problems or not. Perhaps I’m not understand the desired outcome either. Are you looking to:

  • Keeping the users in an external DB: a regular custom DB in Auth0
  • Lazy migration of the users (as they log in): a custom DB with import mode ON
  • Bulk migration of users: a regular DB connection, in which you import users from another source (you can now import hashes in many different formats, so users don’t necessarily have to reset their passwords)

So it looks like I made the error of returning 404 from my API instead of NULL, I can fix that (maybe I missed this in the documentation). Your point of registering a user to Auth0 that already exists in my local DB is correct. The user is rejected with the error ‘user already exists’.

My desired outcome is both lazy migration and bulk migration. Is this possible using the same connection? I tried using two connections but you still have to specify which connection to use when logging in. If I use the migration connection, the user will get migrated and exist in both connections. Should a rule to merge profiles fix this?

I really didn’t find anything handing this scenario, but then there is a lot of documentation and I could have missed it.

Maybe I wasn’t clear about that, but the API can return whatever you want as long as the script returns the expected contract. I.e. this is fine:

function getUser(email, callback) {

  request.get("https://yourAPI/users/" + email, function(err, res, body) {
    if (err) {
      callback(err);
    }
    if (res.statusCode === 404) {
      // convert the 404 response from the API into
      // a null profile, to signal that the user doesn't exist
      return callback(null, null);
    }
    var profile = {
      user_id: body.id,
      [...]
     };
     callback(null, profile);
  });

}

My desired outcome is both lazy migration and bulk migration. Is this possible using the same connection? I tried using two connections but you still have to specify which connection to use when logging in.

Generally, you’d want only one connection, unless you are looking to isolate different sets of users for some very good reason.

It sounds as if what you are looking for could be a custom DB with import mode on (i.e. lazy migration) and, when you have a set of users that you want to import, you can do so into that same connection
(using the bulk import feature).

When a user tries to log in Auth0 will look internally first. If not found, it will try the login script.
When you try to create a user, Auth0 will also look internally, and if not found it will also use the Get User script to ensure that the user doesn’t already exists in the external DB. The Get User script is also used for other flows, like the forgot password one.

When you create new users, you should do so in Auth0 (after all, you are trying to migrate users to Auth0). If you need some kind of shadow record in an external place, maybe you can use a post-registration hook, or simply insert that record as part of the user sign-up flow. I.e.:

User goes through registration screen -> create user in Auth0 -> create user somewhere else.

Not sure why you are trying to create the new user in the external DB as well, though. Those two records are likely to be out of sync eventually, unless you are very careful with updates.

This all looks very promising. The creation flow was one I had previously implemented. Having some duplicate info in both DBs is not ideal, but it’s a stop gap. This is a part of a much larger project, so little by little.

I modified my GetUser script accordingly and that looks better. I need to implement the correct approach to bulk importing as I was just registering the user.

I’ll see how I get on but you’ve been very helpful.

1 Like

Let us know @JoshB2B if you have any questions in the future!