1

I would like to know how to make an authorized request to firebase storage using the user Id Token as a parameter in the url. Right now with a firebase rule of 'request.auth != null' I receive a 403 network error (Failed to load video: You do not have permission to access the requested resource). Here is my GET request url:

https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<folder_name>%2F<video_name>.mp4?alt=media&auth=eyJh...<ID TOKEN>...Ll2un8ng 

-WITHOUT the firebase rule in place I'm able to successfully get the asset with this request url https://firebasestorage.googleapis.com/v0/b/<bucket>/o/<folder_name>%2F<video_name>.mp4?alt=media

-also tried token=, token_id=, tokenId=

-the reason for not using the firebase SDK to fetch the file is so that I can use the flutter video_player (https://pub.dev/packages/video_player#-example-tab-) package and use this with files in firebase, I mention this in case theres a better way to use the video_player library in flutter web right now:

_controller = VideoPlayerController.network(
      'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4',
      closedCaptionFile: _loadCaptions(),
    );

[EDIT] It appears that it's not possible to pass the auth in as a query parameter. After some exploring, I found an acceptable way to still use the video_player with your firebase assets that are protected (If you're not using rules to protect them, you can directly use the firebase url). I will post some general steps here and some sample code:

Use the Storage Firebase SDK package to get the Uint8List, the uri given by getDownloadURL has the correct header auth, for example

import 'package:firebase/firebase.dart';
final url = await storagePath.getDownloadURL();
final response = await http.get(url);
if (response.statusCode == 200) {
  return response.bodyBytes;
}

use the Uint8List buffer to init a Blob object which you'll use to then create an ObjectURL which basically gives you the same interface as a file url to use as the network url for your video player

final blob = html.Blob([data.buffer], 'video/mp4');
final videoUrl = html.Url.createObjectUrl(blob);
videoPlayerController = VideoPlayerController.network(
          videoUrl)
        ..initialize().then((_) {...

That's it.

Aaron Halvorsen
  • 2,610
  • 1
  • 23
  • 31
  • It is really a bad idea to include auth token or id token in the URL. I'd suggest you to send id token through the `Authorization` header or the POST body. – Quanta Jun 24 '20 at 10:03
  • video player package doesn't support headers (https://github.com/flutter/flutter/issues/16466), looking into other options. Thanks for the input. – Aaron Halvorsen Jun 24 '20 at 12:30
  • Firebase storage appearantly doesn't supports Authorization through GET query string in the url. You'll somehow have to pass the header (possibly using some other package/library) https://cloud.google.com/storage/docs/authentication#apiauth (Yes, Firebase storage uses Google Cloud storage under hood, so this link is a valid reference) – Quanta Jun 24 '20 at 16:03

2 Answers2

2

Firebase Storage REST does not (rightly) support authorization from GET query string as you are trying to do. Instead, it uses the standard Authorization header (see here).

Firebase cloud storage internally uses Google Cloud Storage. Mentioned here

If the library you use doesn't support HTTP headers yet, you must consider an alternative. The issue you mentioned in the comment shows that the feature is still under development, so you can also wait for the library to come out with the support for headers.

Quanta
  • 594
  • 3
  • 24
  • This seems to be correct, that Firebase Storage does not support auth from query string, if someone comes across this, and there is a way to do this please correct me. I did find an interesting solution to still using the video_player package which I will post as an edit to my question. However this package does seam to be a work in progress so please note the date of this post and if things change I will try to post an update here. – Aaron Halvorsen Jun 25 '20 at 00:23
1

Internally all this package does for flutter-web is create an HtmlElementView widget here for which it passes a VideoElement (ref here) from the package dart:html with the provided URL which translates to a <Video> tag inside a shadow dom element in your web page. The error 403 could also mean you are trying to access it from a different origin.

I would suggest following approach.

  1. Check your console for any CORS related errors. If yes, then you will have to whitelist your ip/domain in the firebase storage. Check this post for possible approach and more details here.

  2. Check if you are able to access the URL directly with the authorization token as a query parameter as you suggested. If not then, it is not the correct way to access the object and should be corrected. You could update the question with the exact error details.

Abhilash Chandran
  • 6,803
  • 3
  • 32
  • 50
  • It's not a Cors, it's a permissions error. I'm able to access the url with the firebase sdk like this ( final url = await firebasePath.child(filename).getDownloadURL(); final response = await http.get(url); ) However the video player takes a 1. File, 2. NetworkUrl (that won’t accept a header) or 3. Asset. And doesn’t accept raw data (like UInt8List) which is making it hard to use the firebase sdk in this scenario. I think I’ll look into using Indexeddb and an ObjectURL next, looking into my options. Thanks for the comments about VideoElement, that was helpful! – Aaron Halvorsen Jun 24 '20 at 12:46