Scenario:
We are creating applications in OutSystems Developer Cloud (ODC). We use Entra ID Authentication for all our apps. We maintain a centralized authentication application(Authenticator ). Consumer application use the login and logout actions created inside this app. (Login_Testing) is the name of the consumer app used for this scenario.
When user logout out of a consumer application(Login_Testing ) we send the bookmarkable URL of the application to the logout action inside Authenticator app.
https://<environment> /Login_Testing in this scenario
Issue Description:
Logout works successfully. However, when a user attempts the first login of the day or logs in immediately after logout, the user is redirected to:
https://<environment>/Authenticator/_error.html
Error Observed:
Screen not found: /Login_Testing/ - Later, after implementing logging and exception handling, we identified the actual platform error: OS-CLRT-40102 2 Error performing authentication action because a user is already authenticated via a different mechanism. To proceed, a logout is necessary.
Logging & Diagnostics
Authentication Flow Changes
Current Result:
Despite all the above changes, Authentication still hits OS-CLRT-40102. User is eventually redirected to https://<environment> /Authenticator/_error.html. instead of successfully re-authenticating.
Questions:
Any guidance or best practices would be greatly appreciated.
Thanks,
Gowtham Shanmugam
You’re hitting a conflict between ODC’s internal authentication state and the external Entra ID flow, and the centralized “Authenticator” app is making that more visible.
Below is how I’d look at it and what you can do, based on how ODC authentication and external IdPs are expected to work.
OS-CLRT-40102
The error:
OS-CLRT-40102 – Error performing authentication action because a user is already authenticated via a different mechanism. To proceed, a logout is necessary.
means:
In a classic (per‑app) scenario, this usually happens if you mix default ODC login with external login, or if you try to re‑authenticate while a valid session is still active. In your case, the centralized Authenticator app and shared flows make this easier to trigger.
In ODC, each app still has:
When you centralize login/logout in an Authenticator app, you must ensure that:
If a browser keeps an authenticated session to Login_Testing while you start a fresh external login from Authenticator, you can easily get OS-CLRT-40102.
Login_Testing
Authenticator
Even if you use a broker app, the basic pattern should be:
From consumer app (Login_Testing):
GetExternalLogoutURL()
If you must coordinate multiple apps, see the classical unified login/logout approach for inspiration: a “hub” page that becomes the redirect destination and then sends the user to the right app based on roles and availability, instead of relying on Client.LastURL/ReturnToURL only. Use the same login for multiple apps
Client.LastURL
From Authenticator (broker):
GetExternalLoginURL()
https://<environment>/Login_Testing/...
ReturnToURL
The critical part is: don’t start step 2 while an existing internal session is still active – otherwise OS-CLRT-40102 is expected.
_error.html
Your “Login → Logout → Login retry” flow is exactly what the platform is asking for, but the error indicates that the logout is not fully clearing the conflicting context. Common causes:
In short: the entire browser context must be transitioned to “logged out” for all participating ODC apps before a fresh external login is initiated.
GetExternalLoginURL
Within an ODC app, the supported way to fully clear authentication is:
There isn’t an extra “manual purge all sessions” API beyond that; if you manually try to mix custom logout logic with platform-managed sessions, you often end up in the state that triggers OS‑CLRT‑40102.
So, the safest pattern is:
If you’re attempting to call GetExternalLoginURL from inside an error handling flow that still belongs to an authenticated request, ODC can still see the current user as logged in and throw OS‑CLRT‑40102.
From the classic platform world (non‑ODC), similar behavior has been seen:
Typical mitigations there (many of which also apply conceptually in ODC):
Your centralized Authenticator is already similar to this; you may want to:
Given that you already have application logging and exception handling:
On environments where you have access to platform logs, look specifically at:
If, after aligning your flow with the patterns above, you still consistently hit OS‑CLRT‑40102, then it’s likely a platform-level behavior or edge case, and raising it to OutSystems Support with your exact redirect sequence is warranted.
For your centralized Authenticator + Entra ID in ODC:
Per-app logout
Safe landing instead of direct ReturnToURL
No login while authenticated
Handle _error.html as recovery, not dead-end
Minimize chained redirects with session-based ReturnToURL
If you want, you can describe your current exact sequence (who calls GetExternalLogoutURL / GetExternalLoginURL, and what each ReturnToURL is), and I can help you re‑shape it into a minimal, conflict‑free flow that matches the checklist above.
You’re running into a mismatch between ODC’s own authentication session and the Entra ID flow, and the fact you’re centralizing everything in an Authenticator app makes OS‑CLRT‑40102 much easier to hit.
Below I’ll focus on the practical side: how to structure the flow in ODC, and what you can still try given the restrictions of the platform.
The message:
Error performing authentication action because a user is already authenticated via a different mechanism. To proceed, a logout is necessary.
In ODC this typically means:
In a centralized SSO setup, this usually happens when:
Even in ODC:
GetExternalLogoutURL
When you build a broker app (Authenticator) you are effectively:
This increases the chance that:
So the key is: make sure that no app involved in the flow is still authenticated when you call GetExternalLoginURL for a fresh login.
Let’s rewrite your sequence in a way that minimizes conflicts.
When user clicks “Logout” in Login_Testing:
Key point: The logout should be initiated by the app whose session you want to clear, not only by the Authenticator app.
On the Authenticator login screen:
ReturnToURL = "https://<environment>/Login_Testing/..."
The critical rule: Never call GetExternalLoginURL from an authenticated request (in any app that participates in the flow).
Your custom “Login → Logout → Login retry” logic is conceptually correct, but OS‑CLRT‑40102 means logout is not happening from the perspective of the platform:
Typical pitfalls:
Logout only in Authenticator Login_Testing’s session persists, so when you re‑enter Login_Testing via ReturnToURL, ODC sees a valid session and treats the attempt to start a new external login as conflicting.
ReturnToURL re‑introduces an authenticated app If you preserve and reuse a ReturnToURL that points to a screen in Login_Testing while Login_Testing is still authenticated, the “next login” attempt is not really clean.
Multiple tabs/windows Another tab with Login_Testing or another ODC app can keep a session, and any cross‑app redirect chain can then hit OS‑CLRT‑40102 when you restart login from Authenticator.
Starting login inside error handling If your OS‑CLRT‑40102 handling is executed in the same request that is still treated as authenticated, calling GetExternalLoginURL there will again see a conflicting session.
In ODC, you don’t have a “force purge all sessions” API.
You have:
To fully clear conflicts in a centralized SSO scenario, you need to:
Right now _error.html is a dead end. You can turn it into a recovery step:
On _error.html, instead of only showing the error:
/Authenticator/AuthHub
On AuthHub:
AuthHub
GetExternalLoginURL(ReturnToURL = OriginalTargetAppURL)
This way, any error or inconsistent state is funneled into a deterministic hub screen that always forces a logout first, then a fresh login.
Conceptually this is similar to the “unified login” app approach that OutSystems recommends for multiple apps with shared authentication. Use the same login for multiple apps
You already added logging and exception handling, which is great. Given OS‑CLRT‑40102 is about existing sessions, I’d add:
Before any call to GetExternalLoginURL or GetExternalLogoutURL:
On _error.html:
/Authenticator/_error.html
Compare logs between Authenticator and Login_Testing:
If after you align the flow as above you still consistently see OS‑CLRT‑40102, that strongly suggests a platform-level edge case, and at that point it’s worth opening a Support case with the exact redirect sequence and your logs.
Has anyone encountered OS‑CLRT‑40102 in an ODC + Entra ID setup with a centralized SSO application?
Yes, it’s a typical symptom in setups where:
Is there an officially recommended way to completely clear conflicting ODC authentication sessions before invoking GetExternalLoginURL?
Within one app: use only the platform logout (GetExternalLogoutURL + redirect), then start login from an unauthenticated request. Across several apps: you need to ensure each participating app uses platform logout before starting a fresh centralized login flow. There’s no global “kill all sessions” API.
Are there known issues with GetExternalLogoutURL not fully clearing session state in certain scenarios?
The typical issues are not that GetExternalLogoutURL fails, but that:
What is the recommended login/logout sequence for ODC apps using a shared authentication broker application?
In short:
Any additional logging/monitoring or configuration to see why the user lands on _error.html after the recovery flow?
If you’re able to outline your exact redirect chain (who calls which action, with which ReturnToURL, in order), I can help you reshape it into a minimal sequence that avoids the conflicting state and OS‑CLRT‑40102.
You’ve essentially debugged the root cause already: in your Authenticator app, the fallback path in the login exception handler is using the app ReturnToURL (Login_Testing) instead of an IdP URL, and because that URL is not a screen of Authenticator, ODC sends you to Authenticator/_error.html.
Authenticator/_error.html
Let me break it down and then suggest a concrete fix for your flow.
Your sequence:
https://<env>/Login_Testing/...
https://<env>/Authenticator/Login?ReturnToURL=<encoded Login_Testing URL>
GetDefaultExternalLoginURL
/Login_Testing/
This fallback behavior is very similar to what happens in classic OnException flows when people redirect to the wrong place and land in a loop or in another app’s login instead of their own. Remove login screen
You need to separate clearly:
…and never use ReturnToURL as a fallback when IdP login fails.
On the Authenticator login screen’s OnReady:
Current (problematic) pattern (simplified):
Try IdpUrl = GetDefaultExternalLoginURL() RedirectToURL(IdpUrl) Catch // Fallback RedirectToURL(ReturnToURL) End
Recommended pattern:
Try IdpUrl = GetDefaultExternalLoginURL() RedirectToURL(IdpUrl) Catch SecurityException or AuthenticationException // 1. Log details // 2. Redirect to a dedicated error / recovery screen in Authenticator RedirectToURL(GetEntryURL(AuthErrorScreen)) Catch AllOtherExceptions // Same: log + error screen, NOT ReturnToURL RedirectToURL(GetEntryURL(AuthErrorScreen)) End
On AuthErrorScreen (in Authenticator):
This is conceptually the same advice given for SSO exceptions in the classic platform: you send the user to a dedicated error screen, not back to the original page, to avoid loops and confusion. Remove login screen
You still need ReturnToURL (= Login_Testing URL) to know where to send the user after IdP login succeeds, but it should not be used when IdP login fails.
Pattern:
Do not use ReturnToURL in:
Using a dedicated client variable to store the post-login URL is similar to how OutSystems templates handle post-login navigation in reactive apps (store target URL in client state and use it after login). Redirect to correct link from Email after login
In your broader scenario, OS‑CLRT‑40102:
“Error performing authentication action because a user is already authenticated via a different mechanism. To proceed, a logout is necessary.”
is about conflicting session state when starting a new external login. Fixing your exception handling won’t by itself clear sessions, but it will:
Combined with a careful login/logout sequence (per app, as discussed before), this should significantly reduce the inconsistent states that cause both OS‑CLRT‑40102 and _error.html redirects.
OnReady of Login screen:
AuthErrorScreen (Authenticator):
ReturnToURL handling:
GetExternalLoginURL(ReturnToURL = Login_Testing URL)
If you adjust the exception handling like this, the platform won’t try to resolve /Login_Testing/ as a screen in Authenticator, and your users should stop landing in Authenticator/_error.html for this specific case.
In addition to the comments above, I’m sharing the document to. https://success.outsystems.com/documentation/outsystems_developer_cloud/user_management/configuring_authentication_with_external_identity_providers/modify_the_built_in_login_screen_for_external_provider_login/