u/nicemike40

▲ 12 r/node+1 crossposts

File upload/download API behind private blob storage. Stream through or hand out SAS URLs?

Hi, really more of an API design question than an azure-specific one.

I'm building a mixed B2B/B2C file API. Customers/partners upload/download up to 500MB files. Storage account is locked down (currently) with no public access (publicNetworkAccess: Disabled) but I'm considering changing this.

Downloads: Two options:

  1. GET /files/:id/content streams bytes through the API (App Service, private endpoint to blob).

  2. MS Graph style: 302 w/ presigned URL, client downloads straight from blob. No streaming through app but storage needs public access.

Uploads:

Currently doing chunked upload sessions modeled on MS Graph createUploadSession. Client POSTs to create a session, gets back an upload URL with a 24h HMAC token, PUTs chunks. Server calls stageBlock. Token is the only auth on the PUT.

Chose this because:

  • 230s App Service request cap rules out single PUT
  • Chunked PUT direct to blob w/ SAS (like downloads option 2) means public storage
    • I'm still wondering if straight-to-SAS-URL is the right move instead of my chunked sessions
    • It makes it a little weird to use because you also have to tell the client what headers they need to include
    • User can upload ANY size to that endpoint (and we can only check when they commit)
    • User can their own storage tier etc. with the headers it seems?

Has anyone done this tradeoff? I see a lot of "just hand out the blob storage SAS URLs" for both but there seems to be some significant downsides for using them for either download or upload. Just looking for advice or examples.

edit: Thanks for all the feedback. Since security and control is much more important to me than a bit more load on my server, I think I'm going to settle on this set up:

  • publicNetworkAccess: Disabled / vnet-only access to the blob storage
  • app-level Bearer/cookie auth on all file endpoints (no presigned urls anywhere)
  • upload is ms graph-style with PUT /files/upload-sessions + PUT /files/upload-sessions/:id (loop) with auto-commit on the last byte uploaded
  • download is direct from a /files/:id/content with a Range: header supported to allow downloading huge files/resumable downloads despite the 230s request timeout.
reddit.com
u/nicemike40 — 2 days ago