title: Uploading Image to FirebaseStorage - Permission Denied
body: <p>I'm working on authentication/signing up with FirebaseStorage where the user can upload an image during sign-up but I keep on getting errors about the <strong>user not having any permission.</strong> When the user clicks sign-up, the sign-up process using Firebase works because the user is created in Authentication but the information does not get saved on the Firestore Database. Does anyone know what I'm doing wrong?</p>
  <p>This is my Firebase Storage rule:</p>
  <pre><code>rules_version = '2';
  service firebase.storage {
    match /b/{bucket}/o {
      match /user-images {
        allow read, create: if request.auth != null;
      }
      match /avatar.png {
          allow read: if true;
      }
    }
  }
  </code></pre>
  <p>This is the sign-up screen.</p>
  <pre><code>import 'dart:io';
  import 'dart:ui';
  
  import 'package:firebase_storage/firebase_storage.dart';
  import 'package:flutter/material.dart';
  import 'package:firebase_auth/firebase_auth.dart';
  import 'package:flutter/services.dart';
  import 'package:cloud_firestore/cloud_firestore.dart';
  
  import '/screens/auth_screen.dart';
  import '/widgets/build_row.dart';
  import '/screens/chat_screen.dart';
  import '/widgets/user_image_picker.dart';
  
  class SignUpScreen extends StatefulWidget {
    static const routeName = '/sign-up-screen';
  
    @override
    _SignUpScreenState createState() =&gt; _SignUpScreenState();
  }
  
  class _SignUpScreenState extends State&lt;SignUpScreen&gt; {
    final _auth = FirebaseAuth.instance;
  
    final GlobalKey&lt;FormState&gt; _key = GlobalKey();
    String _username = '';
    String _userPW = '';
    String _userEmail = '';
  
    var _isLoading = false;
  
    File? _userImageFile;
    void _pickedImage(File image) {
      _userImageFile = image;
    }
  
    void _submit() {
      final isValid = _key.currentState!.validate();
      if (isValid) {
        _key.currentState!.save();
      }
      this._submitAuthForm(_userEmail.trim(), _userPW.trim(), _username.trim());
    }
  
    void _submitAuthForm(
      String userEmail,
      String password,
      String username,
    ) async {
      try {
        setState(() {
          _isLoading = true;
        });
  
        UserCredential userCredential = await _auth
            .createUserWithEmailAndPassword(email: userEmail, password: password);
  
        final ref = FirebaseStorage.instance
            .ref()
            .child('user-images/${userCredential.user!.uid}.jpg');
  
        final avatarRef = FirebaseStorage.instance.ref().child('avatar.png');
  
        var url;
        if (_userImageFile == null) {
          url = await avatarRef.getDownloadURL();
        }
        if (_userImageFile != null) {
          await ref.putFile(_userImageFile!);
          url = await ref.getDownloadURL();
        }
  
        await FirebaseFirestore.instance
            .collection('users')
            .doc(userCredential.user!.uid)
            .set(
          {
            'username': username,
            'email': userEmail,
            'image_url': url,
          },
        );
        Navigator.of(context).pushReplacement(
          MaterialPageRoute(builder: (ctx) =&gt; ChatScreen()),
        );
      } on PlatformException catch (error) {
        var message = 'An Error has occured!';
        if (error.message != null) {
          message = error.message!;
        }
        setState(() {
          _isLoading = false;
        });
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text(message),
            backgroundColor: Colors.deepPurple.shade600,
          ),
        );
      } catch (error) {
        if (error.toString().contains(
            'The email address is already in use by another account.')) {
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(
              content:
                  Text('The email address is already in use by another account.'),
              backgroundColor: Colors.deepPurple.shade600,
            ),
          );
        }
        print(error);
  
        setState(() {
          _isLoading = false;
        });
      }
    }
  
    @override
    Widget build(BuildContext context) {
      final deviceSize = MediaQuery.of(context).size;
  
      return GestureDetector(
        onTap: () =&gt; FocusManager.instance.primaryFocus?.unfocus(),
        child: Scaffold(
          backgroundColor: Theme.of(context).primaryColor,
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Container(
                  width: deviceSize.width * 0.8,
                  constraints: BoxConstraints(
                      maxHeight: (deviceSize.height -
                              MediaQuery.of(context).viewInsets.bottom) *
                          0.7),
                  decoration: BoxDecoration(
                    border: Border.all(
                      color: Colors.deepPurple.shade600,
                      width: 2.0,
                    ),
                    color: Colors.white,
                  ),
                  child: SingleChildScrollView(
                    padding: EdgeInsets.only(
                      left: 10,
                      bottom: 20,
                    ),
                    child: Form(
                      key: _key,
                      child: Column(
                        mainAxisSize: MainAxisSize.min,
  
                        children: [
                          UserImagePicker(_pickedImage),
                          BuildRowWithIcon(Icons.person, 'Username:', false,
                              (value) {
                            if (value.isEmpty) {
                              return 'Please enter a username';
                            }
                          
                            return null;
                          }, (value) {
                            _username = value;
                          }, 'Username must be at least 6 characters long. Special characters: \$, ^, &amp;, !, ?'),
                          BuildRow(
                            Icons.email_outlined,
                            'E-mail:',
                            false,
                            (value) {
                              if (value.isEmpty) {
                                return 'Please provide an e-mail';
                              }
                              return null;
                            },
                            (value) {
                              _userEmail = value;
                            },
                          ),
                          BuildRowWithIcon(
                              Icons.password_outlined, 'Password:', true,
                              (value) {
                            if (value.isEmpty) {
                              return 'Please enter a password';
                            }
                            if (value.length &lt; 7) {
                              return 'Password must be at least 7 characters long';
                            }
                            return null;
                          }, (value) {
                            _userPW = value;
                          }, 'Password must be at least 7 characters long. You must use a combination of two of the following: letters, numbers, &amp; special characters. Special characters: \$, ^, &amp;, !, ?'),
                          BuildRowWithIcon(
                            Icons.password_outlined,
                            'Confirm PW:',
                            true,
                            (value) {
                              if (value.isEmpty) {
                                return 'Please enter the same password';
                              }
                              return null;
                            },
                            null,
                            'Confirm password',
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
                const SizedBox(height: 30),
                if (_isLoading) CircularProgressIndicator(),
                if (!_isLoading)
                  ElevatedButton(
                    onPressed: _submit,
                    child: const Text(
                      'Sign up!',
                      style: TextStyle(
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    style: ButtonStyle(
                      elevation: MaterialStateProperty.all&lt;double&gt;(20),
                      backgroundColor: MaterialStateProperty.all&lt;Color&gt;(
                          Colors.deepPurple.shade600),
                      foregroundColor: MaterialStateProperty.all&lt;Color&gt;(
                          Colors.tealAccent.shade200),
                      padding: MaterialStateProperty.all&lt;EdgeInsets&gt;(
                          EdgeInsets.all(15)),
                      shadowColor: MaterialStateProperty.all&lt;Color&gt;(
                          Colors.deepPurple.shade800),
                      shape: MaterialStateProperty.all&lt;OutlinedBorder&gt;(
                          RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(15),
                      )),
                    ),
                  ),
                SizedBox(height: 25),
                TextButton(
                  onPressed: () =&gt; Navigator.of(context)
                      .pushReplacementNamed(AuthScreen.routeName),
                  child: Text(
                    'I already have an account.',
                    style: TextStyle(
                      color: Colors.deepPurple.shade400,
                      fontSize: 15,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      );
    }
  }
  </code></pre>
  <p>And this is for the ImagePicker() widget</p>
  <pre><code>import 'package:flutter/material.dart';
  import 'package:image_picker/image_picker.dart';
  import 'dart:io';
  import 'package:path/path.dart' as path;
  
  import 'package:path_provider/path_provider.dart' as syspath;
  
  class UserImagePicker extends StatefulWidget {
    final void Function(File pickedImage) imagePickFn;
  
    UserImagePicker(this.imagePickFn);
  
    @override
    _UserImagePickerState createState() =&gt; _UserImagePickerState();
  }
  
  class _UserImagePickerState extends State&lt;UserImagePicker&gt; {
    File? _pickedImage;
  
    Future&lt;void&gt; _pickImage() async {
      final _pickedImageXFile =
          await ImagePicker().pickImage(
              source: ImageSource.gallery,
              imageQuality: 50,
              maxHeight: 150,
              maxWidth: 150);
      if (_pickedImageXFile == null) {
        return;
      }
      final _pickedImageFile = File(_pickedImageXFile.path);
      setState(() {
        _pickedImage = _pickedImageFile;
      });
      final appDir = await syspath.getApplicationDocumentsDirectory();
      final fileName = path.basename(_pickedImageFile.path);
      final userImageFile =
          await _pickedImageFile.copy('${appDir.path}/$fileName');
      widget.imagePickFn(userImageFile);
    }
  
    @override
    Widget build(BuildContext context) {
      return Column(
        children: [
          Container(
            margin: EdgeInsets.only(top: 10),
            child: CircleAvatar(
              radius: 35,
              backgroundColor: Colors.tealAccent.shade200,
              backgroundImage:
                  _pickedImage == null ? null : FileImage(_pickedImage!),
            ),
          ),
          TextButton.icon(
            onPressed: _pickImage,
            icon: Icon(
              Icons.image_outlined,
              color: Colors.deepPurple.shade600,
            ),
            label: Text(
              'Add User Image',
              style: TextStyle(color: Colors.deepPurple.shade600),
            ),
          ),
        ],
      );
    }
  }
  </code></pre>
  <p><strong>Side question</strong>:
  Is there a way to use Future with validation? I want to be able to show the user while he/she is typing in password/confirm password that it doesn't match the requirements or that the confirm password value doesn't the password value. Do I need to use separate TextControllers for this?</p>