BotBuilder-Python SSO not working
Version
4.14.7
Describe the bug
When using the OAuthPrompt Dialog from the SDK, the call to https://api.botframework.com/api/usertoken/GetToken performed by the SDK returns a 400 status error response. According to the code, the SDK awaits either a 200 or 404 status.
Reference:
https://github.com/microsoft/botbuilder-js/issues/4418 https://github.com/microsoft/botframework-sdk/issues/5464 https://github.com/microsoft/botbuilder-dotnet/issues/4927
To Reproduce
Steps to reproduce the behavior:
- Run the sample code project 24.bot-authentication-msgraph
- Sending a message triggers the SSO process
- Click the login button
Expected behavior
Evoke the SSO certification process
question
It's always 404. It looks like the 404 is due to an incorrect parameter. Is something missing?
DEBUG:urllib3.connectionpool:https://api.botframework.com:443 "GET /api/usertoken/GetToken?userId=<user id value>&connectionName=<name>&channelId=msteams&api-version=token HTTP/1.1" 404 2096
I couldn't solve the problem in the end, and I wasn't as lucky as other users to have it fixed automatically, I spent a long time modifying the configuration and trying over and over again, but no luck!
I tried a different way to authenticate
async def command_login(self, turn_context: TurnContext):
link = await turn_context.adapter.get_oauth_sign_in_link(
turn_context,
self.bot.oauth_name,
)
card_data = get_login_card(link)
card = CardFactory.adaptive_card(card_data)
message = Activity(
text="",
type=ActivityTypes.message,
attachments=[card],
)
await turn_context.send_activity(message)
But when I click on the authentication button(openUrl), it opens the browser into the SSO authentication process, which ultimately returns an authentication CODE, which I need to copy and then validate it
async def action_validation_code_submit(self, turn_context: TurnContext):
"""ValidationCodeSubmit """
submit_data = turn_context.activity.value
if submit_data is None:
return
vcode = submit_data.get("ValidationCode")
if not vcode:
await turn_context.send_activity("Please enter a verification code")
return
token = await turn_context.adapter.get_user_token(turn_context, self.bot.oauth_name, vcode)
if not token:
await turn_context.send_activity("The verification code is invalid")
return
console log
DEBUG:urllib3.connectionpool:https://api.botframework.com:443 "GET /api/usertoken/GetToken?userId=<user id value>&connectionName=<name>&channelId=msteams&code=125204&api-version=token HTTP/1.1" 200 2096
Looks like more code=125204, I'd like to know how this code parameter is configured, and I'd prefer to provide a server-side callback url for the code notification. But I see that the final_redirect parameter in the SDK code is not valid.
async def get_oauth_sign_in_link(
self,
context: TurnContext,
connection_name: str,
final_redirect: str = None, # pylint: disable=unused-argument
oauth_app_credentials: AppCredentials = None,
) -> str:
"""
Gets the raw sign-in link to be sent to the user for sign-in for a connection name.
:param context: Context for the current turn of conversation with the user
:type context: :class:`botbuilder.core.TurnContext`
:param connection_name: Name of the auth connection to use
:type connection_name: str
:param final_redirect: The final URL that the OAuth flow will redirect to.
:param oauth_app_credentials: (Optional) AppCredentials for OAuth.
:type oauth_app_credentials: :class:`botframework.connector.auth.AppCredential`
:return: If the task completes successfully, the result contains the raw sign-in link
"""
client = await self._create_token_api_client(context, oauth_app_credentials)
conversation = TurnContext.get_conversation_reference(context.activity)
state = TokenExchangeState(
connection_name=connection_name,
conversation=conversation,
ms_app_id=client.config.credentials.microsoft_app_id,
relates_to=context.activity.relates_to,
)
final_state = base64.b64encode(
json.dumps(state.serialize()).encode(encoding="UTF-8", errors="strict")
).decode()
return client.bot_sign_in.get_sign_in_url(final_state)
Screenshots
Configuration Validation
This is my configuration, and the test pattern is fine.
@jamiesun - Thank you for your patience. It looks like you are using Teams as the client, yes? If you remove the SSO aspect and just focus on getting a user logged in, does it work then? I ran into some issues of my own not related to logging/OAuth that hampered me, but I have my test environment set up now. And, using the 24.bot-authentication-msgraph sample from the Botbuilder-Samples repo, I can log in using OAuth successfully whether communicating in a 1:1 or in a Teams channel with the bot .
It also looks like the scopes might be incomplete. These scopes (openid profile Mail.Read Mail.Send User.Read User.ReadBasic.All) are what are typically specified when setting up OAuth. You may want to try changing the scopes listed in the OAuth app registration and in your bot's OAuth connection settings and see if that possibly makes a difference.
@stevkan Thanks for your reply, I've bypassed SSO for now, and I'm able to authenticate the user to get the information. I think I need to create a new development environment and bot to verify the issue again to find out what's causing the problem.
Possible duplicate of https://github.com/microsoft/BotBuilder-Samples/issues/3829
Closing as resolved.
I do think we have a Python SSO issue. Leaving open until we can further review the reported issues.
Regarding this issue, after some troubleshooting, significant improvements have been made. I found that the Token Exchange URL was not configured, but after setting it up, the Teams SSO authentication flow finally worked correctly, with the authentication dialog completing as expected. However, the SSO process only succeeds when the application is deployed in the same tenant as the bot. If the application is deployed in a different tenant, the SSO process fails.
What could be missing here?