Closed donatas-xyz closed 6 months ago
Hi @BlueWhaleSEO, some questions to clarify further:
Could you also attach snippets of where/when you are making these requests, and how you set up your connection to the AI model?
401's generally mean the setup to connect to the API, or the call to the API, is formatted incorrectly (e.g., invalid or missing fields/credentials). I'm guessing this is likely the case for you
In the meantime, I would also suggest looking into our ChefBot sample to see how we connect to AzureOpenAI/OpenAI
Hi @lilyydu. Thank you for coming back to me.
This is just the simplest skeleton bot created with the Teams Toolkit. I have much more complex bot, which is suffering from the same issue - works fine until SSO is added.
import { MemoryStorage } from "botbuilder";
import * as path from "path";
import { Application, ActionPlanner, OpenAIModel, PromptManager } from "@microsoft/teams-ai";
import config from "./config";
// Create AI components
const model = new OpenAIModel({
// Use Azure OpenAI
azureApiKey: config.azureOpenAIKey!,
azureDefaultDeployment: "gpt3_5-xxx-custom-model",
azureEndpoint: config.azureOpenAIEndpoint!,
useSystemMessages: true,
logRequests: true,
});
const prompts = new PromptManager({
promptsFolder: path.join(__dirname, "../src/prompts"),
});
const planner = new ActionPlanner({
model,
prompts,
defaultPrompt: "chat",
});
// Define storage and application
const storage = new MemoryStorage();
const app = new Application({
storage,
ai: {
planner,
},
authentication: {settings: {
graph: {
scopes: ['User.Read'],
msalConfig: {
auth: {
clientId: process.env.AAD_APP_CLIENT_ID!,
clientSecret: process.env.AAD_APP_CLIENT_SECRET!,
authority: `${process.env.AAD_APP_OAUTH_AUTHORITY_HOST}/${process.env.AAD_APP_TENANT_ID}`
}
},
signInLink: `https://${process.env.BOT_DOMAIN}/auth-start.html`,
endOnInvalidMessage: true
},
}}
});
export default app;
// Import required packages
import * as path from 'path';
import * as restify from "restify";
// Import required bot services.
// See https://aka.ms/bot-services to learn more about the different parts of a bot.
import {
CloudAdapter,
ConfigurationBotFrameworkAuthentication,
ConfigurationServiceClientCredentialFactory,
} from "botbuilder";
// This bot's main dialog.
import app from "./app";
import config from "./config";
const botFrameworkAuthentication = new ConfigurationBotFrameworkAuthentication(
{},
new ConfigurationServiceClientCredentialFactory({
MicrosoftAppId: config.botId,
MicrosoftAppPassword: process.env.BOT_PASSWORD,
MicrosoftAppType: "MultiTenant",
})
);
// Create adapter.
// See https://aka.ms/about-bot-adapter to learn more about how bots work.
const adapter = new CloudAdapter(botFrameworkAuthentication);
// Catch-all for errors.
const onTurnErrorHandler = async (context, error) => {
// This check writes out errors to console log .vs. app insights.
// NOTE: In production environment, you should consider logging this to Azure
// application insights.
console.error(`\n [onTurnError] unhandled error: ${error}`);
// Send a trace activity, which will be displayed in Bot Framework Emulator
await context.sendTraceActivity(
"OnTurnError Trace",
`${error}`,
"https://www.botframework.com/schemas/error",
"TurnError"
);
// Send a message to the user
await context.sendActivity(`The bot encountered an error or bug: ${error}`);
await context.sendActivity(`To continue to run this bot, please fix the bot source code.`);
};
// Set the onTurnError for the singleton CloudAdapter.
adapter.onTurnError = onTurnErrorHandler;
// Create HTTP server.
const server = restify.createServer();
server.use(restify.plugins.bodyParser());
server.listen(process.env.port || process.env.PORT || 3978, () => {
console.log(`\nBot Started, ${server.name} listening to ${server.url}`);
});
// Listen for incoming server requests.
server.post("/api/messages", async (req, res) => {
// Route received a request to adapter for processing
await adapter.process(req, res as any, async (context) => {
// Dispatch to application for routing
await app.run(context);
});
});
server.get(
'/auth-:name(start|end).html',
restify.plugins.serveStatic({
directory: path.join(__dirname, 'public')
})
);
provision:
- uses: aadApp/create # Creates a new Azure Active Directory (AAD) app to authenticate users if the environment variable that stores clientId is empty
with:
name: SsoAuthBot-aad # Note: when you run aadApp/update, the AAD app name will be updated based on the definition in manifest. If you don't want to change the name, make sure the name in AAD manifest is the same with the name defined here.
generateClientSecret: true # If the value is false, the action will not generate client secret for you
signInAudience: "AzureADMyOrg" # Authenticate users with a Microsoft work or school account in your organization's Azure AD tenant (for example, single tenant).
writeToEnvironmentFile:
# Write the information of created resources into environment file for the specified environment variable(s).
clientId: AAD_APP_CLIENT_ID
clientSecret: SECRET_AAD_APP_CLIENT_SECRET # Environment variable that starts with `SECRET_` will be stored to the .env.{envName}.user environment file
objectId: AAD_APP_OBJECT_ID
tenantId: AAD_APP_TENANT_ID
authority: AAD_APP_OAUTH_AUTHORITY
authorityHost: AAD_APP_OAUTH_AUTHORITY_HOST
- uses: aadApp/update # Apply the AAD manifest to an existing AAD app. Will use the object id in manifest file to determine which AAD app to update.
with:
manifestPath: ./aad.manifest.json # Relative path to teamsfx folder. Environment variables in manifest will be replaced before apply to AAD app
outputFilePath: ./build/aad.manifest.${{TEAMSFX_ENV}}.json
{
"id": "${{AAD_APP_OBJECT_ID}}",
"appId": "${{AAD_APP_CLIENT_ID}}",
"name": "SsoAuthBot-aad",
"accessTokenAcceptedVersion": 2,
"signInAudience": "AzureADMultipleOrgs",
"optionalClaims": {
"idToken": [],
"accessToken": [
{
"name": "idtyp",
"source": null,
"essential": false,
"additionalProperties": []
}
],
"saml2Token": []
},
"requiredResourceAccess": [
{
"resourceAppId": "Microsoft Graph",
"resourceAccess": [
{
"id": "User.Read",
"type": "Scope"
}
]
}
],
"oauth2Permissions": [
{
"adminConsentDescription": "Allows Teams to call the app's web APIs as the current user.",
"adminConsentDisplayName": "Teams can access app's web APIs",
"id": "${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}",
"isEnabled": true,
"type": "User",
"userConsentDescription": "Enable Teams to call this app's web APIs with the same rights that you have",
"userConsentDisplayName": "Teams can access app's web APIs and make requests on your behalf",
"value": "access_as_user"
}
],
"preAuthorizedApplications": [
{
"appId": "1fec8e78-bce4-4aaf-ab1b-5451cc387264",
"permissionIds": [
"${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"
]
},
{
"appId": "5e3ce6c0-2b1f-4285-8d4b-75ee78787346",
"permissionIds": [
"${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"
]
},
{
"appId": "d3590ed6-52b3-4102-aeff-aad2292ab01c",
"permissionIds": [
"${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"
]
},
{
"appId": "00000002-0000-0ff1-ce00-000000000000",
"permissionIds": [
"${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"
]
},
{
"appId": "bc59ab01-8403-45c6-8796-ac3ef710b3e3",
"permissionIds": [
"${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"
]
},
{
"appId": "0ec893e0-5785-4de6-99da-4ed124e5296c",
"permissionIds": [
"${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"
]
},
{
"appId": "4765445b-32c6-49b0-83e6-1d93765276ca",
"permissionIds": [
"${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"
]
},
{
"appId": "4345a7b9-9a63-4910-a426-35363201d503",
"permissionIds": [
"${{AAD_APP_ACCESS_AS_USER_PERMISSION_ID}}"
]
}
],
"identifierUris":[
"api://botid-${{BOT_ID}}"
],
"replyUrlsWithType":[
{
"url": "https://${{BOT_DOMAIN}}/auth-end.html",
"type": "Web"
}
]
}
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"resourceBaseName": {
"value": "bot${{RESOURCE_SUFFIX}}"
},
"botAadAppClientId": {
"value": "${{BOT_ID}}"
},
"botAadAppClientSecret": {
"value": "${{SECRET_BOT_PASSWORD}}"
},
"openAIKey": {
"value": "${{SECRET_OPENAI_API_KEY}}"
},
"azureOpenAIKey": {
"value": "${{SECRET_AZURE_OPENAI_API_KEY}}"
},
"azureOpenAIEndpoint": {
"value": "${{SECRET_AZURE_OPENAI_ENDPOINT}}"
},
"webAppSKU": {
"value": "B1"
},
"botDisplayName": {
"value": "MS_Teams_Bot-PoC"
},
"aadAppClientId": {
"value": "${{AAD_APP_CLIENT_ID}}"
},
"aadAppClientSecret": {
"value": "${{SECRET_AAD_APP_CLIENT_SECRET}}"
},
"aadAppTenantId": {
"value": "${{AAD_APP_TENANT_ID}}"
},
"aadAppOauthAuthorityHost": {
"value": "${{AAD_APP_OAUTH_AUTHORITY_HOST}}"
}
}
}
@maxLength(20)
@minLength(4)
@description('Used to generate names for all resources in this file')
param resourceBaseName string
@description('Required when create Azure Bot service')
param botAadAppClientId string
@secure()
@description('Required by Bot Framework package in your bot project')
param botAadAppClientSecret string
@secure()
param openAIKey string
@secure()
param azureOpenAIKey string
@secure()
param azureOpenAIEndpoint string
param webAppSKU string
@maxLength(42)
param botDisplayName string
param serverfarmsName string = resourceBaseName
param webAppName string = resourceBaseName
param location string = resourceGroup().location
param aadAppClientId string
param aadAppTenantId string
param aadAppOauthAuthorityHost string
@secure()
param aadAppClientSecret string
// Compute resources for your Web App
resource serverfarm 'Microsoft.Web/serverfarms@2021-02-01' = {
kind: 'app'
location: location
name: serverfarmsName
sku: {
name: webAppSKU
}
}
// Web App that hosts your bot
resource webApp 'Microsoft.Web/sites@2021-02-01' = {
kind: 'app'
location: location
name: webAppName
properties: {
serverFarmId: serverfarm.id
httpsOnly: true
siteConfig: {
alwaysOn: true
ftpsState: 'FtpsOnly'
}
}
}
resource webAppSettings 'Microsoft.Web/sites/config@2021-02-01' = {
name: '${webAppName}/appsettings'
properties: {
WEBSITE_NODE_DEFAULT_VERSION: '~16'
WEBSITE_RUN_FROM_PACKAGE: '1'
BOT_ID: botAadAppClientId
BOT_PASSWORD: botAadAppClientSecret
BOT_DOMAIN: webApp.properties.defaultHostName
AAD_APP_CLIENT_ID: aadAppClientId
AAD_APP_CLIENT_SECRET: aadAppClientSecret
AAD_APP_TENANT_ID: aadAppTenantId
AAD_APP_OAUTH_AUTHORITY_HOST: aadAppOauthAuthorityHost
RUNNING_ON_AZURE: '1'
}
}
// Register your web service as a bot with the Bot Framework
module azureBotRegistration './botRegistration/azurebot.bicep' = {
name: 'Azure-Bot-registration'
params: {
resourceBaseName: resourceBaseName
botAadAppClientId: botAadAppClientId
botAppDomain: webApp.properties.defaultHostName
botDisplayName: botDisplayName
}
}
// The output will be persisted in .env.{envName}. Visit https://aka.ms/teamsfx-actions/arm-deploy for more details.
output BOT_AZURE_APP_SERVICE_RESOURCE_ID string = webApp.id
output BOT_DOMAIN string = webApp.properties.defaultHostName
{
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.16/MicrosoftTeams.schema.json",
"manifestVersion": "1.16",
"version": "1.0.0",
"id": "${{TEAMS_APP_ID}}",
"packageName": "com.microsoft.teams.extension",
"developer": {
"name": "Teams App, Inc.",
"websiteUrl": "https://www.example.com",
"privacyUrl": "https://www.example.com/termofuse",
"termsOfUseUrl": "https://www.example.com/privacy"
},
"icons": {
"color": "color.png",
"outline": "outline.png"
},
"name": {
"short": "MS_Teams_Bot-PoC${{APP_NAME_SUFFIX}}",
"full": "full name for MS_Teams_Bot-PoC"
},
"description": {
"short": "Testing various concepts of Teams Bot",
"full": "We are testing SSO this time round"
},
"accentColor": "#FFFFFF",
"bots": [
{
"botId": "${{BOT_ID}}",
"scopes": [
"personal",
"team",
"groupchat"
],
"supportsFiles": false,
"isNotificationOnly": false
}
],
"composeExtensions": [],
"configurableTabs": [],
"staticTabs": [],
"permissions": [
"identity",
"messageTeamMembers"
],
"validDomains": ["${{BOT_DOMAIN}}",
"*.botframework.com"],
"webApplicationInfo": {
"id": "${{BOT_ID}}",
"resource": "api://botid-${{BOT_ID}}"
}
}
@BlueWhaleSEO Thank you for sharing your files! I tried following your steps but I was unable to reproduce the bug. I will try again with my team and let you know.
In the meantime, to unblock you, this is the recommended approach to add AzureOpenAI
to your SSO bot. This is an example of our SSO bot with AI logic from our ChatModeration bot.
We suggest this approach rather than changes in the config
, YML
, azure.paramters.json
and azure.bicep
files.
STEPS:
- Clone a new version of the SSO Bot
- Run
yarn install
andyarn build
in the root JS folder- Add in the
prompts/chat
folder with yourconfig.json
andskprompt.txt
(in this format)- Comment out lines 104-114
- Add in the code snippet below to your
index.ts
. My model usesgpt-35-turbo
and this is edited in both theindex.ts
andconfig.json
- In your root folder's
.env
file, add your associated keys (see below, similiar to this)- In your
teamsapp.local.yml
, underneathversion: 1.0.0
, addenvironmentFolderPath: ./env
- Press
F5
- TK automatically provisions, deploys the app for you. This will set up your bot locally on Teams.- Send a series of messages to the bot, and the responses will come from the model
Let me know if this works for you.
// Create AI components
const model = new OpenAIModel({
// OpenAI Support
apiKey: process.env.OPENAI_KEY!,
defaultModel: 'gpt-3.5-turbo',
// Azure OpenAI Support
azureApiKey: process.env.AZURE_OPENAI_KEY!,
azureDefaultDeployment: 'gpt-35-turbo',
azureEndpoint: process.env.AZURE_OPENAI_ENDPOINT!,
azureApiVersion: '2023-03-15-preview',
// Request logging
logRequests: true
});
const prompts = new PromptManager({
promptsFolder: path.join(__dirname, '../src/prompts')
});
const planner = new ActionPlanner({
model,
prompts,
defaultPrompt: 'chat'
});
// Create appropriate moderator
let moderator: Moderator;
if (process.env.OPENAI_KEY) {
moderator = new OpenAIModerator({
apiKey: process.env.OPENAI_KEY!,
moderate: 'both'
});
} else {
if (!process.env.AZURE_CONTENT_SAFETY_KEY || !process.env.AZURE_CONTENT_SAFETY_ENDPOINT) {
throw new Error(
'Missing environment variables - please check that both AZURE_CONTENT_SAFETY_KEY and AZURE_CONTENT_SAFETY_ENDPOINT are set.'
);
}
moderator = new AzureContentSafetyModerator({
apiKey: process.env.AZURE_CONTENT_SAFETY_KEY!,
endpoint: process.env.AZURE_CONTENT_SAFETY_ENDPOINT!,
apiVersion: '2023-04-30-preview',
moderate: 'both',
categories: [
{
category: 'Hate',
severity: ModerationSeverity.High
},
{
category: 'SelfHarm',
severity: ModerationSeverity.High
},
{
category: 'Sexual',
severity: ModerationSeverity.High
},
{
category: 'Violence',
severity: ModerationSeverity.High
}
]
// breakByBlocklists: true,
// blocklistNames: [] // Text blocklist Name. Only support following characters: 0-9 A-Z a-z - . _ ~. You could attach multiple lists name here.
});
}
// Define storage and application
const storage = new MemoryStorage();
const app = new ApplicationBuilder<ApplicationTurnState>()
.withStorage(storage)
.withAuthentication(adapter, {
settings: {
graph: {
scopes: ['User.Read'],
msalConfig: {
auth: {
clientId: process.env.AAD_APP_CLIENT_ID!,
clientSecret: process.env.AAD_APP_CLIENT_SECRET!,
authority: `${process.env.AAD_APP_OAUTH_AUTHORITY_HOST}/${process.env.AAD_APP_TENANT_ID}`
}
},
signInLink: `https://${process.env.BOT_DOMAIN}/auth-start.html`,
endOnInvalidMessage: true
}
}
})
.withAIOptions({
planner,
moderator
})
.build();
app.ai.action(AI.FlaggedInputActionName, async (context, state, data) => {
let message = '';
if (data?.categories?.hate) {
message += `<strong>Hate speech</strong> detected. Severity: ${data.category_scores.hate}. `;
}
if (data?.categories?.sexual) {
message += `<strong>Sexual content</strong> detected. Severity: ${data.category_scores.sexual}. `;
}
if (data?.categories?.selfHarm) {
message += `<strong>Self harm</strong> detected. Severity: ${data.category_scores.selfHarm}. `;
}
if (data?.categories?.violence) {
message += `<strong>Violence</strong> detected. Severity: ${data.category_scores.violence}. `;
}
await context.sendActivity(
`I'm sorry your message was flagged due to triggering Azure OpenAI’s content management policy. Reason: ${message}`
);
return AI.StopCommandName;
});
app.ai.action(AI.FlaggedOutputActionName, async (context, state, data) => {
await context.sendActivity(`I'm not allowed to talk about such things.`);
return AI.StopCommandName;
});
app.ai.action(AI.HttpErrorActionName, async (context, state, data) => {
await context.sendActivity('An AI request failed. Please try again later.');
return AI.StopCommandName;
});
AZURE_OPENAI_KEY=
AZURE_OPENAI_ENDPOINT=
AZURE_CONTENT_SAFETY_KEY=
AZURE_CONTENT_SAFETY_ENDPOINT=
Hi @lilyydu.
I've finally had a chance to test your method of installing and running SSO bot. Unfortunately, it comes back with the same error.
Here are my notes on this:
yarn
, which I didn't need to before. wsrun
package was missing, so I had to install that additionally. Error: Script ('yarn install') execution error: warning @microsoft/teams-ai > botbuilder > @azure/msal-node@1.18.4: A newer major version of this library is available. Please upgrade to the latest available version.
. So I've realised I had to downgrade my NodeJS v20 to v18 in order for @azure/msal-node@1.18.4
to work. After that the deployment went ahead. I haven't added anything else besides what was in your instructions and neither have I made any changes in MS Entra entity.
Just thinking out loud - could it be that msal-node 1.18 is not agreeing with the corporate "firewall" somehow? Something like this bug here: https://github.com/Azure/azure-sdk-for-js/issues/21867 ?
Hi @donatas-xyz,
Since you're receiving a 401 again and the bot is responding correctly for other scenarios, it has to do with the configuration of your AzureOpenAI credentials
.env
?azureApiKey, azureDefaultDeployment, azureEndpoint and azureApiVersion
. You can try printing out the values to checkIt's a bit difficult for me to debug- are you able to link me to a public repo with your code and I can try to clone + reproduce?
Hi @lilyydu.
Just to make sure everything is still working without SSO, I've created another basic AI bot using Teams Toolkit. It works as expected.
Let me try to answer your questions:
.env.*
files to store the credentials - as per instructions in documentation. To make it clear, the files end up with the following keys populated:
TEAMSFX_ENV=dev
APP_NAME_SUFFIX=dev
AZURE_SUBSCRIPTION_ID= AZURE_RESOURCE_GROUP_NAME= RESOURCE_SUFFIX=
BOT_ID= TEAMS_APP_ID= BOT_AZURE_APP_SERVICE_RESOURCE_ID= BOT_DOMAIN= TEAMS_APP_TENANT_ID=
### .env.dev.user
```text
SECRET_BOT_PASSWORD=crypto_
SECRET_OPENAI_API_KEY=
SECRET_AZURE_OPENAI_API_KEY=
SECRET_AZURE_OPENAI_ENDPOINT=
TEAMS_APP_UPDATE_TIME=
I appreciate that having a link to a repo would be helpful (I would have to upload the files outside my company's repository though), but in this instance it's literally absolutely nothing different from the template provided by the Teams Toolkit or the example you've kindly shared. It's only my credentials that are different, so the bot itself cannot even be called "mine" as there's nothing of mine in it :)
The credentials above I don't ever change once they are set up. All that gets added is AAD config and credentials. And that's when previously working functionality starts failing with 401 error.
Hi @donatas-xyz,
Awesome, it does look like your credentials are active. Thank you for providing the code snippets as well.
First note- your Azure keys and endpoints are meant to be stored in the .env
file in the root dir, rather than the .env*
files. You can duplicate this file, populate the missing fields, and rename it to ".env". This automatically links to the YML we've set up.
I noticed you're importing a config
file and populating your values inside app.ts
with config's parameters. However, instead, now that we have the .env
file, you can simply do this (we're usingprocess.env
instead of config.
):
/ Create AI components
const model = new OpenAIModel({
// OpenAI Support
apiKey: process.env.OPENAI_KEY!,
defaultModel: 'gpt-3.5-turbo',
// Azure OpenAI Support
azureApiKey: process.env.AZURE_OPENAI_KEY!,
azureDefaultDeployment: 'gpt-35-turbo',
azureEndpoint: process.env.AZURE_OPENAI_ENDPOINT!,
azureApiVersion: '2023-03-15-preview',
// Request logging
logRequests: true
});
I noticed you also changed the YML
, azure.parameters.json
and azure.bicep
files, this is not necessary. These files should be the same as our source code
Hi @lilyydu,
Thank you for your reply. I assume your suggestions are mostly recommendations and not the requirements, as at the end of the day - both methods of implementing SSO should work? What I mean is that I've tried both pure and unmodified Teams Toolkit method and a method of copying ready SSO example from GitHub - both failed with the same issue.
There are not that many files and lines to add to a working AI Chatbot template in order to get SSO working. Or otherwise we are saying we can't incrementally add features to our working solutions unless we get prepared example of said solution from the GitHub :) I have definitely compared every single file and every line between various SSO examples and cannot see anything missing. It definitely made me learn a lot about how the bot app is structured, but it hasn't resolved my issue.
I think the last part to make sure is correct is credentials and MS Entra bit. So if I may ask you to confirm that these settings and assumptions are correct please? We are obviously talking about the most basic out-of-the-box SSO AI bot here.
BOT_PASSWORD
and AAD_APP_CLIENT_SECRET
share the same value found at MS Entra > Bot App > Certificates & secrets > Value. I only have one secret in there at the moment. BOT_ID
and AAD_APP_CLIENT_ID
share the same value TEAMS_APP_TENANT_ID
and AAD_APP_TENANT_ID
share the same value AAD_APP_OAUTH_AUTHORITY=https://login.microsoftonline.com/your-tenant-id-GUID
and AAD_APP_OAUTH_AUTHORITY_HOST=https://login.microsoftonline.com
AAD_APP_ACCESS_AS_USER_PERMISSION_ID
comes from MS Entra > Bot App > Manifest > oauth2Permissions > id like so:
I think besides that I have nothing else left to check and any other ideas my be long shots, such as CORS, corporate firewall and its "certificate issues" etc.
Can I also ask if anyone else managed to get SSO working by simply going fresh Teams Toolkit route as described before? And I mean in an environment that hasn't been prepared for Teams apps development before - no additional firewall ports opened, no NodeJS packages installed, Azure never really used for web apps either, no little one-off environmental hacks applied to just get things working etc. Should it really be just as easy as putting your own credentials in, provisioning and deploying, and then it all (including MS Entra settings) should just work?
Thank you!
Hi @donatas-xyz,
Apologies for the delay, I was OOF
BOT_PASSWORD
and AAD_APP_CLIENT_SECRET
share different values. The one in MS Entra is theBOT_PASSSWORD
Application (client ID)
is not AAD_APP_CLIENT_ID
.
Likewise, Object ID
is not AAD_APP_OBJECT_ID
.
Only Directory(tenant ID)
= AAD_APP_TENANT_ID.
BOT_ID
and AAD_APP_CLIENT_ID
are also differentaad.manifest.json
file. The one in MS Entra is emptyNot to my knowledge, but going to tag @blackchoey for assistance from the Toolkit team as well- any guess to what is going wrong here?
Hi @donatas-xyz To my understanding, you're running your app from Azure App Service. Below bicep snippet you shared previously shows the OpenAI key is not configured to Azure App Service, can you check the App Service's configuration? It should include the endpoint and key for Azure OpenAI.
resource webAppSettings 'Microsoft.Web/sites/config@2021-02-01' = {
name: '${webAppName}/appsettings'
properties: {
WEBSITE_NODE_DEFAULT_VERSION: '~16'
WEBSITE_RUN_FROM_PACKAGE: '1'
BOT_ID: botAadAppClientId
BOT_PASSWORD: botAadAppClientSecret
BOT_DOMAIN: webApp.properties.defaultHostName
AAD_APP_CLIENT_ID: aadAppClientId
AAD_APP_CLIENT_SECRET: aadAppClientSecret
AAD_APP_TENANT_ID: aadAppTenantId
AAD_APP_OAUTH_AUTHORITY_HOST: aadAppOauthAuthorityHost
RUNNING_ON_AZURE: '1'
}
}
As far as I know, MSAL does not use axios to send requests. Since you get an axios error, we may focus on the http requests to Azure OpenAI first. Please let me know if I misunderstand the problem.
Hi @blackchoey. Thank you for getting back to me.
The azure.bicep snippet above is no different to the one found SSO bot example, so are you saying that additional keys of AZURE_OPENAI_API_KEY
and AZURE_OPENAI_ENDPOINT
should be added to it?
Thank you!
Yes, the example you referred does not include AI capability, so it doesn't have the settings. Before you add the AI related app settings, please check your code and update the setting's name accordingly if your code is referencing another setting name.
Well of course it had to be something as stupid as this... It finally works @blackchoey @lilyydu! Thank you!
Besides other questions that this raises, perhaps it would be a good idea to update the SSO bot example with those 2 lines as well, because it's really difficult to consider it a working example under teams-ai repo, when all it can do is to retrieve the Graph key... A simple console app can do that :)
Here's what I had to do in the end:
@secure()
param azureOpenAIKey string
@secure()
param azureOpenAIEndpoint string
// [..]
resource webAppSettings 'Microsoft.Web/sites/config@2021-02-01' = {
name: '${webAppName}/appsettings'
properties: {
WEBSITE_NODE_DEFAULT_VERSION: '~18'
WEBSITE_RUN_FROM_PACKAGE: '1'
BOT_ID: botAadAppClientId
BOT_PASSWORD: botAadAppClientSecret
BOT_DOMAIN: webApp.properties.defaultHostName
AAD_APP_CLIENT_ID: aadAppClientId
AAD_APP_CLIENT_SECRET: aadAppClientSecret
AAD_APP_TENANT_ID: aadAppTenantId
AAD_APP_OAUTH_AUTHORITY_HOST: aadAppOauthAuthorityHost
AZURE_OPENAI_API_KEY: azureOpenAIKey
AZURE_OPENAI_ENDPOINT: azureOpenAIEndpoint
RUNNING_ON_AZURE: '1'
}
}
Thank you once again for your help and your patience!
Now onto the #1130 bug, that's still stopping me from using teams-ai v1.
Language
Javascript/Typescript
Version
latest
Description
I've been trying to implement SSO on bot existing Teams AI Bot app and a new one as well following this example.
In both cases I'm getting "AxiosError: Request failed with status code 401" as soon as I make a request to AI model.
I've tried a myriad of things for days and went through endless examples of similar implementations with nothing else left to check.
The bot is able to successfully:
app.message(/prompting tutorial/i, async (context, state)
)app.conversationUpdate("membersAdded", async (context: TurnContext, state: ApplicationTurnState)
app.authentication.get('graph').onUserSignInSuccess(async (context: TurnContext, state: ApplicationTurnState) => { await context.sendActivity('Successfully logged in'); });
)app.activity(ActivityTypes.Message, async (context: TurnContext, state: ApplicationTurnState) => { await getGraphToken(context, state); });
)However, as soon as I make request that would involve the AI model itself (i.e. "Who are you?"), it returns Axios 401 error.
What is not making it easier is that I'm behind a corporate firewall and using a lot of solutions for debugging is simply out of question for me. I can only reliably use Azure's log stream (which only shows the same error anyway) and the Axios output itself, but it doesn't output anything else, so I don't know what exactly is it not happy about.
I'm not an expert in front-end development, so I would appreciate any other tips on how to work it out what the actual issue here is?
Reproduction Steps