B2B Org assignment on first login: how to avoid the "personal account" prompt with organization_usage: "allow"?

We’re migrating users from Cognito to Auth0 using a custom DB connection with import_mode: true (lazy / automatic migration). All non-SSO orgs share a single user-pool DB connection. The intent is fully B2B — every user must belong to an Organization, no individual accounts.

We have a pre-built map of email/domain → [org_id, ...]. When a user lands on /authorize with an organization parameter, everything works: the JIT login script validates their Cognito password, Auth0 creates the user, assign_membership_on_login: true attaches them, login completes.

The problem is the bare URL case (no organization param):

  • With organization_usage: "require": the “user must belong to an org” check fires before any Post Login Action. The Action never runs, so we can’t pre-attach memberships. Login fails with "client requires organization membership, but user does not belong to any organization".

  • We can’t use Pre User Registration because event.organization isn’t exposed there, and pre-importing the user kills the lazy password migration (login script no longer fires for imported users).

  • Switching to organization_usage: "allow" does work: the Post Login Action runs, looks up the email in the map, calls organizations.members.create(...), and the user is attached during login.

The catch: with "allow", the post-login org picker now offers “Continue with personal account” alongside the user’s orgs. We don’t want that — it’s a strict B2B app.

Question: Is there a way to either:

  1. Run a Post Login Action before the org-membership check fires, or

  2. Hide the “personal account” option while keeping organization_usage: "allow" (so the Post Login attach works), or

  3. Some other native pattern for “lazy migrate from legacy DB + assign user to org by email domain on first login + no personal accounts”?

    Thanks!

Hi @marianoc

Welcome to the Auth0 Community!

I will need some time to investigate and I will come back with an update later today!

Kind Regards,
Nik

Hi again!

  1. Run a Post Login Action before the org-membership check fires, or

No. The authentication pipeline order is strictly fixed: Custom DB Login → Auth0 Internal Org Check → Post-Login Actions.

  1. Hide the “personal account” option while keeping organization_usage: "allow" (so the Post Login attach works), or

Not via a simple toggle in the Dashboard. The button is hardcoded into the Auth0 Organization Picker when usage is set to "allow" .

However, you can achieve your goal of “lazy migration + assign to org + no personal accounts.” You have two paths forward:

  1. The cleanest, most native way to solve this is to never send the user to a bare /authorize URL. Instead of relying on Auth0 to ask for the email and figure out the routing, move the initial email prompt to your application.
    ->The user lands on your application and enters their email address: yourapp.com/login .
    ->Your frontend calls a lightweight, unauthenticated endpoint on your backend: GET /api/org-lookup?email=user@domain.com . Your backend returns the org_id .
    ->Your application redirects the user to Auth0, explicitly appending the parameter: /authorize?organization=org_id...
    ->Because the organization parameter is present, you can safely set organization_usage: "require" . Auth0 knows the target org immediately, the Custom DB script fires, the user is migrated, assign_membership_on_login triggers, and the flow completes without ever showing an Org Picker or a Personal Account button.

  2. If you cannot build a login screen on your application and must use the Auth0 Universal Login page as the starting point, you can use the Auth0 Actions Redirect feature to perform a silent SSO bounce.
    → Set organization_usage: "allow" .
    → The user logs in via the bare URL. Your Post-Login Action fires. Since they didn’t pass an org, event.organization is undefined.
    ->The Action looks up the mapping, uses the Management API to assign the user to the org_id , and then immediately interrupts the login flow using api.redirect.sendUserTo() :

exports.onExecutePostLogin = async (event, api) => {
  if (event.organization) return;

  const targetOrgId = await assignUserToOrg(event.user.email);

  const bounceUrl = `https://yourapp.com/api/auth/bounce?org=${targetOrgId}`;
  api.redirect.sendUserTo(bounceUrl);
};

->The user lands on yourapp.com/api/auth/bounce . That route does absolutely nothing except issue an immediate HTTP 302 Redirect back to Auth0:
/authorize?organization=org_id&prompt=none&...
2.->Because you appended prompt=none , Auth0 recognizes the user’s active session, securely drops them into the specific Organization context without prompting them for a password or showing the Org Picker, and returns the tokens to your app.

Hope this helps, if you have any other questions or issues, let me know!

Kind Regards,
Nik

Thanks Nik, super helpful.

Quick follow-up on Option 2 (silent bounce): how does it handle users who belong to multiple orgs? Around 10% of our users are in this case. Since the bounce uses prompt=none, the Action can’t prompt the user to pick right?

The options I see are: (a) auto-pick a default in the Action and let them switch in-app afterwards, or (b) redirect to a picker page on our side first, then bounce — but at that point we’re rebuilding most of Option 1.

Is there a third path I’m missing, or is auto-default the only clean option for Option 2 with multi-org?

Thanks!

My pleasure.

In the context of a user belonging to multiple organizations during JIT, the solution is not as clean as you might expect.

The recommended solution in order to have a good end user experience would be to redirect these type of users to your application normally in order to receive the “user does not belong to organization” error in order to silently authenticate them and have them redirected to the organization picker.

To explain how this flow would behave for both types of user:

  • Users only with one organization
    → User logs in during migration
    → Is assigned organization
    → Gets redirected to the proper /authorize url containing the org_id
    → Is authenticated within the organization context

  • Users with multiple organizations
    → User logs in during migration
    → Is assigned multiple organizations
    → Action detects that the user is part of multiple organizations
    → Application catches and handles the error and performs a silent authentication for the user
    → User is redirected to the organization picker
    → Is authenticated within the selected organization’s context

I just realized that i did not inquire regarding if you are creating these organizations during migration or they are created ahead of the user. If you need extra help on this matter or some examples, let me know!

Kind Regards,
Nik

Thanks Nik!

Two clarifications:

  1. Orgs are already provisioned ahead of time via a custom script — the orgs exist in Auth0 before anyone logs in. Just JIT migrating users into them.

  2. About the picker you mentioned for the multi-org scenario (“User is redirected to the organization picker”) — which picker is that? Under organization_usage: "allow" (needed for the Action/bounce to run), Auth0’s post-login picker includes a “Continue with personal account” button. That’s exactly the UI we want to avoid (strict B2B, no individual accounts). Is there an Auth0-hosted picker mode that excludes the personal-account option while keeping "allow", or were you referring to a custom application-hosted picker?

  3. Returning users — even with the bounce working for first-time logins, already-migrated users hitting the bare URL still see the picker (with the personal-account button), because post_login_prompt fires before Post Login Actions when the user has memberships. We’d need to flip organization_require_behavior to no_prompt for the Action to consistently get control on every login. Does that combo (allow + no_prompt + bounce) match what you intended, or are we missing something?

Thanks!

Hi again !

That’s exactly the UI we want to avoid (strict B2B, no individual accounts). Is there an Auth0-hosted picker mode that excludes the personal-account option while keeping "allow" , or were you referring to a custom application-hosted picker?

Have you switched back to only allowing business users for your organization or do you still have it set to Both?

already-migrated users hitting the bare URL still see the picker (with the personal-account button)

At this point, you should have set your organizations settings only to business users and NOT BOTH.
Can you confirm that these issues arise when you have it set to only business users?

Kind Regards,
Nik

Hi Nik — small mix-up. We’re on allow because your Option 2 (post #4) told us to be. We tried require first and got the “user does not belong to any organization” error, which can’t even produce a picker issue since login fails before the action runs to associate the user with the organizations.

Could you clarify which path you’re now recommending?

(a) Drop Option 2, go with Option 1 (app-side email prompt + require). Not ideal since require custom solution on our side.

(b) Stick with Option 2 — in which case my three questions from post #7 still stand.

thanks!

Oh yeah, thanks for pointing that out, I did indeed mix things over with another issue I was investigating regarding organizations.

Allow me to double check everything and I will get back to you regarding the matters.

Kind Regards,
Nik

Hi again @marianoc

Sorry for the delayed response to the matter.

I believe there is a big mix-up between us regarding the provided solution and implementation.

The Option 2 I have suggested above would require you to have your app’s Login Experience set to Business Users. Since you are using a PostLogin Action to redirect the users which are being migrated, they will not be presented with the error :“User must belong to an organization” because they do not have an org assigned at that time.

The purpose of the redirection is to have the user log in again on the proper /authorize url containing the assigned org id so they can authenticate successfully.

This is a little different for users with multiple orgs, the same happens but they should have a silent auth performed in order for them to be redirected to the org picker. As long as the application is set to Business Users, they will be met with an org picker and NOT the initial Continue with personal account / Continue with org. Knowing this, since all of your users belong to an org, you should not be using BOTH.

Let me know if that clarified things for your set-up or if I can help with anything else.

Kind Regards,
Nik