fix(feishu): correct invalid scope name in permission grant URL (#32509)

* fix(feishu): correct invalid scope name in permission grant URL

The Feishu API returns error code 99991672 with an authorization URL
containing the non-existent scope `contact:contact.base:readonly`
when the `contact.user.get` endpoint is called without the correct
permission. The valid scope is `contact:user.base:readonly`.

Add a scope correction map that replaces known incorrect scope names
in the extracted grant URL before presenting it to the user/agent,
so the authorization link actually works.

Closes #31761

* chore(changelog): note feishu scope correction

---------

Co-authored-by: SidQin-cyber <sidqin0410@gmail.com>
This commit is contained in:
Tak Hoffman
2026-03-02 22:06:42 -06:00
committed by GitHub
parent b3b4fd30c3
commit 6cdfd2eaaa
2 changed files with 18 additions and 1 deletions

View File

@@ -47,6 +47,22 @@ type PermissionError = {
const IGNORED_PERMISSION_SCOPE_TOKENS = ["contact:contact.base:readonly"];
// Feishu API sometimes returns incorrect scope names in permission error
// responses (e.g. "contact:contact.base:readonly" instead of the valid
// "contact:user.base:readonly"). This map corrects known mismatches.
const FEISHU_SCOPE_CORRECTIONS: Record<string, string> = {
"contact:contact.base:readonly": "contact:user.base:readonly",
};
function correctFeishuScopeInUrl(url: string): string {
let corrected = url;
for (const [wrong, right] of Object.entries(FEISHU_SCOPE_CORRECTIONS)) {
corrected = corrected.replaceAll(encodeURIComponent(wrong), encodeURIComponent(right));
corrected = corrected.replaceAll(wrong, right);
}
return corrected;
}
function shouldSuppressPermissionErrorNotice(permissionError: PermissionError): boolean {
const message = permissionError.message.toLowerCase();
return IGNORED_PERMISSION_SCOPE_TOKENS.some((token) => message.includes(token));
@@ -72,7 +88,7 @@ function extractPermissionError(err: unknown): PermissionError | null {
// Extract the grant URL from the error message (contains the direct link)
const msg = feishuErr.msg ?? "";
const urlMatch = msg.match(/https:\/\/[^\s,]+\/app\/[^\s,]+/);
const grantUrl = urlMatch?.[0];
const grantUrl = urlMatch?.[0] ? correctFeishuScopeInUrl(urlMatch[0]) : undefined;
return {
code: feishuErr.code,