Password Delivery Is the Last Manual Step in Onboarding

By Sandra Saluti May 18, 2026
New employee locked out on first day — automated password delivery with Entra ID Lifecycle Workflows

Accounts don’t always get created on the hire date. HR systems feed into provisioning pipelines days or weeks early. Managers put in requests ahead of time. IT gets ahead of the queue. Sometimes someone just creates the account manually because it’s easier than waiting for automation to catch up.
However it happens, the result is the same. The account exists. A password gets generated. And that password has to go somewhere — usually a manager’s inbox — weeks before the employee starts. The account sits there, enabled, inactive, with a known credential and no one watching it.
Then day one arrives. The new employee sits at their desk. The account exists. Access is provisioned. They just can’t log in — which is the one thing they actually need to do.
The person sorting it out is usually dealing with ten other things at 8am on a Monday. The first experience the employee has with IT is waiting.
It’s also an unnecessary burden on the manager. Getting a password to a new employee means knowing the right process, reaching the right people during office hours, and figuring out how to pass a credential on securely. Most managers don’t think about any of that. They just want their new team member to be able to work. Which is fair. That’s their job.

Manual password process flow — manager opens ticket, IT generates password, email chain to employee

The workaround that makes it worse

Picture this. A new hire starts in three weeks. The manager puts in the request early, IT creates the account, and the automation fires off a welcome email with a temporary password. Job done. The account sits there, enabled, for three weeks. It has never been logged into. No activity, no baseline, nothing to compare against. If that password ends up in the wrong place — a forwarded email, a Teams message, an inbox someone else has access to — and someone logs in, Entra ID sees nothing unusual. There’s no behavior to deviate from. The first login just looks like the first login.
Nobody is watching. The manager isn’t thinking about it anymore. IT closed the ticket. The account is just sitting there, open, for three weeks.
Then, a few days before the start date, the manager realizes they still need to actually get the password to the new employee. The one from the email was complicated. Too complicated to read out over the phone or drop in a message. So the manager logs straight into the account and changes it to something easier. Something like Summer2026!. Because the last person got Spring2026! and consistency matters, apparently.
When a manager does this, forceChangePasswordNextSignIn is cleared. No admin action is recorded. Entra ID sees a normal user login and a normal password change. The new password inherits the tenant policy — which usually means it never expires. The sign-in log shows the manager’s device and location. No flags. No alerts.
The employee starts on day one, logs in, everything works. Nobody follows up. Six months later the account is still running on a password the manager picked, shared in a Teams message, never changed by the actual user — and Entra ID considers it perfectly valid. It stopped being a temporary password the moment the manager set it. It was never the employee’s to begin with.
There’s also the MFA problem. New users are usually excluded from MFA Conditional Access during onboarding because they need to register their authentication methods before MFA can be enforced. So when the manager logged in, there was no MFA prompt. In some cases the manager has also registered their own phone as the MFA method on the new account. MFA shows as enabled. It just isn’t protecting the right person.
And that password — the one the manager set — is sitting in a Teams message or an email somewhere in plaintext, with no audit trail and no expiry. The original temporary password is gone. This one isn’t going anywhere.
I have seen this more times than I can count. Different organizations, different industries, different levels of maturity — same outcome. If you work in IT long enough you probably have your own version of this story. The details change. The seasonal password usually doesn’t.

A process that doesn’t depend on anyone

The goal isn’t efficiency, though that’s a welcome side effect. The goal is a process that runs the same way every time, regardless of who’s on the service desk that morning, whether the manager remembers, or whether IT is swamped with ten other things at 8am on a Monday.
Think about what that looks like in practice. The hire date arrives. Nobody opens a ticket. Nobody calls IT. The account gets a password, the manager gets notified, and the employee can log in on day one. If they don’t log in within the expected window — because they’re in a different time zone, because onboarding ran long, because life happens — the account gets reset automatically and IT gets a heads up. No audit required to find it. No six month review where someone notices the account has never been touched.
And when someone leaves, the same process runs in reverse. The account stops working. Sessions are closed. No credential goes anywhere. Nobody has to remember to do it.

That’s the bar. Not complicated. Just defined.

The delivery mechanism is where most implementations fall short. Email to the manager is the path of least resistance — it works, it’s easy to build, and it’s better than the manual process in almost every way. But it still puts a credential in an inbox, and a manager with access to a temporary password and enough time will set Summer2026!. The only real fix is taking the manager out of the delivery chain entirely. The alternatives are covered in the next section. The architecture stays the same regardless of which one you choose — swapping the delivery mechanism is a single action in the Logic App, nothing else changes.

Sending through email is not the right answer

Email works. I use it in this solution. I am not proud of it.

Every organization I have worked with has ended up here at some point. Email is easy, it’s already there, and it gets the password to the manager without anyone having to build anything complicated. But a password in an email is a credential in plaintext, sitting in a mailbox that might be accessed from a personal device, forwarded by accident, or left open on a shared screen. The Logic App adds an audit trail and forces a change on first login, so it’s better than the manual process. The plaintext-in-inbox part doesn’t go away though.
The real fix is taking the manager out of the delivery chain entirely. If the manager never sees the password, they can’t log in as the employee, they can’t set Summer2026!, and they can’t forward it anywhere. The delivery step in the Logic App is a single action — swapping it out doesn’t touch anything else. The password generation, the reset, the follow-up logic, the offboarding branch — all of it stays exactly the same. You replace one HTTP call with another.

Password delivery alternatives — email, enterprise password manager, SMS, compared as Logic App HTTP action swap

Enterprise password manager. 1Password and Bitwarden both have REST APIs. The Logic App writes the credential to a vault, the manager gets a notification with a link. The password never travels through email. The manager can see it if they need to hand it over in person, but it’s one deliberate action rather than a credential sitting in an inbox for three weeks.

SMS directly to the employee. The manager never sees it. The employee gets a text on their personal phone before day one with everything they need to log in. Any SMS gateway with a REST API works — Twilio, Azure Communication Services, whatever your organization already has. The one dependency is a verified mobile number in the HR system before the hire date. That’s a data quality problem worth solving regardless.

Temporary Access Pass. Worth mentioning but a different conversation. TAP is designed to replace the first-login password entirely for passwordless onboarding, and Lifecycle Workflows has a built-in task for generating one. It only works cleanly if the organization is going passwordless end to end — cloud-only accounts, Entra-joined devices. For hybrid-joined devices the user still needs a password before TAP can be used to set up Windows Hello for Business. If you’re not on that path yet, TAP doesn’t solve the same problem this solution does.

One thing worth sorting out regardless of which delivery method you choose: Logic Apps store inputs and outputs in run history by default. Enable Secure Inputs on the password steps. It’s a small thing, easy to miss, and it means a credential isn’t sitting visible to anyone with access to the Logic App. Defeats the purpose of everything else if you skip it.

How it works

The solution has two parts: a Logic App definition and a PowerShell deployment function. The Logic App is the workflow. The PowerShell function deploys it, wires up the managed identity, assigns Graph permissions, configures the authorization policy, and registers the custom extension — one function call and you’re done.

The Logic App is registered as a custom task extension in Entra ID Lifecycle Workflows using Launch and continue mode. This matters because it means Lifecycle Workflows fires the Logic App and moves on immediately — there’s no callback, no held slot, no workflow run sitting open for five days waiting for a response. All the wait logic lives inside the Logic App itself. The trigger payload already includes the manager’s display name, email, and ID so there’s no separate Graph call needed to figure out who to notify.

On the hire date the Logic App:

  1. Generates a temporary password
  2. Saves the exact reset timestamp
  3. Resets the account via Graph PATCH with forceChangePasswordNextSignIn: true
  4. Emails the password to the manager via Graph sendMail
  5. Waits five days

After five days it checks two things:

  • signInActivity.lastSignInDateTime — has the user actually logged in at least once?
  • passwordProfile.forceChangePasswordNextSignIn — is this false, meaning the user changed the password themselves and not the Logic App?
Automated Logic App flow showing Is Onboarding Workflow condition splitting into two branches. True branch: generate password, reset account with forceChangePasswordNextSignIn true, email manager, wait configurable period, check sign-in and forceChangePasswordNextSignIn false. If stale: reset to unknown password and notify manager. False branch: reset to unknown password and revoke sessions.

Both must be true. Checking sign-in alone isn’t enough — forceChangePasswordNextSignIn is the reliable signal. If it’s still true, the user has never changed the password themselves, regardless of what the timestamps say.

If both conditions are met: nothing happens. The account is in the right state.

If not: the Logic App generates a new unknown password, resets the account to it, and notifies the manager to contact the service desk. Nobody has this password — not the manager, not IT, not the Logic App. The account is inaccessible until someone steps in manually.

For offboarding: the Logic App checks which Lifecycle Workflow triggered it. If the workflow ID isn’t in the onboarding list it goes straight to the offboarding branch — resets to an unknown password and calls POST /users/{id}/revokeSignInSessions. No email. No credential. Sessions closed, account locked.

Deploy it with the PowerShell script

powershell

Deploy-PasswordResetLogicApp `
    -SubscriptionId  "<subscription-id>" `
    -ResourceGroup   "rg-entra-governance-prod" `
    -LogicAppName    "la-Password-Reset" `
    -Location        "swedencentral" `
    -MailSender      "governance@yourcompany.com" `
    -OnboardingWorkflowIds @("<workflow-id>")

Run that once. The script replaces the placeholder values in the Logic App JSON, deploys via ARM REST API with System-assigned Managed Identity enabled, and assigns these Graph permissions:

PermissionPurpose
User.ReadWrite.AllRead and write user profiles
Mail.SendSend email as the governance mailbox
UserAuthenticationMethod.ReadWrite.AllReset authentication methods
AuditLog.Read.AllRead signInActivity — requires Entra ID P1/P2
User.RevokeSessions.AllRevoke sessions on offboarding
User-PasswordProfile.ReadWrite.AllReset password via passwordProfile
LifecycleWorkflows.ReadWrite.AllRegister and manage the custom task extension

The managed identity is also assigned the User Administrator Entra ID role — Graph API permissions alone aren’t sufficient for password resets via passwordProfile. The deployment script handles this The managed identity is also assigned the User Administrator Entra ID role. Graph API permissions alone aren’t sufficient for password resets via passwordProfile — this is one of those things that isn’t obvious until it fails in production. The deployment script handles it automatically.

The script also locks down who can trigger the Logic App. By default Logic Apps use SAS — Shared Access Signature — which means the trigger URL itself contains a secret key. Anyone who gets hold of that URL can call the Logic App. For a workflow that resets passwords that’s not acceptable. The script configures AADPOP — Azure Active Directory with Proof of Possession — which means only a caller that can prove it’s Lifecycle Workflows can trigger it. Once that’s done SAS is disabled. The URL still exists, the key still looks valid, but it no longer works.

The custom task extension is registered automatically. The only manual step after deployment is wiring it into your Lifecycle Workflow:

  1. Go to Entra ID → Identity Governance → Lifecycle Workflows
  2. Open the joiner workflow you want to use
  3. Select Tasks → Add task
  4. Search for Run a custom task extension and add it
  5. In the task settings select your extension from the dropdown — it will appear by the display name you set (default: Password Reset Extension)
  6. Set Task behavior to Launch and continue
  7. Save the workflow

For offboarding repeat the same steps in your leaver workflow. The same Logic App handles both — the Is Onboarding Workflow condition inside the Logic App routes the call to the correct branch automatically based on which workflow ID triggered it.

Managing the Logic App after deployment

Once deployed, most changes can be made directly in the Logic App designer in the Azure portal. You don’t need to redeploy from the script for every change.

Adding a new onboarding workflow ID

When you create a new joiner workflow in Lifecycle Workflows you need to tell the Logic App to treat it as onboarding. Open the Logic App in the Azure portal, go to Logic App designer, and click the Is Onboarding Workflow condition to open the panel on the right.
The condition uses an OR expression — each row compares the incoming workflow ID against one of your known onboarding workflow IDs. The left side is the workflow ID that Lifecycle Workflows sends in the trigger payload. The right side is your hardcoded onboarding workflow ID.

To add a new workflow:

  1. Click + New item at the bottom of the condition panel
  2. On the left side click fx and enter the expression triggerBody()?['data']?['workflow']?['id'] — this explicitly pulls the workflow ID from the trigger payload. There are multiple id fields in the payload so using the expression avoids any ambiguity
  3. Keep the operator as =
  4. On the right side paste your new onboarding workflow ID
  5. Click Save at the top

The Logic App will now treat calls from both workflows as onboarding and route them through the True branch.

Changing the wait period

Click the Wait For Login Period step in the designer. Change the duration to whatever fits your organization — 5 hours if employees are expected to log in on day one, 7 days if you have people starting across different time zones. Save. The follow-up check and the stale account reset both happen relative to this window, so the rest of the flow adjusts automatically.

Adding offboarding actions

The False branch of the Is Onboarding Workflow condition handles offboarding. The deployed Logic App already includes two actions here — reset to an unknown password and revoke all active sessions. The account becomes inaccessible immediately, without any credential going anywhere. If your leaver workflow also runs a disable account task, that covers the SSPR angle as well — a disabled account can’t use self-service password reset to get back in.

Changing the password complexity

Click Generate Initial Password or Generate Expiry Password to see the expression that generates the password. It uses a combination of guid(), rand(), and string manipulation to produce something that meets complexity requirements. Modify the expression if your tenant has specific password requirements beyond the defaults.

Changing the email template

Click the Email Manager step in the designer to open the sendMail action. The email body is written directly in the action — you can update the subject, the body text, and the formatting here without touching anything else. The password value is referenced as a dynamic expression so it will always pull through correctly regardless of what you change around it. Save when done.

Wrapping up

Security is about layers. No single control stops everything. Zero Trust is built on exactly this — assume breach, verify explicitly, use least privilege. Not because any one of those things is a silver bullet, but because together they make the attacker’s job meaningfully harder at every step.
Password delivery during onboarding is a small problem, but it’s a layer that most organizations have left uncontrolled. The manual process creates delays, produces credentials with no expiry and no audit trail, and opens attack windows on accounts that nobody is monitoring. The workarounds people reach for — sending passwords weeks in advance, letting managers log in as the employee — quietly remove layers rather than adding them.
This solution adds a few back. The password is generated and distributed by a system, not a person. The change is enforced, not optional. The stale account is handled automatically, not discovered in an audit six months later. None of that is complicated. It’s just governance — defining what the process is, and making sure it actually happens.
The email delivery is a starting point, not the architecture. The architecture stays the same when you replace it with something better.

Everything is at github.com/irean/EntraGovernance-Scripts under Logic Apps/Password Reset Logic App.

Author

  • I work with Microsoft Entra ID Governance and identity automation — lifecycle workflows, access packages, and the real-world edge cases that break standard solutions. Based in Sweden, working with organizations on their identity governance journey. Find me on LinkedIn.

    View all posts

Discover more from Agder in the cloud

Subscribe to get the latest posts sent to your email.

By Sandra Saluti

I work with Microsoft Entra ID Governance and identity automation — lifecycle workflows, access packages, and the real-world edge cases that break standard solutions. Based in Sweden, working with organizations on their identity governance journey. Find me on LinkedIn.

Leave a Reply