We are currently rolling out Auth0 for our services, and our setup involves supporting both business users and personal users. This means:
Some of our customers belong to organisations that have their own custom Auth0 login pages.
Other customers do not belong to any organisation and authenticate via a generic login page accessible to all users.
We have chosen to use the lazy migration strategy. I’ve managed to configure the get user and login custom database scripts to work successfully, allowing users to migrate from Cognito into Auth0. I’ve also set up Actions to assign users to their correct organisation on their first login when they authenticate through the generic login page.
The issue arises with legacy users who log in via an organisation-specific login page. Here’s what happens:
The get user and login scripts work as expected, and the user is migrated into Auth0.
However, immediately after this, authentication fails because the user is not yet a member of the organisation.
As a result, post-login Actions do not fire, making it impossible to assign the user to the correct organisation.
What I’ve Tried
Assigning the user to an organisation within the login script: This didn’t work because the user does not yet have a user_id during the login script execution.
Pre-User Registration Triggers: I encountered similar issues since these triggers don’t suit this use case.
Post-Registration Triggers: These are asynchronous, so they also didn’t solve the problem.
What I’m Looking For
I need a solution to achieve one of the following:
Redirect a newly migrated user (who attempts to log in via an organisation-specific login page) to the generic login page. This would ensure that post-login Actions can fire and assign the user to the correct organisation.
Alternatively, a way to assign a user to an organisation as soon as they are created (during the same flow as the custom database script execution). This would allow them to be both migrated and assigned to an organisation seamlessly.
I’ve searched the forums extensively but haven’t found a solution that works. Any guidance or suggestions would be greatly appreciated.
First, modify your get_user script to identify the user type and connection:
function getUser(email, callback) {
getUserFromCognito(email)
.then(async (cognitoUser) => {
// Add metadata about the connection and user type
const userData = {
email: cognitoUser.email,
user_metadata: {
migrated_from_cognito: true,
original_connection: connection.name,
is_business_user: determineIfBusinessUser(cognitoUser)
},
// ... other user properties
};
callback(null, userData);
})
.catch(err => callback(err));
}
Then, modify your login script to handle different paths:
function login(email, password, callback) {
authenticateAgainstCognito(email, password)
.then(async (success) => {
if (success) {
const isBusinessUser = user.user_metadata.is_business_user;
const connectionName = connection.name;
if (isBusinessUser && connectionName.startsWith('org-specific')) {
// Business user trying to login through org-specific page
// Redirect to generic login with special parameters
callback(null, {
redirect_url: `https://your-domain.auth0.com/login?` +
`migration=true&` +
`original_connection=${connectionName}&` +
`business_user=true`
});
} else {
// Personal user or already on generic login
callback(null, user);
}
} else {
callback(new WrongUsernameOrPasswordError(email));
}
})
.catch(err => callback(err));
}
Add a new Action to handle the organization assignment:
// Post-login action
exports.onExecutePostLogin = async (event, api) => {
if (event.user.user_metadata.migrated_from_cognito) {
const managementClient = await getManagementClient();
if (event.user.user_metadata.is_business_user) {
// Business user flow
const orgId = determineOrgFromConnection(
event.user.user_metadata.original_connection
);
await managementClient.users.assignOrganizations({
id: event.user.user_id,
organizations: [orgId]
});
// If came from redirect, send back to org login
if (event.request.query.migration === 'true') {
api.redirect.sendUserTo(
event.user.user_metadata.original_connection
);
}
} else {
// Personal user flow
await managementClient.users.assignOrganizations({
id: event.user.user_id,
organizations: ['default-personal-org']
});
}
}
};
Add a Universal Login page customization to handle the migration flow:
// In your Universal Login page
async function handleLogin(event) {
if (event.query.migration === 'true') {
// Show migration-specific UI if needed
await handleMigrationFlow({
business: event.query.business_user === 'true',
originalConnection: event.query.original_connection
});
}
// ... rest of your login logic
}
This solution:
Identifies user type during migration
Redirects business users to the generic login temporarily
Assigns appropriate organization membership
Returns business users to their org-specific login page