Lesson 16 / 25

Cloud Storage Uploads and Rules

User files in a bucket.

Upload, link and protect

Cloud Storage for Firebase stores files in a Google Cloud Storage bucket. On the client, create a reference with ref(storage, path), upload with uploadBytes (simple) or uploadBytesResumable (progress, pause and resume), and get a shareable URL with getDownloadURL. Download URLs contain a token and work for anyone who has them, so treat them as semi-public. Storage Security Rules look like Firestore rules: match on path segments, check request.auth, and validate uploads with request.resource.size and request.resource.contentType. Rules cannot inspect file contents, so scan or resize uploads in a function if needed.

Files and trusted code

Cloud Storage holds user files behind storage rules; Cloud Functions run trusted server code with the Admin SDK.

Three ideas: uploads and storage rules, function triggers, schedules and secrets.
Figure 6.1 — Storage, functions and the Admin SDK.

Uploading an avatar and its rules

TypeScript and Storage Security Rules.

import { getStorage, ref, uploadBytesResumable, getDownloadURL } from "firebase/storage";

const storage = getStorage(app);

export function uploadAvatar(uid: string, file: File, onProgress: (pct: number) => void) {
  const fileRef = ref(storage, `users/${uid}/avatar.jpg`);
  const task = uploadBytesResumable(fileRef, file, { contentType: file.type });
  task.on("state_changed", (s) => onProgress((s.bytesTransferred / s.totalBytes) * 100));
  return task.then(() => getDownloadURL(fileRef));
}

/* storage.rules
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /users/{uid}/{fileName} {
      allow read: if request.auth != null;
      allow write: if request.auth != null && request.auth.uid == uid
                   && request.resource.size < 5 * 1024 * 1024
                   && request.resource.contentType.matches('image/.*');
    }
  }
}
*/

Store paths, not only URLs

Save the storage path in Firestore alongside any download URL, so you can delete, move or regenerate access later.

Quick check: Which rule condition limits uploads to images?

  • request.auth.token.image == true
  • resource.data.type == 'image'
  • request.resource.contentType.matches('image/.*')
  • request.time < timestamp.date(2030, 1, 1)
Answer

request.resource.contentType.matches('image/.*') — request.resource describes the incoming file.