Jason
Jason

Reputation: 115

Access Firebase Cloud Storage server-side with security rules applied

On my Firebase app, I'd like to know the recommended way to make a server-side request to Cloud Storage for Firebase on behalf of a signed-in user (authenticated via ID token), with security rules applied to the request (i.e. not with the Admin SDK).

The overall app flow currently looks like this:

For Cloud Storage, I'd like to do something similar to the Firestore case above, but there isn't a Firebase-specific REST API available in the docs. It's possible to just let the client make requests directly to Firebase (as suggested in this answer), but would prefer to keep the logic in the backend.

Are there alternatives to doing this for Storage? Please feel free to also point out if there are better ways of handling the Firebase Auth and Firestore cases mentioned above. Thanks!

EDIT: Adding more possible solutions as I find them

Once you have an ID token, you can pass that to the REST API via the auth query parameter to authenticate a request. The request respects Firebase Security Rules as if the end user logged into the client was making the request.

Upvotes: 3

Views: 574

Answers (3)

Jason
Jason

Reputation: 115

After considering the various options above (thanks Frank and som!), the best choice in my situation was to change things up and make Storage requests directly from the client. The 2 main reasons were:

  • It is the simplest to implement since there is already an SDK that allows you to do this
  • Interacting with Firebase Storage may involve large objects, and so user experience might suffer if there are too many network trips

When making the request from the client, som's answer above and this answer may come in useful if there's a XMLHttpRequest is not defined error

Upvotes: 0

som
som

Reputation: 2477

Edit 6 Jan 2020: This method has had a couple of days testing under heavy-load. See bottom for some minor new requirements.

Original response: This isn't an answer, so much as an in-ecosystem workaround (that works for me!)

Basically, I have a similar-ish use-case with regards an offline-first/potentially insecure iot device that needs auth based storage access with security rules. This morning I took a peek at the Firebase js sdk repo and noted that a native XHR API is the main piece missing from a working node implementation.

I detailed my workaround on this github issue ... included here for convenience:

.. patching the storage library with an XHR polyfill actually appears to work (Node 15 / minimal testing so far). Specifically I've installed xmlhttprequest-ssl and imported it at the top of the storage module (in my case line 5 in @firebase/storage/dist/index.cjs.js):

var XMLHttpRequest = require("xmlhttprequest-ssl").XMLHttpRequest;

Back in the app I import firebase/storage as normal, then just load files from the local file system and upload as per the standard Firebase API:

import { firebase } from "@firebase/app";
import "@firebase/storage";

/* include Firebase setup, etc. */

const filename = 'offline-user-generated-image.jpg';
const file = fs.readFileSync(filename); // for brevity only
const ref = firebase.storage().ref().child(`test/${filename}`);

// use the buffer's underlying arraybuffer 
ref.put(file.buffer, {
  contentType: 'image/jpg', // defaults to 'application/octet-stream'
  customMetadata: {
    uid: 'abc123', // for enhanced security rules
  },
})
.then(() => console.log('done'))
.catch(e => console.log(e));

Storage rules apply to uploads (woop!) and security tokens and custom metadata are applied as expected. Also tested with `putString'. This solves some fairly drastic workarounds for my use case, as it means I can keep my logic/auth/etc. entirely within the Firebase ecosystem. Keen to hear others thoughts.

Note: I'm using patch-package to ensure the patch stays intact across installs / upgrades.

Update 6 Jan 2020: Some extra bits and pieces

It turns out that there is an uncleared timeout in the storage package that causes hell with node processes (and is likely a resource hog in all environments) .. I've submitted a PR (pretty much a clearTimeout) that resolves the issue, but in the meantime this will also need to be manually patched unless you can safely process.exit(0) in your code.

Upvotes: 1

Frank van Puffelen
Frank van Puffelen

Reputation: 599706

There is no way to enforce Firebase's security rules for Cloud Storage when using the Admin SDK. Firebase doesn't provide a documented REST API for Cloud Storage, and I doubt the Google Cloud REST API for Storage accepts Firebase ID tokens.

So I don't really think you have good options to do this from the server on behalf of your users. The two options I can think of:

  1. Pass the necessary information back to the client, and let that access the data through the Firebase SDK - in which case the security rules are enforced.
  2. Replicate the necessary security logic in your Cloud Functions code.

Upvotes: 1

Related Questions