rud
rud3w ago

Microsoft Entra ID: eager create users in Extranal Authentication action doesn't quite work

This is for Zitadel 4.3.0, self-hosted. We are building an integration with Microsoft Entra ID. The use-case is for customers of our SaaS will have their Microsoft Entra Tenant ID whitelisted in our system. Once a user from an allowed Microsoft Entra ID tenant logs in, we want to automatically provision the user and give them the appropriate roles in Zitadel, then log them in. This is the flow we are trying to implement: - Zitadel login (v1 UI): user enters their email, the email domain matches an organization we have setup Microsoft Entra ID for, so a "Login with Microsoft Entra ID" button appears - User clicks that Microsoft button, logs in over at Microsoft Entra ID, and returns to Zitadel - We have a v1 Action setup on External Authentication for the organization, which makes a blocking HTTP call to an internal system we have built. In that internal system: - We verify the Microsoft Entra tenant is one with a paid subscription, lookup their access level and within the call will call back to the Zitadel API to create the User in Zitadel, and add the relevant roles to the User. Once the External Authentication Action completes, a user exists in Zitadel with the email-address returned from Microsoft Entra ID. - What we would like to happen next: user is silently and automatically logged in, as their user account exists and has access to a relevant system - What actually happens next: the "sign up" user form is shown, and the user ends up in a "account already exists" error state in the UI. What do we seem to be missing in our understanding or setup for this to be as smooth and elegant as things usually are in Zitadel? Would trying out the beta Actions v2 be any help? If Actions v2 are indicated, what triggers/flow would be relevant to build upon?
1 Reply
Ask Inkeep
Ask Inkeep3w ago
Hi @rud, I'm an AI assistant for ZITADEL. While a team member reviews this question, I'll see if I can find relevant sources for your question. Answer Based on the available sources, I can see there's a known issue that might be directly related to your problem. There's a documented GitHub issue where user grants are not persisted after action calls in external authentication post creation triggers (1) . This could explain why your user creation in the action isn't resulting in the expected automatic login flow. For Microsoft Entra ID integration, the standard approach documented is to use ZITADEL's built-in user provisioning features rather than manually creating users via API calls within actions (2) . The external authentication flow should handle user creation automatically when properly configured. Here are the key settings you should verify in your Microsoft Entra ID provider configuration : - Automatic creation: Should be enabled to allow ZITADEL to automatically create users when they don't exist - Automatic update: Should be enabled to sync user data from Entra ID - Account creation allowed: Must be enabled for new user provisioning - Account linking allowed: Should be enabled if you want to link existing accounts For user data pre-filling, there's a documented action example for Entra ID SAML that handles user provisioning (3) (2) :
function prefilRegisterFromEntraId(ctx, api) {
if (ctx.v1.externalUser.externalIdpId != "<SAML SP id>") {
return
}
let firstname = ctx.v1.providerInfo.attributes["<http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname%22%5D;>
let lastname = ctx.v1.providerInfo.attributes["<http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname%22%5D;>
let email = ctx.v1.providerInfo.attributes["<http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress%22%5D;>
if (firstname != undefined) {
api.setFirstName(firstname[0]) ;
}
if (lastname != undefined) {
api.setLastName(lastname[0]) ;
}
if (email != undefined) {
api.setEmail(email[0]) ;
api.setEmailVerified(true) ;
}
}
function prefilRegisterFromEntraId(ctx, api) {
if (ctx.v1.externalUser.externalIdpId != "<SAML SP id>") {
return
}
let firstname = ctx.v1.providerInfo.attributes["<http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname%22%5D;>
let lastname = ctx.v1.providerInfo.attributes["<http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname%22%5D;>
let email = ctx.v1.providerInfo.attributes["<http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress%22%5D;>
if (firstname != undefined) {
api.setFirstName(firstname[0]) ;
}
if (lastname != undefined) {
api.setLastName(lastname[0]) ;
}
if (email != undefined) {
api.setEmail(email[0]) ;
api.setEmailVerified(true) ;
}
}
For adding user grants, there's also a documented example (3) :
function addGrant(ctx, api) {
api.userGrants.push({
projectID: '<the projects resource ID>',
roles: ['<the role key>']
}) ;
}
function addGrant(ctx, api) {
api.userGrants.push({
projectID: '<the projects resource ID>',
roles: ['<the role key>']
}) ;
}
However, based on the GitHub issue (1) , there seems to be a problem with user grants not persisting in post creation triggers, which might be affecting your flow. Instead of creating users manually via API calls within your action, I'd recommend: 1. Configure your Entra ID provider with automatic creation enabled 2. Use Pre Creation or Post Authentication triggers to handle user data mapping 3. Use Post Creation triggers for adding grants (though be aware of the potential persistence issue ) Regarding Actions V2, the sources don't provide specific information about whether it would resolve your particular issue, but there are discussions about migrating from V1 to V2 actions (4) . For the most current guidance on this specific integration pattern, you might want to click the "Ask for help" button to get assistance from a team member who can provide more specific guidance for your ZITADEL 4.3.0 setup. ​ To learn more, see the sources I considered: [1] [Bug]: User Grants are not persisted after action call in external authentication trigger type post creation [2] Configure Entra ID as a SAML Service Provider in ZITADEL [3] Code examples [4] V1 Actions (Complement SAMLResponse → Pre SAMLResponse creation) not triggering for SAML login ​ Feel free to tag @Ask Inkeep with additional questions.

Did you find this page helpful?