-
Notifications
You must be signed in to change notification settings - Fork 15
Description
Question
When registering a custom signin/failure handler via @app.on_signin_failure(), both the custom handler and the built-in default handler execute. In TypeScript and C#, registering a custom handler for the same route replaces the default one.
Is this intentional behavior for the Python SDK? I noticed the Python SDK uses additive middleware-style routing where all matching handlers chain together, so this may be by design. But it means there's no way to suppress the default behavior for these types of invokes.
Note that this only applies to type: system invokes (e.g. signin/verifyState, signin/tokenExchange, signin/failure) where the SDK registers built-in default handlers, so the practical impact is narrow.
Behavior comparison
In TypeScript, when a new route is added with the same name, the router removes the existing route before adding the new one — so a custom signin.failure handler replaces the default.
In Python, on_signin_failure adds the handler without removing the existing default, so both execute.
Reproduction
@app.on_signin_failure()
async def handle_signin_failure(ctx):
failure = ctx.activity.value
print(f"Custom handler: {failure.code} - {failure.message}")
await ctx.send("Sign-in failed. Please contact your admin.")When signin/failure is received, both the built-in default handler (which logs a warning) and the custom handler above fire.
Context
- Confirmed via live testing in Teams with a
resourcematchfailedfailure - Currently documenting this as a Python-specific note in the user authentication guide