I have the following post-login action which is intended to modify a user’s app_metadata if they originate from one of 2 Enterprise Connections.
// Set app_metadata organization = <company_name> if logging in from <company_name> Okta or Azure AD
exports.onExecutePostLogin = async (event, api) => {
if (event.connection.id === "<okta-connection-id>" || event.connection.id === "<azuread-id>") {
api.user.setAppMetadata("organization", "<company-name>");
};
};
We have a SAML-integrated application that expects a “http://schemas.auth0.com/organization” attribute in the user’s SAML assertion on login. However, when a user logs in to our SAML-integrated Application for the first time, and the Auth0 user profile is first created, that first SAML assertion lacks this attribute and the user is denied access at the application.
Subsequent SAML assertions have the organization attribute and login works fine.
Is this behavior expected? My understanding was that the post-login action should be firing before auth data is sent by OIDC or SAML to the app. So it is confusing to me why this first login is failing.
Anything suggestions to achieve the desired result and avoid the initial login failure which is a bad UX and results in support calls?
Issue: Post-login action not reflecting in the first SAML assertion, causing missing attribute and login failure.
Root Cause: Post-login actions in Auth0 execute after authentication but before the SAML assertion is generated. However, it might not be immediate, causing a delay in the first login.
Solutions:
-
Pre-Registration Hook: Use a pre-registration hook to set app_metadata
when the user is first created.
exports.onExecutePreUserRegistration = async (event, api) => {
if (event.connection.id === "<okta-connection-id>" || event.connection.id === "<azuread-id>") {
api.user.setAppMetadata("organization", "<company-name>");
}
};
-
Rule-based Approach: Use Auth0 Rules, which are synchronous and execute as part of the authentication pipeline.
function (user, context, callback) {
if (context.connectionID === "<okta-connection-id>" || context.connectionID === "<azuread-id>") {
user.app_metadata = user.app_metadata || {};
user.app_metadata.organization = "<company-name>";
auth0.users.updateAppMetadata(user.user_id, user.app_metadata)
.then(() => {
callback(null, user, context);
})
.catch((err) => {
callback(err);
});
} else {
callback(null, user, context);
}
}
-
SAML Attribute Mapping: Directly map the organization attribute in the SAML configuration.
{
"mappings": {
"http://schemas.auth0.com/organization": "app_metadata.organization"
}
}
-
Retry Logic: Implement retry logic in your application to handle the first-time failure gracefully.
Choose the one that best fits your architecture and requirements.
Thanks @suchislife801. Unfortunately I don’t think any of your proposed solutions would work (or in the case of rules would continue to work past the sunset of rules).
Pre-Registration Hook: Not applicable to our use case as described as our users are Enterprise users and pre-registration only fires for database/passwordless users.
Rule-based Approach : We can try this, but rules are deprecated and will be fully sunsetted by Nov 2024.
SAML Attribute Mapping : I think this is chicken-egg. If the action is firing too late in the flow, the app metadata won’t be there to map.
Retry Logic : The application code is not under our control
Hey there!
As this topic is related to Actions and Rules & Hooks are being deprecated soon in favor of Actions, I’m excited to let you know about our next Ask me Anything session in the Forum on Thursday, January 18 with the Rules, Hooks and Actions team on Rules & Hooks and why Actions matter! Submit your questions in the thread above and our esteemed product experts will provide written answers on January 18. Find out more about Rules & Hooks and why Actions matter! Can’t wait to see you there!
Learn more here!