配置Azure AD多租户应用解决Teams SSO登录匹配错误
Teams多租户应用SSO认证失败:资源与iframe源不匹配
问题背景
我们基于VS Code Teams Toolkit的React模板开发一款将发布到Teams应用商店的应用,原本用Toolkit创建的单租户Azure AD应用实现了SSO登录功能,登录代码如下:
import { TeamsUserCredential } from "@microsoft/teamsfx"; import { useNavigate } from "react-router-dom"; interface IProps { teamsUserCredential?: TeamsUserCredential } const LoginPage = (props: IProps) => { const navigate = useNavigate(); const login = async () => { try { await props.teamsUserCredential?.login(["User.Read", "User.ReadBasic.All"]); navigate("/home"); } catch(e: any) { console.log("User did not logged", e); } } return ( <div > <p>You need to login</p> <button onClick={login}>Login</button> </div> ) } export default LoginPage;
由于Toolkit创建的应用无法启用多租户,我们手动创建了新的多租户Azure AD应用,并修改了Teams应用Manifest匹配该应用,但之后SSO认证失效,点击登录按钮触发错误:Get SSO token failed with error: App resource defined in manifest and iframe origin do not match
应用托管在Azure存储账户,访问URL为https://m365tabxxxxxx.z6.web.core.windows.net,以下是两个Manifest内容:
Teams应用Manifest
{ "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.12/MicrosoftTeams.schema.json", "version": "1.0.15", "manifestVersion": "1.12", "id": "myappid", "packageName": "fr.mycompanyname.myappname", "name": { "short": "myappname", "full": "myappname" }, "developer": { "name": "mycompanyname", "mpnId": "0000000", "websiteUrl": "https://www.mycompanyname.fr/en/", "privacyUrl": "https://www.mycompanyname.fr/privacy-policy/", "termsOfUseUrl": "https://www.mycompanyname.fr/en/legal-informations/" }, "description": { "short": "My app is nice", "full": "My app is nice but longer..." }, "icons": { "outline": "outline.png", "color": "color.png" }, "accentColor": "#FFFFFF", "staticTabs": [ { "entityId": "index0", "name": "Personal Tab", "contentUrl": "https://m365tabxxxxxx.z6.web.core.windows.net/index.html#/tab", "websiteUrl": "https://m365tabxxxxxx.z6.web.core.windows.net/index.html#/tab", "scopes": [ "personal" ] } ], "validDomains": [ "myappname.mycompanyname.fr", "m365tabxxxxxx.z6.web.core.windows.net" ], "webApplicationInfo": { "id": "myMultiTenantAzureADAppId", "resource": "api://myappname.mycompanyname.fr/myMultiTenantAzureADAppId" }, "localizationInfo": { "defaultLanguageTag": "en-us", "additionalLanguages": [ { "languageTag": "fr", "file": "fr.json" } ] }, "publisherDocsUrl": "https://www.mycompanyname.fr/en/help-page/" }
Azure AD应用注册Manifest
{ "id": "MyAADAppObjectId", "acceptMappedClaims": null, "accessTokenAcceptedVersion": 2, "addIns": [], "allowPublicClient": true, "appId": "myMultiTenantAzureADAppId", "appRoles": [], "oauth2AllowUrlPathMatching": false, "createdDateTime": "2023-12-12T16:41:59Z", "description": null, "certification": null, "disabledByMicrosoftStatus": null, "groupMembershipClaims": null, "identifierUris": [ "api://myappname.mycompanyname.fr/myMultiTenantAzureADAppId" ], "informationalUrls": { "termsOfService": "https://www.mycompanyname.fr/en/legal-informations/", "support": null, "privacy": "https://www.mycompanyname.fr/privacy-policy/", "marketing": null }, "keyCredentials": [], "knownClientApplications": [], "logoUrl": "https://mylogourl", "logoutUrl": null, "name": "myappname-multi-tenant", "notes": null, "oauth2AllowIdTokenImplicitFlow": true, "oauth2AllowImplicitFlow": true, "oauth2Permissions": [ { "adminConsentDescription": "Allows Teams to call the app's web APIs as the current user.", "adminConsentDisplayName": "Teams can access app's web APIs", "id": "my_access_as_user_id", "isEnabled": true, "lang": null, "origin": "Application", "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" } ], "oauth2RequirePostResponse": false, "optionalClaims": null, "orgRestrictions": [], "parentalControlSettings": { "countriesBlockedForMinors": [], "legalAgeGroupRule": "Allow" }, "passwordCredentials": [ { "customKeyIdentifier": null, "endDate": "2025-12-12T10:10:24.569Z", "keyId": "myKeyId", "startDate": "2023-12-13T10:10:24.569Z", "value": null, "createdOn": "2023-12-13T10:10:42.6188671Z", "hint": "---", "displayName": "Password uploaded on Wed Dec 13 2023" } ], "preAuthorizedApplications": [ { "appId": "5e3ce6c0-2b1f-4285-8d4b-75ee78787346", /*Microsoft Teams Web Client*/ "permissionIds": [ "my_access_as_user_id" ] }, { "appId": "1fec8e78-bce4-4aaf-ab1b-5451cc387264", /*Microsoft Teams*/ "permissionIds": [ "my_access_as_user_id" ] } ], "publisherDomain": "mycompanyname.fr", "replyUrlsWithType": [ { "url": "https://m365tabxxxxxx.z6.web.core.windows.net", "type": "Web" }, { "url": "https://m365tabxxxxxx.z6.web.core.windows.net/blank-auth-end.html", "type": "Spa" }, { "url": "https://m365tabxxxxxx.z6.web.core.windows.net/auth-end.html", "type": "Web" } ], "requiredResourceAccess": [ { "resourceAppId": "00000003-0000-0000-c000-000000000000", /*Microsoft Graph*/ "resourceAccess": [ { "id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d", /*User.Read*/ "type": "Scope" }, { "id": "b340eb25-3456-403f-be2f-af7a0d370277", /*User.ReadBasic.All*/ "type": "Scope" } ] } ], "samlMetadataUrl": null, "signInUrl": "https://www.mycompanyname.fr/en", "signInAudience": "AzureADandPersonalMicrosoftAccount", "tags": [], "tokenEncryptionKeyId": null }
问题排查与解决方案
核心原因
错误提示的本质是Teams应用Manifest中定义的webApplicationInfo.resource域名,与应用实际运行的iframe源域名不匹配。你的应用当前从Azure存储账户域名m365tabxxxxxx.z6.web.core.windows.net加载,但resource配置的是自定义域名myappname.mycompanyname.fr,Teams的SSO机制会验证这两个域名的一致性,从而拒绝令牌请求。
解决方案(二选一)
方案1:临时使用Azure存储账户域名测试
适用于不需要自定义域名的开发测试阶段:
- 修改Teams应用Manifest的
webApplicationInfo.resource:"webApplicationInfo": { "id": "myMultiTenantAzureADAppId", "resource": "api://m365tabxxxxxx.z6.web.core.windows.net/myMultiTenantAzureADAppId" } - 登录Azure门户,找到对应的多租户AD应用,更新
identifierUris为相同值:"identifierUris": [ "api://m365tabxxxxxx.z6.web.core.windows.net/myMultiTenantAzureADAppId" ] - 重新打包Teams应用并上传到Teams管理中心,清除Teams客户端缓存后测试。
方案2:使用自定义域名正式部署
如果要使用myappname.mycompanyname.fr作为访问域名:
- 将自定义域名映射到Azure存储账户的静态网站终结点(需在Azure门户配置自定义域名绑定)。
- 修改Teams应用Manifest中的
contentUrl和websiteUrl为自定义域名地址:"staticTabs": [ { "contentUrl": "https://myappname.mycompanyname.fr/index.html#/tab", "websiteUrl": "https://myappname.mycompanyname.fr/index.html#/tab" } ] - 确保
validDomains已包含自定义域名(你的配置中已满足)。 - 更新Azure AD应用的
replyUrlsWithType,添加自定义域名的回调地址:"replyUrlsWithType": [ // 保留原有存储账户地址,新增以下项 { "url": "https://myappname.mycompanyname.fr", "type": "Web" }, { "url": "https://myappname.mycompanyname.fr/blank-auth-end.html", "type": "Spa" }, { "url": "https://myappname.mycompanyname.fr/auth-end.html", "type": "Web" } ] - 重新打包上传Teams应用,清除缓存测试。
额外检查项
- 确认
.env配置文件中:REACT_APP_CLIENT_ID设置为多租户AD应用的appIdREACT_APP_OAUTH_AUTHORITY设置为多租户权威地址https://login.microsoftonline.com/common(单租户为租户ID,多租户必须用common)
- 检查
TeamsUserCredential初始化是否使用了正确的参数:const teamsUserCredential = new TeamsUserCredential({ clientId: process.env.REACT_APP_CLIENT_ID, authority: process.env.REACT_APP_OAUTH_AUTHORITY });
内容的提问来源于stack exchange,提问作者supergalou
相关产品推荐
相关产品推荐

