Build1 distinct publisher3 min readUpdated
One practitioner's Flutter walkthrough puts the AWS credential back on the server and takes the app server off the upload path. The scoped signature becomes the thing you have to police.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
The presign endpoint is where the risk went, and the sample code makes that legible. The handler builds the object key from `Date.now()` plus `req.body.fileName` and passes `req.body.contentType` straight into the `PutObjectCommand` [9], so the signature covers three attributes: bucket, key, content type [10]. Two of the three arrive from the caller [21]. The long-lived credential is off the device [4], and what replaces it is a service that will sign a write for whatever path and MIME type a client asks for. Smaller grant, still a grant, and validating it is now your job rather than IAM's.
What the backend keeps doing per upload is one small JSON exchange: the client posts a filename and content type, gets a URL back, then PUTs the raw bytes to S3 [12]. The bytes must not be wrapped in JSON, since the signature was cut against the binary body and the declared content type [13]. Success comes back as a 200 with the object ETag [14]. There is a small inconsistency in the write-up worth resolving before you copy it: the prose says the backend already knows the key from the presign step and so the app need not return much [14], while the code comment on the 200 branch tells the app to report the key so the backend can process the file [15]. Those are two different bookkeeping designs wearing the same snippet.
The expiry is the other operational detail. The Node sample signs for 900 seconds, and the author's argument for it is that a leaked URL is inert after the deadline [8]. That cuts the other way for a driver on a bad connection: an upload that has not landed inside the window needs a fresh signature, which puts the presign call on the retry path and not just the happy path [20]. Pinning `ContentType` at signing time has a similar double edge. It stops the object being served later as `application/octet-stream` [11], and it means the type the client declared is the type the object carries.
On the client the same function serves both targets, with the web build passing `Uint8List` bytes from a `file_picker` result instead of a `File` with a path [16]. The whole dependency list is `http` [18], which is the honest tell about where the difficulty sits.
Weight this as what it is: one practitioner's account of one implementation, on a client delivery app where drivers photograph parcels for backend processing [5]. The tooling claim is thin because the tooling is thin. The credential claim does not need corroboration, because a secret in a shipped build is readable by anyone who decompiles it or opens dev tools on the web target [3].
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
The author says the implementation came from a client's delivery app where drivers photograph parcels and the photos needed to land in S3 for the backend to process.
The first version of that delivery app uploaded via a backend proxy; the client's data bill was painful, so the team moved to direct presigned uploads.
The dev.to article walks through uploading files to AWS S3 from a Flutter app on both web and mobile.
The author describes the naive approach, appearing in half the tutorials, as pasting the AWS access key and secret into the app and calling putObject directly, and tells readers not to do it.
According to the author, anyone who decompiles the app, or opens the browser's dev tools on the web build, gets the secret key and then owns the bucket.
The author's recommended flow: the backend signs a short-lived URL, the Flutter app uploads the file directly to that URL, and the secret never leaves the server.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Runnable code, single voice
The mechanics are unusually well evidenced for a single post: concrete Node.js presign code, a Dart upload function, a call site, and a bucket CORS policy that a reader can execute and verify. But everything rests on one self-published practitioner article with no second source, no AWS documentation reference, and no measurements, so the architectural claims are demonstrable while the outcome claims are not.
One self-reported client app
The only adoption signal in the supplied material is the author's own account of a single unnamed client delivery app that migrated from proxy uploads to presigned uploads. There are no release, benchmark, pricing, or third-party deployment observations, and no indication of how widely the pattern is used beyond this one disclosure.
Standard practice, sharpened framing
Mildly overstated. The technical claims are conventional and are backed by working code, but the rhetoric runs ahead of the evidence in two places: the bucket-handover framing is asserted rather than demonstrated, and the data-bill motivation carries no numbers while being presented as the reason for a re-architecture. Offsetting that, the piece understates the new exposure it creates by not noting that the client supplies two of the three signed attributes or that the presign endpoint is now on the retry path.
Practitioner credibility, no vendor tie
Low to moderate. This is an individually authored dev.to tutorial whose author cites shipped client work and a code-review stance, which carries a reputational and consulting-visibility incentive. No sponsorship, vendor affiliation, or commercial relationship with AWS or any tool named is disclosed in the supplied text, and nothing being promoted is the author's own product.
Mechanics solid, outcomes thin
Moderate confidence in the assessment. The described mechanics are internally consistent and shown in code, so claims about how the flow works are safe to rely on. Confidence is held down by the single-publisher cluster, the absence of any independent corroboration, and the fact that the cost and security outcomes rest on one unquantified self-report.
build
The npm audit that works because it never installs the package1 distinct publisher
build
A birth-time calculator that has to know about China's forgotten 1986 summer time1 distinct publisher
build
Two prices, no signup: a gate that charges every request in sats or CPU1 distinct publisher
build
A GAN beauty filter is a device budget allocation, not a feature toggle1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 23, 2026