Skip to content

Fix multipart file upload handling in HTTP client#516

Open
BinoyOza-okta wants to merge 2 commits intomasterfrom
OKTA-1131607
Open

Fix multipart file upload handling in HTTP client#516
BinoyOza-okta wants to merge 2 commits intomasterfrom
OKTA-1131607

Conversation

@BinoyOza-okta
Copy link
Contributor

Problem

The theme image upload endpoints (upload_brand_theme_logo, upload_brand_theme_favicon, upload_brand_theme_background_image) were failing with 400 errors due to incorrect multipart/form-data handling.

Root Cause

  • The HTTP client was setting a Content-Type: multipart/form-data header without the required boundary parameter
  • When using aiohttp.FormData, the library needs to generate its own boundary and set the Content-Type header
  • The existing code was overriding this header, causing the server to reject requests

Solution

Changes Made

  1. HTTP Client (okta/http_client.py):

    • Added _remove_content_type_header() helper function to strip Content-Type when using FormData
    • Updated form data processing to support both legacy dict format and new tuple-based format
    • Properly handle file uploads with aiohttp.FormData by:
      • Creating FormData instance for file uploads
      • Removing Content-Type header to let aiohttp set it with boundary
      • Supporting both file paths (legacy) and binary data (new format)
  2. API Layer (okta/api/themes_api.py):

    • Need to set the file parameter with the post_params received from the serialisation process.

Implementation Details

The fix handles two upload patterns:

Pattern 1 - New format (tuple-based):

[("file", ("logo.png", file_bytes, "image/png"))]

Pattern 2 - Legacy format (dict with file path):

{"file": "/path/to/logo.png"}
  • Both patterns now correctly:
  • Create aiohttp.FormData instance
  • Add file data with proper filename and content-type
  • Remove Content-Type header to allow aiohttp to set boundary
  • Successfully upload files to Okta API

Testing

Tested with:

  • ✅ upload_brand_theme_logo - PNG files
  • ✅ upload_brand_theme_favicon - PNG files
  • ✅ upload_brand_theme_background_image - JPG/PNG files
    Example usage:
with open("logo.png", "rb") as f:
    logo_bytes = f.read()

result = await client.upload_brand_theme_logo(
    brand_id=brand_id,
    theme_id=theme_id,
    file=logo_bytes
)

Verification

  • Uploads now return 200/201 status codes
  • Server accepts multipart data with proper boundary
  • Images are correctly stored and accessible via returned URLs
  • No breaking changes to existing API

Breaking Changes

None - this fix is backward compatible with existing code.

- Fix Content-Type header handling for multipart/form-data requests
- Add proper file data handling for binary uploads in aiohttp
- Remove Content-Type header to allow aiohttp to set boundary automatically
- Update form parameter processing to handle both dict and list formats
- Support new tuple-based file upload format: [(field_name, (filename, filedata, mimetype))]

This fixes the multipart upload endpoints for theme images (logo, favicon, background)
where the Content-Type boundary was being overridden, causing "no multipart boundary param" errors.

Fixes: Theme image upload endpoints returning 400 errors
Related files:
- okta/http_client.py
- okta/api/themes_api.py
@BinoyOza-okta BinoyOza-okta self-assigned this Mar 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant