openclaw - ✅(Solved) Fix Slack download-file fails: auth header stripped on redirect to Slack CDN [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#63523Fetched 2026-04-10 03:42:54
View on GitHub
Comments
1
Participants
2
Timeline
2
Reactions
0
Author
Participants
Timeline (top)
commented ×1cross-referenced ×1

The download-file action for Slack files fails with "File could not be downloaded (not found, too large, or inaccessible)" even though the bot token has files:read scope and the Slack API (files.info) returns the file successfully.

Root Cause

In actions-ClxauASC.js, the createSlackMediaFetch function uses redirect: "manual" and strips the Authorization header after the first request:

function createSlackMediaFetch(token) {
    let includeAuth = true;
    return async (input, init) => {
        if (includeAuth) {
            includeAuth = false;
            headers.set('Authorization', \`Bearer \${token}\`);
            return fetch(parsed.href, { ...rest, headers, redirect: 'manual' });
        }
        headers.delete('Authorization');
        return fetch(url, { ...rest, headers, redirect: 'manual' });
    };
}

When Slack's file hosting returns a redirect (302), the subsequent request to the redirect URL is made without the Authorization header. The redirect target (still a Slack domain) returns an HTML login page instead of the file content. The resolveSlackMedia function then detects the HTML response via looksLikeHtmlBuffer() and returns null.

Fix Action

Fixed

PR fix notes

PR #63588: Codex/issue 63523 slack download auth

Description (problem / solution / changelog)

Summary

  • Problem: Slack download-file 在文件 URL 跳转到 Slack CDN 时,只在首跳带了 Authorization,后续跳转请求丢掉了 token,最终拿到 HTML 登录页而不是文件内容。
  • Why it matters: 这会让已经具备 files:read 权限的 Slack bot 仍然无法下载文件,用户只能看到 “File could not be downloaded”。
  • What changed: 调整 Slack 媒体下载请求逻辑,只要重定向目标仍然是 Slack 自有 HTTPS 域名,就继续附带 Authorization;如果跳出 Slack 域,则移除该 header。并补充回归测试覆盖该行为。
  • What did NOT change (scope boundary): 没有修改 Slack 权限模型、没有扩大 token 可发送的域范围、没有改动非 Slack 渠道或通用下载框架。

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #63523
  • Related #
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: Slack 下载路径里的自定义 fetch 只在第一次请求时附带 AuthorizationfetchRemoteMedia 手动跟随 302 时,第二跳如果仍落在 Slack CDN,就会无 token 请求,返回 HTML 登录页。
  • Missing detection / guardrail: 缺少覆盖 “Slack -> Slack CDN 重定向仍需带 auth” 的回归测试;已有逻辑默认把跨源跳转都当成“不需要 token”。
  • Contributing context (if known): Node/fetch 在跨源重定向时默认不会保留 Authorization,这里原本是手动绕过这个行为,但把 Slack CDN 场景建模得过于宽松了。

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: extensions/slack/src/monitor/media.test.ts
  • Scenario the test should lock in: Slack 文件下载在 files.slack.com 返回 302 到 cdn.slack-edge.com 时,第二跳仍然带 Authorization;如果跳转离开 Slack 域,则移除该 header。
  • Why this is the smallest reliable guardrail: 这个问题完全发生在请求构造和重定向处理层,用 mock fetch 的单测就能稳定复现,不需要真实 Slack 环境。
  • Existing test that already covers this (if any): 无;本 PR 新增/更新了对应覆盖。
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

Slack download-file 在 Slack 自有 CDN 重定向场景下会恢复正常下载,不再错误返回 “File could not be downloaded (not found, too large, or inaccessible)”。无新增配置项,无默认值变化。

Diagram (if applicable)

Before:
[download-file] -> [files.slack.com 302] -> [cdn.slack-edge.com without Authorization] -> [HTML login page] -> [download fails]

After:
[download-file] -> [files.slack.com 302] -> [Slack-owned redirect keeps Authorization] -> [binary file response] -> [download succeeds]

## Changed files

- `extensions/slack/src/monitor/media.test.ts` (modified, +166/-120)
- `extensions/slack/src/monitor/media.ts` (modified, +67/-47)

Code Example

function createSlackMediaFetch(token) {
    let includeAuth = true;
    return async (input, init) => {
        if (includeAuth) {
            includeAuth = false;
            headers.set('Authorization', \`Bearer \${token}\`);
            return fetch(parsed.href, { ...rest, headers, redirect: 'manual' });
        }
        headers.delete('Authorization');
        return fetch(url, { ...rest, headers, redirect: 'manual' });
    };
}
RAW_BUFFERClick to expand / collapse

Description

The download-file action for Slack files fails with "File could not be downloaded (not found, too large, or inaccessible)" even though the bot token has files:read scope and the Slack API (files.info) returns the file successfully.

Root Cause

In actions-ClxauASC.js, the createSlackMediaFetch function uses redirect: "manual" and strips the Authorization header after the first request:

function createSlackMediaFetch(token) {
    let includeAuth = true;
    return async (input, init) => {
        if (includeAuth) {
            includeAuth = false;
            headers.set('Authorization', \`Bearer \${token}\`);
            return fetch(parsed.href, { ...rest, headers, redirect: 'manual' });
        }
        headers.delete('Authorization');
        return fetch(url, { ...rest, headers, redirect: 'manual' });
    };
}

When Slack's file hosting returns a redirect (302), the subsequent request to the redirect URL is made without the Authorization header. The redirect target (still a Slack domain) returns an HTML login page instead of the file content. The resolveSlackMedia function then detects the HTML response via looksLikeHtmlBuffer() and returns null.

Steps to Reproduce

  1. Configure a Slack bot with files:read scope
  2. Upload a file (e.g., image.png) in a Slack channel
  3. Use the message tool with action=download-file and the file ID
  4. Observe: returns "File could not be downloaded"
  5. Direct curl with the same bot token to the url_private works fine

Expected Behavior

The file should download successfully since the bot has proper access.

Suggested Fix

Re-include the Authorization header when the redirect target is still a Slack domain (*.slack.com, *.slack-edge.com, *.slack-files.com). The isSlackHostname() function already exists and could be used for this check.

Environment

  • OpenClaw version: 2026.4.5 (3e72c03)
  • Node.js: v22.22.2
  • Platform: Linux x64

extent analysis

TL;DR

Modify the createSlackMediaFetch function to include the Authorization header in redirect requests when the target is a Slack domain.

Guidance

  • Update the createSlackMediaFetch function to check if the redirect target is a Slack domain using the isSlackHostname() function and re-include the Authorization header if it is.
  • Verify that the isSlackHostname() function correctly identifies Slack domains (*.slack.com, *.slack-edge.com, *.slack-files.com).
  • Test the updated function with a file download request to ensure the Authorization header is included in the redirect request.
  • Confirm that the file downloads successfully after applying the fix.

Example

function createSlackMediaFetch(token) {
    let includeAuth = true;
    return async (input, init) => {
        if (includeAuth) {
            includeAuth = false;
            headers.set('Authorization', `Bearer ${token}`);
            const response = await fetch(parsed.href, { ...rest, headers, redirect: 'manual' });
            if (response.redirected && isSlackHostname(response.url)) {
                headers.set('Authorization', `Bearer ${token}`);
            }
            return response;
        }
        // ...
    };
}

Notes

This fix assumes that the isSlackHostname() function is correctly implemented and can identify Slack domains. If this function is not accurate, the fix may not work as expected.

Recommendation

Apply the workaround by modifying the createSlackMediaFetch function to include the Authorization header in redirect requests to Slack domains, as this should resolve the file download issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING