Performance and reliability gauge
Engineering

Hardening Access: Scoped Tokens, Previews, and OAuth Consent

Byte serving now requires scoped tokens, previews moved behind an authenticated path, and OAuth consent shows the scope a caller actually asked for.


Two things got most of our attention this cycle. The first is bytes: who is allowed to pull the contents of a file, and what travels with those bytes when they leave. The second is consent: what the OAuth screen tells you before you grant an application access. Here is what changed.

Byte serving now requires a scoped token

The internal storage endpoints that serve file bytes now require a scoped JWT bearer token. A request for content is authorized against the scope the token was issued with, instead of inheriting trust from whatever context happened to be nearby.

Image and video previews moved with them. Previews are now served from an authenticated, profile-scoped previewer path, so a preview is tied to the profile it belongs to rather than sitting on a separately reachable route.

Embedded metadata is released on download, not on view

Photos and videos carry embedded exif and media metadata, such as camera and capture details. Fastio now releases that metadata when you download the original file, and not when you or an agent views it.

Access fixes

  • Share storage versions. A share storage versions endpoint had been returning 401 to every caller for years. It now responds correctly.
  • Scope bypass closed. A workspace token could reach personal shares. That is fixed.
  • MCP chat token scope. The MCP chat token issued inside workspace-owned shares now carries read scope on the parent workspace, so chat in those shares can read the files it is being asked about.

The consent screen is the only place you get to make an informed decision about a third-party application, so it should show you exactly what was requested, not a friendly summary of it.

  • Unrecognized scopes are shown. They first appeared behind a collapsible disclosure, so a scope string we did not have a friendly label for still showed up.
  • Requested scope is now inline. We then moved the scope out from behind the toggle entirely. If an application asks for it, you see it on the page without clicking anything.
  • Multi-scope requests are handled properly. When an application requests more than one scope, consent explains that you are choosing one.
  • Space-delimited scopes are accepted. The authorize endpoint now takes RFC 6749 space-delimited multi-scope requests, which is what standard OAuth clients send.
  • Unicode scope strings work. A regular expression was rejecting valid scope values containing Unicode. We replaced the pattern with a refinement.

Serving and queue reliability

Locking down the serving path is only useful if the serving path stays up. The rest of the cycle went into that.

  • Ordered representation walks. request_representations gained an ordered-walk engine and now accepts GET.
  • Render space preflight. Renders check for available temporary space before starting, and a reaper cleans up orphaned scratch space instead of letting it accumulate.
  • Cache failures are retryable. A preview cache host failure is now classified as a retryable 503 rather than a 404, so a transient problem no longer looks like a missing file.
  • Asset reads retry. Transient misses retry with cache invalidation instead of failing outright.
  • Direct post-upload enqueue. Upload endpoints enqueue post-upload processing directly, covering content hashing, metadata extraction, and AI indexing.
  • Honest index state. A file is marked Indexed only when the vector upsert actually succeeds, so search state reflects reality.
  • Enqueue throttle. Bulk backfills run behind rate and depth brakes so a large job cannot crowd out live work.
  • Non-fatal receipt stamps. Storage-node receipt stamping is genuinely non-fatal after a move or rename has already committed, so a stamp failure cannot undo work that succeeded.
  • Empty representations map. An empty representations map was serializing as a JSON array. It now serializes as an object, which is what clients expect.

Billing

Superseded subscription invoices are now voided when you re-subscribe, so a re-subscribe cannot leave a stale invoice behind and produce a duplicate charge.

None of this changes what you do day to day. It changes what a token is allowed to reach, what leaves with a file, and what the consent screen tells you before you say yes.

Ready to get started?

Start with a 14-day Business Trial.