Wicked Smart Data
LearnInsightsAboutContact
Sign InLet's Build
LearnInsightsAboutContact
Sign InLet's Build
Wicked Smart Data

Intelligence, automation, and expert execution — plus an elite library of free knowledge. We turn complexity into competitive advantage.

Start a conversation

Platform

  • Learning Paths
  • Insights
  • RSS Feed

Company

  • About
  • Contact
  • Work With Us

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Wicked Smart Data. All rights reserved.

Intelligence · Automation · Advantage

All Insights
Power Automate

Automating Web Application Login and Session Persistence in Power Automate Desktop: Handling Cookie Consent, SSO Redirects, and Session Timeouts in Unattended Browser Flows

Unattended browser flows fail silently when they hit SSO redirects, cookie consent banners, and session timeouts at 2 AM. This lesson teaches you how to architect login flows that handle all of it — with persistent browser profiles, conditional consent handling, and mid-flow session recovery.

⚡ Practitioner25 min readNov 4, 2026Updated Nov 4, 2026
Automating Web Application Login and Session Persistence in Power Automate Desktop: Handling Cookie Consent, SSO Redirects, and Session Timeouts in Unattended Browser Flows
On this page
  • Introduction
  • Prerequisites
  • Understanding What Actually Happens During a Web Login
  • Setting Up Your Browser Profile for Unattended Flows
  • Launching Chrome with a Persistent Profile
  • Clearing Stale Profile State
  • Handling Cookie Consent Banners
  • Navigating SSO Redirects: Azure AD and Entra ID Flows
  • Step 1: Navigate to the Application and Detect Where You Land
  • Step 2: Handle the Microsoft Login Form
  • Handling "Stay Signed In?" and Other Interstitial Prompts
  • Detecting and Recovering from Session Timeouts Mid-Flow
  • The Session Check Pattern
  • The Re-Authentication Subflow
  • Managing Session Persistence Across Flow Runs
  • Token Refresh Considerations
  • Building the Complete Login Flow: A Realistic Scenario
  • Flow Structure
  • The CheckAndRefreshSession Subflow in Detail
  • Handling the Dynamics 365 Specific Quirks
  • Hands-On Exercise
  • Common Mistakes & Troubleshooting
  • "My flow clicks the Sign In button but nothing happens"
  • "The flow works in attended mode but fails unattended"
  • "SSO redirect goes to an unexpected page"
  • "The cookie consent check takes too long"
  • "The browser profile is getting corrupted"
  • "Session expires exactly every X hours despite KMSI"
  • Summary & Next Steps
  • Automating Web Application Login and Session Persistence in Power Automate Desktop: Handling Cookie Consent, SSO Redirects, and Session Timeouts in Unattended Browser Flows

    Introduction

    You've built a solid unattended desktop flow. It launches a browser, navigates to your company's internal reporting portal, and starts extracting data — but at 2 AM, with no one watching, it hits the Microsoft login page, stalls on a cookie consent banner, and times out waiting for an SSO redirect that never completes. The flow fails. The report doesn't generate. Someone gets an angry email at 8 AM.

    This is the reality of web login automation in production RPA environments, and it's dramatically more complicated than what you encounter in tutorials. Real enterprise web applications don't just have a username and password field. They have multi-step authentication, identity provider redirects, conditional MFA prompts, cookie consent gates that appear only on first run or after a browser profile reset, and session tokens that expire mid-flow. Each of these is a potential failure point in an unattended flow, where there's no human to click "Accept Cookies" or type a one-time code.

    By the end of this lesson, you'll know how to architect browser login flows that survive all of these challenges. You'll handle cookie consent banners conditionally, navigate SSO redirects including SAML and OIDC flows through Azure AD, detect and recover from session timeouts mid-flow, and persist browser state across runs to avoid re-authenticating every time. We'll also cover how to structure your credentials handling in a way that doesn't get your account locked out or your bot flagged as suspicious.

    What you'll learn:

    • How to detect and dismiss cookie consent overlays without breaking your flow when they don't appear
    • How to navigate multi-step SSO login flows including Azure AD / Entra ID redirects
    • How to detect session timeouts mid-flow and re-authenticate without restarting from scratch
    • How to persist browser session state across flow runs to minimize authentication overhead
    • How to structure your login logic as a reusable subflow with proper error handling

    Prerequisites

    This lesson assumes you're comfortable with the fundamentals of Power Automate Desktop browser automation. You should understand how to open a browser, interact with web elements, and work with UI selectors. If you need a refresher on those foundations, the lesson on web automation in Power Automate Desktop: browser actions, form filling, and data extraction will bring you up to speed.

    You should also understand how UI elements and selectors work in Power Automate Desktop, since selector resilience is especially important in login flows where page structure can change between sessions. And you'll want to have read the lesson on handling credentials securely in desktop flows before putting any of this into production — we won't repeat that material here, but secure credential retrieval is assumed throughout.


    Understanding What Actually Happens During a Web Login

    Before writing a single action, you need to understand the authentication flow you're automating. This sounds obvious, but most failing login bots were built by someone who watched the happy path once and recorded it. They missed the branches.

    A modern enterprise web login typically has at least four distinct phases:

    Phase 1 — Pre-authentication overlays. Before you can even see the login form, the browser may present a cookie consent banner, a "you're using an unsupported browser" warning, or a GDPR notice. These appear conditionally — sometimes only on a fresh browser profile, sometimes on every session, sometimes only in certain regions or after a policy update.

    Phase 2 — The login form itself. This might be on the application's own domain, or it might immediately redirect to an identity provider. For Azure AD / Entra ID–backed applications, clicking "Sign In" often takes you away from the application domain entirely and lands you on login.microsoftonline.com. Your selector that targeted the username field on app.contoso.com won't find anything on login.microsoftonline.com.

    Phase 3 — Post-authentication redirects. After credentials are submitted, the identity provider redirects back to the application, potentially through several intermediate URLs. The page might go through two or three URL changes in quick succession before settling. If your flow tries to interact with the page during this redirect chain, it'll fail.

    Phase 4 — Session establishment. Once the page settles, the browser sets session cookies and the application loads. If this takes longer than expected — say, the application is slow on Tuesday mornings — a flow that hardcodes a 3-second wait will start clicking on a half-loaded page.

    Your login subflow needs to handle all four phases, in sequence, with appropriate checks at each step.

    Key insight

    The fundamental mistake in most failed login automations is treating login as a single action ("fill form, click button, done") rather than as a multi-phase state machine where each state transition needs to be detected and confirmed before moving on.


    Setting Up Your Browser Profile for Unattended Flows

    The browser instance you use in unattended flows needs careful setup. By default, Power Automate Desktop can launch a browser in a fresh, profile-less state — which means every run re-encounters cookie consent banners, loses any stored session state, and sometimes loads in a language the site picked based on request headers rather than user preference.

    For unattended runs, you want to launch the browser with a persistent profile directory. This lets the browser retain cookies, local storage, and cached authentication tokens between runs. Here's how to set this up:

    Launching Chrome with a Persistent Profile

    In Power Automate Desktop, the "Launch new Chrome" action has a "Launch with arguments" parameter. Use it like this in your flow:

    Launch new Chrome
      URL: 'https://portal.contoso.com'
      Launch mode: Normal window  
      Wait for page load: Page load completed
      Window state: Maximized
      Additional arguments: '--user-data-dir=C:\BotProfiles\ChromePortal --profile-directory=Default'
      Result: Browser
    

    The --user-data-dir path points to a folder on the unattended machine that persists between runs. The bot's service account needs read/write access to this folder. After the first successful authenticated run, Chrome will store session cookies here, and subsequent runs may not need to re-authenticate at all — the application will recognize the session as still valid.

    Warning

    Do not share a Chrome profile directory across multiple bot instances running concurrently. If two flows open the same profile simultaneously, Chrome will lock the profile and one instance will fail to launch correctly. For machine groups running parallel unattended flows, give each machine its own profile path, ideally parameterized using the machine hostname.

    For Edge, the equivalent argument syntax is identical — Edge is Chromium-based and accepts the same --user-data-dir flag.

    Clearing Stale Profile State

    Persistent profiles are great until they cause problems. Session tokens can become corrupted, cached JavaScript can interfere with page behavior, or the site might detect that a cookie is very old and force re-authentication anyway while also displaying an extra "Welcome back" banner your flow didn't expect.

    Build a PowerShell action into your maintenance or error recovery path that can clear specific cache files without deleting the entire profile:

    # Clear Chrome session storage but preserve cookies
    $profilePath = "C:\BotProfiles\ChromePortal\Default"
    $sessionFilePath = Join-Path $profilePath "Sessions"
    if (Test-Path $sessionFilePath) {
        Remove-Item $sessionFilePath -Force -ErrorAction SilentlyContinue
    }
    # Clear the Code Cache to avoid stale JS
    $codeCachePath = Join-Path $profilePath "Code Cache"
    if (Test-Path $codeCachePath) {
        Remove-Item $codeCachePath -Recurse -Force -ErrorAction SilentlyContinue
    }
    Write-Output "Cache cleared"
    

    You can run this as a PowerShell script action inside your desktop flow in the error recovery branch, then re-launch the browser cleanly.


    Handling Cookie Consent Banners

    Cookie consent banners are the cockroaches of web automation: you think you've dealt with them, and then they appear again three weeks later after a site update. The key principle is conditional handling — your flow should check whether the banner is present and dismiss it if so, but not fail if it's absent.

    Here's the pattern:

    # Step 1: Wait briefly for the page to stabilize after load
    Wait 2 seconds
    
    # Step 2: Check if cookie consent overlay is present
    # Use "If web page contains element" with a short timeout
    If web page contains element (CookieConsentAcceptButton) with timeout 5 seconds
      Then:
        Click web page element (CookieConsentAcceptButton)
        Wait for page to load
    End If
    

    The critical part is the selector for the consent button. Cookie consent banners from services like OneTrust, Cookiebot, TrustArc, and Cookielaw all use different HTML structures, and the same service can update its markup without warning.

    Build your selector to be resilient rather than brittle. Instead of capturing the exact button with its auto-generated class name like optanon-allow-all btn-sm_14a8c, target by the accessible role and text:

    In the selector builder, prefer:

    • Tag name: button
    • Text contains: Accept (or Accept All, Accept Cookies — check what your specific site uses)
    • Or by aria-label: Accept cookies

    If the banner uses an iframe (which OneTrust often does), you'll need to handle that differently. You can't directly target elements inside cross-origin iframes with standard web element actions. In that case, use a JavaScript injection approach:

    Run JavaScript function on web page
      Script: |
        // For OneTrust banners
        if (typeof OneTrust !== 'undefined') {
          OneTrust.AllowAll();
        }
      Result: JSResult
    

    Tip

    When you're building the cookie consent handling, test it both with a fresh browser profile (banner appears) and with an existing profile that already accepted cookies (banner doesn't appear). Both paths need to work without throwing errors. The "If web page contains element" action with a short timeout is your friend here — it effectively implements a "try to find, proceed regardless" pattern.


    Navigating SSO Redirects: Azure AD and Entra ID Flows

    This is where the majority of unattended web login automations fail in enterprise environments. Almost every internal business application authenticates through Azure AD (now Entra ID), and the redirect chain looks like this:

    1. Browser loads https://portal.contoso.com
    2. App detects no session, redirects to https://login.microsoftonline.com/[tenant-id]/oauth2/v2.0/authorize?...
    3. Microsoft's login page loads — username field appears
    4. User enters username, clicks Next
    5. If the account has a home tenant different from the resource tenant, there may be another redirect
    6. Password field appears (or MFA prompt, or Windows Hello prompt)
    7. After authentication, Microsoft redirects back to https://portal.contoso.com via a POST to the redirect URI
    8. Application loads

    Your flow needs to follow this chain correctly. Here's the structure that works:

    Step 1: Navigate to the Application and Detect Where You Land

    # Launch browser and navigate
    Launch new Chrome
      URL: 'https://portal.contoso.com'
      Additional arguments: '--user-data-dir=C:\BotProfiles\ChromePortal --profile-directory=Default'
      Result: Browser
    
    # Wait for initial page load
    Wait for page to load in Browser
      Timeout: 30
    
    # Check the current URL to determine state
    Get current URL from Browser
      Result: CurrentURL
    
    # If we're already at the app (session persisted), skip authentication
    If CurrentURL contains 'portal.contoso.com/dashboard'
      Set variable AuthRequired to False
    Else If CurrentURL contains 'login.microsoftonline.com'
      Set variable AuthRequired to True
    Else
      # Unexpected landing page - log and handle
      Set variable AuthRequired to True
    End If
    

    Note

    The URL check is more reliable than checking for the presence of a specific element, because the Microsoft login page can render in slightly different states depending on whether the account was previously used in this browser profile. If the email is remembered, the page skips the username field and goes straight to the password field. Checking the URL tells you where you are, not what specific form is showing.

    Step 2: Handle the Microsoft Login Form

    The Microsoft login flow is well-structured and uses consistent element IDs that have been stable for years. This makes it one of the more reliable SSO flows to automate:

    # If authentication is required
    If AuthRequired = True
    
      # Handle username entry (may be pre-filled from profile)
      If web page contains element (MicrosoftLoginEmailField)
        Wait for element (MicrosoftLoginEmailField) to appear
        Click web page element (MicrosoftLoginEmailField)
        Clear web page element text (MicrosoftLoginEmailField)
        Populate web page element text (MicrosoftLoginEmailField) with '%BotUsername%'
        Click web page element (MicrosoftLoginNextButton)
        Wait for page to load
      End If
    
      # Wait for password field - it appears after email submission
      Wait for element (MicrosoftLoginPasswordField) with timeout 20 seconds
      
      # Handle "Stay signed in?" prompt if it appears
      # (This appears before the password page sometimes for certain tenant configs)
      
      Populate web page element text (MicrosoftLoginPasswordField) with '%BotPassword%'
      Click web page element (MicrosoftLoginSignInButton)
    
      # Wait for the redirect chain to complete
      # Don't try to interact with the page during redirects
      Wait 3 seconds
      Wait for page to load in Browser
        Timeout: 45
    
      # Confirm we made it back to the application
      Get current URL from Browser
        Result: PostLoginURL
        
      If not PostLoginURL contains 'portal.contoso.com'
        # Still on login domain - something went wrong
        Throw error 'Login failed: Expected redirect to portal.contoso.com but landed on %PostLoginURL%'
      End If
    
    End If
    

    The Wait for page to load after clicking Sign In is crucial. During the SAML or OIDC redirect, the page will go through intermediate states that look like errors or blank pages momentarily. If you wait for the page load event to complete rather than waiting a fixed number of seconds, you'll catch the settled final state.

    Handling "Stay Signed In?" and Other Interstitial Prompts

    After successful authentication, Microsoft often presents a "Stay signed in?" dialog (kmsi — Keep Me Signed In). For unattended flows using a persistent profile, you usually do want to click "Yes" here, as it stores a persistent refresh token that can extend your session dramatically:

    # After login, check for KMSI prompt
    If web page contains element (KMSIYesButton) with timeout 5 seconds
      Click web page element (KMSIYesButton)
      Wait for page to load
    End If
    
    # Also check for "Don't show this again" / access package prompts
    If web page contains element (AccessPackageAcceptButton) with timeout 3 seconds
      Click web page element (AccessPackageAcceptButton)  
      Wait for page to load
    End If
    

    For the KMSI button, the reliable selector targets the button with id="idSIButton9" and value="Yes" — these have been consistent across Microsoft's login pages for years.

    Warning

    Some organizations configure Azure AD Conditional Access policies that actively detect automated sign-ins and block them, force MFA, or require a compliant device. If your bot's service account is hitting MFA prompts in production, the solution is not to try to automate the MFA — it's to work with your IT/identity team to configure a service account with appropriate Conditional Access exclusions, or to use certificate-based authentication. Never try to automate TOTP code generation and entry as a production pattern; it's fragile and will likely violate your organization's security policies.


    Detecting and Recovering from Session Timeouts Mid-Flow

    Session timeouts are insidious because they don't happen during login — they happen 20 minutes into your flow, right in the middle of a data extraction loop. The page silently becomes a login page (or shows a timeout modal), and your flow keeps trying to click on data elements that no longer exist.

    The pattern to handle this involves two things: a session check mechanism and a re-authentication subflow that can be called from anywhere in the main flow.

    The Session Check Pattern

    Before any critical interaction sequence, you can optionally check the session state. For most flows, it's more practical to build session detection into your error handling rather than checking proactively on every action:

    # In your error handler:
    On block error
      Get current URL from Browser
        Result: ErrorTimeURL
        
      If ErrorTimeURL contains 'login.microsoftonline.com'
        # Session expired, re-authenticate
        Run subflow: AuthenticateToPortal
        # Retry the failed action
        Retry
      Else If ErrorTimeURL contains 'portal.contoso.com/session-expired'
        # App-specific timeout page
        Click web page element (SessionExpiredContinueButton)
        Wait for page to load
        Run subflow: AuthenticateToPortal
        Retry
      Else
        # Different error - re-throw
        Rethrow error
      End If
    End On block error
    

    This integrates naturally with the error handling patterns in desktop flows you should already be using in production flows. The retry mechanism here is strategic: re-authenticate, then retry the action that failed — not restart the entire flow.

    The Re-Authentication Subflow

    Encapsulating login logic in a reusable subflow is essential for session timeout recovery. If login logic is scattered throughout your main flow, you can't call it cleanly when a timeout is detected mid-run.

    Your AuthenticateToPortal subflow should:

    1. Navigate to the portal URL (not necessarily starting from scratch — the browser may already be on the login page)
    2. Run through the full cookie consent check
    3. Handle the SSO redirect sequence
    4. Confirm successful landing back on the application
    5. Return a success/failure status as an output variable
    Subflow: AuthenticateToPortal
      Input parameters: (none — credentials read from Azure Key Vault within subflow)
      Output parameters: AuthSuccess (Boolean)
    
      # Navigate to login URL
      Navigate web browser Browser to URL 'https://portal.contoso.com'
      Wait for page to load
      
      # Cookie consent (conditional)
      If web page contains element (CookieConsentBanner) with timeout 4 seconds
        Click web page element (CookieConsentAcceptButton)
        Wait 1 second
      End If
      
      # Check if already logged in
      Get current URL from Browser
        Result: CheckURL
      
      If CheckURL contains 'portal.contoso.com/dashboard'
        Set variable AuthSuccess to True
        Exit subflow
      End If
      
      # Retrieve credentials from Key Vault
      Run subflow: GetCredentialsFromKeyVault
        Result: BotUsername, BotPassword
      
      # Perform login sequence
      [... login steps as described in previous section ...]
      
      # Verify outcome
      Get current URL from Browser
        Result: FinalURL
      
      If FinalURL contains 'portal.contoso.com'
        Set variable AuthSuccess to True
      Else
        Set variable AuthSuccess to False
      End If
    

    Managing Session Persistence Across Flow Runs

    Re-authenticating on every flow run is wasteful and also more likely to trigger security alerts — repeated logins from a service account look like a brute-force attempt to some security monitoring tools. The goal is to authenticate once and then rely on the persisted session for subsequent runs.

    This requires the persistent profile approach described earlier, combined with intelligent session checking at the start of each run:

    # Main flow — start of execution
    Launch new Chrome (with persistent profile arguments)
    
    # Navigate to application
    Navigate to 'https://portal.contoso.com'
    Wait for page to load
      Timeout: 30
    
    # Check if session is still valid
    Get current URL from Browser
      Result: LandingURL
    
    If LandingURL contains 'portal.contoso.com/dashboard'
      # Session persisted - log this and proceed
      Write to log 'Session persisted from previous run, skipping authentication'
    Else
      # Need to authenticate
      Run subflow: AuthenticateToPortal
      
      If AuthSuccess = False
        # Critical failure - cannot proceed
        Send email notification 'Bot authentication failed at %DateTime%'
        Exit flow with error
      End If
    End If
    
    # Proceed with main flow work...
    

    Tip

    Log whether each run authenticated fresh or used a persisted session. After running for a week, look at the data. If the session is persisting 70% of the time, your profile strategy is working. If it's persisting 10% of the time, something is forcing session invalidation — perhaps the application has a short absolute session timeout, or a nightly infrastructure restart is clearing state. Knowing the pattern helps you tune your approach.

    Token Refresh Considerations

    For applications using OAuth2/OIDC with Azure AD, the browser stores both a session cookie and a refresh token (when KMSI is accepted). The refresh token can be valid for 90 days by default in Azure AD, but your IT team may have configured shorter lifetimes. If you're seeing authentication failures every 24 hours exactly, that's likely a session cookie expiry. Every 7 days? Probably a refresh token policy. Work with your identity team to understand what's configured.

    For attended vs unattended run mode decisions, session persistence is a significant factor: attended flows can tolerate re-authentication because a human can intervene, while unattended flows absolutely must handle the full auth flow without human input or use service accounts configured for non-interactive authentication.


    Building the Complete Login Flow: A Realistic Scenario

    Let's put this all together with a production-realistic scenario. You're automating a nightly data extract from a Dynamics 365 portal that's backed by Azure AD. The flow runs at 1 AM unattended. Let's build it properly.

    Flow Structure

    Main Flow: NightlyDynamicsExtract
    
    [Subflow: GetCredentialsFromKeyVault]
      → Retrieves bot service account username and password from Azure Key Vault
      → Returns: BotUsername (sensitive), BotPassword (sensitive)
    
    [Subflow: AuthenticateToPortal]  
      → Handles full login including cookie consent and SSO
      → Uses GetCredentialsFromKeyVault internally
      → Returns: AuthSuccess (boolean)
    
    [Subflow: CheckAndRefreshSession]
      → Verifies current URL indicates active session
      → Calls AuthenticateToPortal if session expired
      → Returns: SessionValid (boolean)
    
    [Main Flow]
      1. Launch Chrome with persistent profile
      2. Navigate to Dynamics portal
      3. Run AuthenticateToPortal (handles fresh auth or confirms persisted session)
      4. Begin data extraction loop
      5. At each major step boundary: run CheckAndRefreshSession
      6. On error: check if URL-based session timeout, recover and retry
      7. Close browser and clean up
    

    The CheckAndRefreshSession Subflow in Detail

    Subflow: CheckAndRefreshSession
      Output: SessionValid (Boolean)
      
      Get current URL from Browser
        Result: CurrentURL
        
      If CurrentURL contains 'login.microsoftonline.com'
        OR CurrentURL contains '/session-expired'
        OR CurrentURL contains '/signin'
        
        # Session has expired, re-authenticate
        Run subflow: AuthenticateToPortal
        Set SessionValid to AuthSuccess
        
      Else If CurrentURL contains 'dynamics.com'
        OR CurrentURL contains 'portal.contoso.com'
        
        # Looks good, but do a quick element check
        # (some apps redirect to app domain but show a timeout modal)
        If web page contains element (SessionTimeoutModal) with timeout 2 seconds
          Click web page element (SessionTimeoutDismissButton)
          Wait 1 second
          Run subflow: AuthenticateToPortal
          Set SessionValid to AuthSuccess
        Else
          Set SessionValid to True
        End If
        
      Else
        # Unexpected URL state
        Set SessionValid to False
        Write to event log 'Unexpected URL during session check: %CurrentURL%'
        
      End If
    

    Handling the Dynamics 365 Specific Quirks

    Dynamics 365 has a few authentication behaviors worth knowing:

    The app uses a returnUrl parameter after login, so your post-login URL might look like https://[tenant].crm.dynamics.com/main.aspx?app=... rather than a simple path check. Build your URL validation accordingly:

    If PostLoginURL contains '.dynamics.com' OR PostLoginURL contains '.crm.dynamics.com'
      Set AuthSuccess to True
    End If
    

    Dynamics also sometimes shows a "You have been signed out" modal on the main page rather than redirecting. This modal has an ID of sessionExpiredDialog in the DOM, which makes it reliably detectable:

    If web page contains element (DynamicsSessionExpiredDialog) with timeout 2 seconds
      Run subflow: AuthenticateToPortal
    End If
    

    Hands-On Exercise

    Build a complete, production-ready login flow for a web application of your choice that uses Azure AD / Entra ID authentication. The Microsoft 365 portal (portal.office.com) is a good candidate if you have an M365 tenant available.

    Exercise steps:

    1. Create a new desktop flow called M365PortalLogin_Prod

    2. Create a subflow called GetTestCredentials that reads a username and password from either a PAD-level sensitive variable or, ideally, from an Azure Key Vault secret. If you haven't set up Key Vault integration, review the credentials security lesson first.

    3. Create a subflow called AuthenticateToM365 that:

      • Launches Chrome with a persistent profile at C:\BotProfiles\M365Test
      • Navigates to https://portal.office.com
      • Handles any cookie consent banner conditionally
      • Detects whether it lands on the Microsoft login page or the portal home page
      • If on the login page: enters credentials, handles KMSI prompt, verifies landing on portal.office.com or www.office.com
      • Returns AuthSuccess as a boolean output variable
    4. In your main flow:

      • Call AuthenticateToM365
      • If AuthSuccess is False, log the failure and stop
      • If True, navigate to the M365 admin center (https://admin.microsoft.com)
      • Check if you're prompted to log in again or if the session transfers automatically
      • Run the flow twice — the second time should use the persisted session and skip the full login
    5. Add an error handler that checks the current URL when any browser action fails and calls AuthenticateToM365 if the URL indicates a session timeout

    What to observe:

    • How long does the full authentication path take vs. the persisted session path?
    • Does the cookie consent banner appear on the second run?
    • What URL does the browser land on immediately after clicking Sign In, before the redirect completes?

    Common Mistakes & Troubleshooting

    "My flow clicks the Sign In button but nothing happens"

    This usually means the button click is happening before the form is in a ready state, or you're clicking the wrong element. The Microsoft login page loads the button as enabled but not yet wired to the submit handler for a brief moment. Add a Wait for element (SignInButton) to be enabled check before clicking, or introduce a 1-second wait after the password field is populated.

    "The flow works in attended mode but fails unattended"

    This is the most common complaint and usually has one of three causes. First, check whether the unattended machine has the browser extension installed — Power Automate Desktop's browser extension needs to be installed and enabled in the browser profile being used. Second, verify the unattended service account actually has access to the application — service accounts are often in different Azure AD groups than user accounts. Third, check if the application uses Windows Integrated Authentication (Kerberos/NTLM) which may work automatically for domain users but not for service accounts running as a different identity. This is a common pattern in unattended RPA scenarios that require careful machine configuration.

    "SSO redirect goes to an unexpected page"

    Capture the actual URL you're landing on by using Get current URL right after Wait for page to load completes after the redirect. Log it to a file. This tells you exactly where in the redirect chain you're getting stuck. Common culprits include: a "Terms of Use" acceptance page the service account has never accepted, an MFA enrollment prompt, or a Conditional Access block page.

    "The cookie consent check takes too long"

    If you're using a 10-second timeout on your "If web page contains element" check for a consent banner that rarely appears, you're adding 10 seconds of dead time to every flow run. Reduce the timeout to 3-4 seconds for elements you expect to rarely appear. The check only blocks if the element isn't found, so short timeouts are fine for optional UI.

    "The browser profile is getting corrupted"

    Signs of profile corruption include the browser launching to a "Profile error" page or the Chrome Data Directory showing lock files even when no Chrome instance is running. Build a PowerShell recovery action that deletes the SingletonLock and SingletonCookie files from the profile directory — these are Chrome's instance locks and can be left behind after a crash:

    $profilePath = "C:\BotProfiles\ChromePortal\Default"
    $lockFiles = @("SingletonLock", "SingletonCookie", "SingletonSocket")
    foreach ($lockFile in $lockFiles) {
        $lockPath = Join-Path (Split-Path $profilePath) $lockFile
        if (Test-Path $lockPath) {
            Remove-Item $lockPath -Force
            Write-Output "Removed lock file: $lockFile"
        }
    }
    

    "Session expires exactly every X hours despite KMSI"

    Your tenant has a configured session lifetime policy that overrides the KMSI behavior. This is an Azure AD / Entra ID configuration setting, not something you can work around from the bot side. Raise this with your identity team and ask them to extend the session lifetime for the service account, or configure a Conditional Access sign-in frequency policy that allows longer sessions for the bot's machine or service account.

    Warning

    Don't try to solve short session timeouts by having the bot periodically click through the application to "keep the session alive." This can interfere with the actual work the bot is doing, and many enterprise applications specifically detect and disconnect idle-but-clicking sessions. Work with the application owner or identity team to address the root cause.


    Summary & Next Steps

    Web application login automation in unattended flows is not a single action — it's a state machine with at least four phases, each of which can fail independently. By treating login as a proper subflow with conditional handling at each phase (cookie consent, SSO redirect, KMSI prompts, and post-login verification), you build a foundation that actually works in production at 2 AM without anyone watching.

    The key practices we covered:

    • Use persistent Chrome profiles via --user-data-dir to preserve session cookies and avoid re-authenticating on every run
    • Check the current URL, not just element presence, to determine where in the login flow you are
    • Handle every interstitial conditionally — cookie banners, KMSI prompts, and access package prompts all appear sometimes but not always
    • Build session timeout detection into your error handlers, not just at the start of the flow — timeouts happen mid-flow in long-running automations
    • Encapsulate all login logic in a subflow so it can be called from error handlers and recovery paths, not just at flow start
    • Never try to automate MFA — the solution is proper service account configuration, not code

    Where to go next:

    Since you now have robust login handling, the logical progression is building the actual work your flow does once it's inside the application. For data extraction scenarios, the lesson on multi-step web scraping and pagination handling covers exactly that. If your flow is part of a larger unattended architecture, you'll want to understand how to monitor these flows in production — the lesson on monitoring and troubleshooting desktop flow runs at scale will show you how to detect login failures in aggregated run data before they become a week-long incident. And if you're deploying this across multiple machines, the enterprise-scale orchestration patterns in building a resilient unattended RPA orchestration framework show you how to coordinate session management across a fleet.

    Work With Us

    From insight to implementation

    Reading is the start. When you're ready to build the data, automation, or AI systems behind it, our team turns strategy into shipped results.

    Let's Build

    Power Automate Desktop & RPA

    Previous

    Controlling Flow with Loops and Conditionals in Power Automate Desktop: For Each, Loop Until, and If Actions for Practical Desktop Automation

    Related Insights

    Power AutomatePractitioner

    Automating Recurring Calendar-Based Reminders with Power Automate: Building Scheduled Flows That Check SharePoint Dates, Calculate Deadlines, and Send Personalized Outlook Notifications

    22 min
    Power AutomateFoundation

    Implementing Power Automate Flow Trigger Filtering and Trigger Conditions to Reduce Unnecessary Run Consumption in High-Volume Production Environments

    19 min
    Power AutomateFoundation

    Controlling Flow with Loops and Conditionals in Power Automate Desktop: For Each, Loop Until, and If Actions for Practical Desktop Automation

    18 min

    On this page

    • Introduction
    • Prerequisites
    • Understanding What Actually Happens During a Web Login
    • Setting Up Your Browser Profile for Unattended Flows
    • Launching Chrome with a Persistent Profile
    • Clearing Stale Profile State
    • Handling Cookie Consent Banners
    • Navigating SSO Redirects: Azure AD and Entra ID Flows
    • Step 1: Navigate to the Application and Detect Where You Land
    • Step 2: Handle the Microsoft Login Form
    • Handling "Stay Signed In?" and Other Interstitial Prompts
    • Detecting and Recovering from Session Timeouts Mid-Flow
    • The Session Check Pattern
    • The Re-Authentication Subflow
    • Managing Session Persistence Across Flow Runs
    • Token Refresh Considerations
    • Building the Complete Login Flow: A Realistic Scenario
    • Flow Structure
    • The CheckAndRefreshSession Subflow in Detail
    • Handling the Dynamics 365 Specific Quirks
    • Hands-On Exercise
    • Common Mistakes & Troubleshooting
    • "My flow clicks the Sign In button but nothing happens"
    • "The flow works in attended mode but fails unattended"
    • "SSO redirect goes to an unexpected page"
    • "The cookie consent check takes too long"
    • "The browser profile is getting corrupted"
    • "Session expires exactly every X hours despite KMSI"
    • Summary & Next Steps