Implement Node.js File Export: Temporary Download Links with Presigned Access Control
Short answer: implement the export as an authenticated policy check followed by a short-lived, object-specific presigned download link; keep the game application out of the large-file byte path. When a game platform exports a replay, texture bundle, or moderation video, the application should authorize the request and get out of the byte path. The operational constraint is that a temporary link is a bearer credential: delivery becomes pleasantly simple, while revocation, audience scope, and leakage become harder. I would therefore issue a short-lived, object-specific URL only after an authenticated export record has passed an authorization check, and I would keep the app responsible for policy, not payload streaming. The link is the credential. The choice is less about generating a URL than about deciding which system is allowed to say yes. A storage service can move a 4 GB capture efficiently; it should not decide that a player, tournament staff member, or internal reviewer is entitled to see it. How should I implement a file export with temporary download links? A presigned URL normally packages a method, an object identifier, an expiration time, and an integrity-protected signature. Anyone holding it can usually make the permitted request until it expires, so the URL must be treated like a password with a clock attached. It does not authenticate the person clicking it, and expiration is not the same thing as immediate revocation. That distinction changed how I model export jobs. The API authorizes an export request against a tenant, match, or moderation case, then returns a URL for one immutable result. The storage object remains private, and the browser downloads it directly. The object key is generated server-side from an opaque export ID; accepting a client-supplied path would turn path construction into an authorization bug. The useful invariant is narrow: a valid link grants access to exactly one export, for one operation, until one stated deadline. It does not grant a listing permission, a bucket permission, or access to neighboring objects. That is the boundary worth defending. This boundary is appropriate when the result is already complete and a small authorization service can tolerate bearer-link semantics. It is a poor fit for data that must be revoked instantly, must be watermarked per viewer, or is assembled from many objects under a changing policy. Those cases need a delivery layer that can authenticate each request, or a controlled proxy that accepts the additional bandwidth and on-call burden. The export path I would put in production The API should record the export before handing out a link. A minimal state machine might use queued, ready, expired, and revoked; the download endpoint authorizes only ready, and the signer refuses records whose deadline has passed. A worker writes the finished object to a private namespace and stores its size, checksum, content type, and ownership attributes beside the job record. Here is the important part of the path in Go. The storage adapter is deliberately generic: the policy decision stays testable without coupling it to one provider SDK. package export import ( "context" "errors" "fmt" "time" ) type Export struct { ID string OwnerID string ObjectKey string State string ExpiresAt time.Time } var ErrForbidden = errors.New("export is not available") // Signer creates a GET-only URL for a private object. type Signer interface { SignGet(ctx context.Context, key string, ttl time.Duration) (string, error) } func DownloadURL(ctx context.Context, callerID string, e Export, signer Signer, now time.Time) (string, error) { if e.State != "ready" || e.OwnerID != callerID || !now.Before(e.ExpiresAt) { return "", ErrForbidden } ttl := time.Until(e.ExpiresAt) if ttl
This is a summary aggregated from Dev.to. Read the complete article on the original site:
Read full article at Dev.to