Custom headers not being passed from AwsS3 plugin to Companion

Hello Uppy team,

I’m experiencing an issue where custom headers specified in the AwsS3 plugin are not being passed to my Companion server. I’ve tried multiple approaches based on various GitHub issues and forum posts, but none have worked.

Environment

  • Uppy version: 4.17.0 (CDN)
  • Companion version: 5.8.0
  • Node.js: 18.20.8
  • Deployment: Companion running on separate subdomain

What I’m trying to achieve

I need to pass user-specific information (x-user-id and x-database-id)
from the client to Companion so I can organize S3 uploads in
user-specific folders using a custom getKey function.

Current Setup

Client-side (Uppy configuration):

  const { Uppy, Dashboard, AwsS3, OneDrive, GoogleDrive } = window.Uppy;

  const uppy = new Uppy({
    debug: true,
    // ... other config
  });

  // Tried setting metadata
  uppy.setMeta({
    userId: '{{ request.user.id }}',
    databaseId: '{{ database.index }}'
  });

  // Tried multiple header configurations
  uppy.use(AwsS3, {
    endpoint: 'https://uploads.domain.com',
    headers: {  // Also tried 'companionHeaders'
      'x-requested-with': 'XMLHttpRequest',
      'x-user-id': '{{ request.user.id }}',
      'x-database-id': '{{ database.index }}'
    }
  });

Server-side (Companion configuration):

  const app = express();

  // Added custom CORS middleware before Companion
  app.use((req, res, next) => {
    res.header('Access-Control-Allow-Headers',
      'Authorization, Origin, Content-Type, Accept, uppy-auth-token, 
  uppy-versions, x-user-id, x-database-id, x-requested-with'
    );
    res.header('Access-Control-Expose-Headers',
  'Access-Control-Allow-Headers');

    if (req.method === 'OPTIONS') {
      res.header('Access-Control-Allow-Origin', req.headers.origin ||
  '*');
      res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, 
  PUT, PATCH, DELETE');
      res.header('Access-Control-Allow-Credentials', 'true');
      return res.sendStatus(200);
    }

    next();
  });

  const companionOptions = {
    corsOrigins: true,
    s3: {
      key: process.env.COMPANION_AWS_KEY,
      secret: process.env.COMPANION_AWS_SECRET,
      bucket: process.env.COMPANION_AWS_BUCKET,
      region: process.env.COMPANION_AWS_REGION || 'us-east-1',
      getKey: (req, filename, metadata) => {
        // Trying to get data from both metadata and headers
        let userId = metadata?.userId || req.headers['x-user-id'] ||
  'anonymous';
        let databaseId = metadata?.databaseId ||
  req.headers['x-database-id'] || 'default';

        const key = `${userId}/${databaseId}/raw/${filename}`;

        console.log('Generating S3 key:', {
          userId, databaseId, filename, key,
          metadata, headers: req.headers
        });

        return key;
      }
    },
    // ... other config
  };

What I’ve tried

  1. Using headers property in AwsS3 plugin configuration
  2. Using companionHeaders property (found in some GitHub issues)
  3. Setting metadata with uppy.setMeta()
  4. Adding custom CORS middleware before Companion
  5. Exposing Access-Control-Allow-Headers in CORS response
  6. Using lowercase header names (Node.js normalization)
  7. Trying AwsS3Multipart instead of AwsS3

The Problem
strong text
When I log the incoming requests in Companion:

  • The custom headers (x-user-id, x-database-id) are not present in
    req.headers
  • The metadata object in getKey is either undefined or doesn’t contain
    my custom fields
  • Files are always uploaded to the anonymous/default/raw/ path

Debug Output

From my debug middleware, I can see Uppy IS sending the standard
headers, but my custom headers are missing:
=== Incoming Request ===
Method: POST
URL: /s3/params
Headers: {
“host”: “uploads.domain.com”,
“content-type”: “application/json”,
“accept”: “application/json”,
“uppy-versions”: “@uppy/aws-s3=…”,
// … other standard headers
// But NO x-user-id or x-database-id!
}

What is the correct way to pass custom headers from the AwsS3 plugin to Companion in the latest versions?

I’ve seen various GitHub issues (#2465, #1059, #2089) mentioning
similar problems, but the solutions don’t seem to work with the current
versions.

Any help would be greatly appreciated! This is blocking our ability to
properly organize user uploads in S3.

Thank you!