Moving users out of a Base44 app: can they keep their passwords?

We’re moving an app off Base44 onto our own stack and the part I’m stuck on is the users. As far as I can tell Base44 doesn’t let you export password hashes, so a normal user export would force everyone to reset their password.

Is there a way to bring them over with their existing passwords, ideally ending up in Auth0 or our own backend?

Hi @n001spartan

Welcome to the Auth0 Community!

You are asking whether users can move from Base44 to Auth0, or to your own backend, with their existing passwords intact, given that Base44 does not provide password hashes in its user export.

[Root Cause]

A standard user export does not include password hashes, so a plain export and import cannot carry passwords over. Auth0 accepts pre-existing hashes only through the custom_password_hash field in a bulk import, and only for supported algorithms and parameters.

[Solution]

The standard, battle-tested solution for this: Lazy Migration (also known as Just-in-Time (JIT) Migration or Shadow Authentication).

When a provider like Base44 does not expose password hashes (often due to security boundaries or platform lock-in), you cannot perform a bulk password import. However, you can intercept and capture credentials when users naturally log in.

Here is how you can implement this either directly in Auth0 or in your own backend:

Option 1: Using Auth0’s Built-in Automatic Migration (Recommended)

Auth0 natively supports this pattern out of the box through Custom Database Connections:

  1. Pre-seed User Profiles (Optional but recommended):

    • Export user metadata (user IDs, emails, names, roles) from Base44.

    • Bulk-import these profiles into Auth0 without passwords.

  2. Enable Automatic Migration in Auth0:

    • In the Auth0 Dashboard, navigate to Authentication → Database.

    • Create or configure a Database Connection.

    • Enable Custom Database and toggle on Import Users to Auth0 (Automatic Migration).

  3. Implement the Login Script:

    • Auth0 provides a node.js Login script executed whenever a user who does not yet have a password stored in Auth0 attempts to authenticate.

    • In this script, make an HTTP call to Base44’s authentication endpoint using the email and plaintext password supplied by the user:

     function login(email, password, callback) {
       const request = require('request');

       // Call Base44's login API
       request.post({
         url: 'https://api.base44.com/v1/auth/login', // Base44 auth endpoint
         json: { email: email, password: password }
       }, function(err, response, body) {
         if (err) return callback(err);
         if (response.statusCode === 401 || response.statusCode === 403) {
           return callback(new WrongUsernameOrPasswordError(email));
         }
         if (response.statusCode !== 200) {
           return callback(new Error('Base44 authentication error'));
         }

         // Successfully authenticated against Base44
         return callback(null, {
           user_id: body.id || body.user_id,
           email: email,
           email_verified: body.email_verified || true,
           name: body.name
         });
       });
     }
  • What happens next: Once Base44 returns a success code, Auth0 receives the callback, automatically hashes the password using bcrypt, and stores it in Auth0’s secure database. Subsequent logins authenticate directly against Auth0, completely bypassing Base44.
  1. Implement the Get User Script (for Password Resets):

    • Auth0 also uses a Get User script. If a user clicks “Forgot Password” before they have logged into Auth0 for the first time, this script queries Base44 to confirm the user exists so Auth0 can initiate the reset flow.

Option 2: Implementing Lazy Migration in Your Own Backend

If you are handling authentication in your own service:

  1. Pre-populate your database: Import existing users with a flag such as migrated: false and password_hash: null.

  2. On login request (POST /auth/login):

    • Check your local database for the user:

      • Case A: password_hash exists: Authenticate normally against your local hash (e.g., using Argon2id or bcrypt).

      • Case B: password_hash is null (or user flagged unmigrated):

        1. Call the Base44 auth API in the background using the incoming email and plaintext password.

        2. If Base44 returns failure: Return 401 Unauthorized to the user.

        3. If Base44 returns success:

          • Hash the plaintext password locally using your chosen algorithm.

          • Save the new hash to your database and set migrated: true.

          • Return your own session/JWT token.

  3. The next time the user visits, they are authenticated entirely within your system.

[Migration Strategy & Edge Cases to Consider]

  • The Long Tail (Inactive Users):

    • Typically, 80–90% of active users will log in and migrate seamlessly within 30 to 60 days.

    • For remaining dormant users, set a sunset date (e.g., 90 days). Once you shut down the Base44 account, any unmigrated user who returns later will simply be prompted to use the “Forgot Password” flow to set a new password.

  • Social Logins (Google, GitHub, Apple):

    • If any users authenticate via OAuth/social providers on Base44, no passwords need to be captured. Configure the same OAuth clients in Auth0/your backend and map users by their verified email address or provider ID.
  • MFA / 2FA:

    • MFA secrets (TOTP seeds, SMS setups) cannot be migrated via lazy auth. Migrated users will need to set up their MFA authenticators on your new platform upon their next login.
  • Contacting Base44 Support:

    • Before building scripts, submit a support ticket to Base44 asking if they offer a manual/compliance export of user password hashes (e.g., encrypted S3 dump or PGP-encrypted file). Some BaaS providers support this as an enterprise/ad-hoc service even when it is not in the self-service UI.

Kind Regards,
Nik