use gravatar images for user profiles in laravel jetstream

Laravel Jetstream

Laravel jetstream is a feature rich application starter kit with most common features required by an application already built into it. One of the many amazing features of laravel jetstream is user profiles.

Laravel jetstream comes with a feature which allows your application users to upload their profile images. Once a profile picture gets uploaded, It will be displayed in the navigation menu and used as a dropdown trigger for profile dropdown. This feature can be enabled in the config/jetstream.php configuration file.

Even though i like displaying user profile images in my application, I personally don't like the idea of having a file upload feature. I try to avoid the file upload feature in as much as possible due to the security issues concerns for having a file upload feature.

Laravel jetstream is pretty secure and allows only image files to be uploaded from the profile section. But, It prevents a user from turning off file uploads in PHP. If my application does not have a file upload feature, I prefer to disable the file uploads in php.ini configuration file. This is to prevent attackers exploiting vulnerabilities in any third party package, or other parts of code which grants them access to upload an arbitrary file to the server.

I encourage you to do the same and disable file uploads in your php.ini configuration file if your application does not require file uploads.

Although security is the main reason for not using profile image upload feature, There are other issues with having user uploaded files such as

To avoid the above mentioned issues, I prefer to add file upload feature to applications only if it is an essential part of the application.

That being said, Let's dive right into how we can customize Laravel jetstream to use gravatar images instead of user uploaded profile photos.

what is gravatar?

For those of you who are not familiar with gravatar, You can get profile image for any user just by using their email address. If the user has an account on gravatar.com and has a profile picture added to it, We can easily get the profile picture and use it in our applications. Gravatar's images are being used by many applications worldwide to display user profile picture without actually having a profile picture upload feature in their applications.

Customizing laravel jetstream to use gravatar profile photos

Gravatar images can be used in laravel jetstream simply by overriding a method and commenting out few lines of code.

1. Enable profile photos feature in jetstream

The very first step is to enable profile photos feature in laravel jetstream. if you haven't already enabled it, It can be done in the config/jetstream.php configuration file. Uncomment the below line from the features array.

1 
2'features' => [
3 Features::profilePhotos(),
4],

Once the above line got uncommented, You will start seeing a default placeholder image in navigation. You will also see the profile picture upload option in the user profile settings page. We will be disabling this feature in few minutes.

2. Override default behaviour to retrieve profile images

Once we enable the profile photos feature, We now need to override the way laravel jetstream retrieves the profile images. By default, Laravel jetstream retrieves the profile images by retrieving them from the storage location. We need to override this logic and let jetstream use the gravatar image urls instead of the profile image urls from storage.

We can do this by overriding the getProfilePhotoUrlAttribute method in your User model. This is a method in HasProfilePhoto php trait which is added to your user model. Add the below two method to your user model.

1 
2// app/Models/User.php
3 
4/**
5 * @return string
6 */
7public function getProfilePhotoUrlAttribute()
8{
9 // You can add any of the gravatar supported options to this array.
10 // See https://gravatar.com/site/implement/images/
11 $config = [
12 'default' => $this->defaultProfilePhotoUrl(),
13 'size' => '200' // use 200px by 200px image
14 ];
15 
16 return 'https://www.gravatar.com/avatar/'.md5($this->email).'?'.http_build_query($config);
17}
18 
19/**
20 * @return string
21 */
22public function defaultProfilePhotoUrl()
23{
24 return 'https://ui-avatars.com/api/'. implode('/', [
25 
26 //IMPORTANT: Do not change this order
27 urlencode($this->name), // name
28 200, // image size
29 'EBF4FF', // background color
30 '7F9CF5', // font color
31 ]);
32}

As soon as you add the above methods to your user model, You will start seeing the gravatar images near the profile picture section in the navigation menus and profile settings page. Ofcourse you can customize the default image to use by changing the defaultProfilePhotoUrl method.

3. Remove upload profile picture button from settings page

Now that we have successfully switched our jetstream application to display gravatar profile images, We need to prevent users from uploading any of their images directly to our application. To do this, We need to comment our or remove few lines of code.

Laravel Livewire Stack

If you are using laravel livewire stack for your jetstream application, First publish livewire assets by running

1php artisan vendor:publish --tag=jetstream-views

Now edit resources/views/profile/update-profile-information-form.blade.php file and comment out or remove the following lines.

If you haven't made any changes to this file previously, Most probably these are the lines from line 14 to line 25.

1<!-- Profile Photo File Input -->
2<input type="file" class="hidden"
3 wire:model="photo"
4 x-ref="photo"
5 x-on:change="
6 photoName = $refs.photo.files[0].name;
7 const reader = new FileReader();
8 reader.onload = (e) => {
9 photoPreview = e.target.result;
10 };
11 reader.readAsDataURL($refs.photo.files[0]);
12 " />

Now comment out the following code as well. This will most probably be from line 34 to line 51.

1<!-- New Profile Photo Preview -->
2 <div class="mt-2" x-show="photoPreview">
3 <span class="block rounded-full w-20 h-20"
4 x-bind:style="'background-size: cover; background-repeat: no-repeat; background-position: center center; background-image: url(\'' + photoPreview + '\');'">
5 </span>
6 </div>
7 
8 <x-jet-secondary-button class="mt-2 mr-2" type="button" x-on:click.prevent="$refs.photo.click()">
9 {{ __('Select A New Photo') }}
10 </x-jet-secondary-button>
11 
12 @if ($this->user->profile_photo_path)
13 <x-jet-secondary-button type="button" class="mt-2" wire:click="deleteProfilePhoto">
14 {{ __('Remove Photo') }}
15 </x-jet-secondary-button>
16 @endif
17 
18 <x-jet-input-error for="photo" class="mt-2" />

Inertia Stack

If you are using inertia stack for laravel jetstream, Edit resources/js/Pages/Profile/UpdateProfileInformationForm.vue file and comment out or remove the following lines.

If you haven't made any changes to this file previously, Most probably these are the lines from line 14 to line 17.

1<!-- Profile Photo File Input -->
2<input type="file" class="hidden"
3 ref="photo"
4 @change="updatePhotoPreview">

Now comment out the following code as well. This will most probably be from line 26 to line 41.

1<!-- New Profile Photo Preview -->
2<div class="mt-2" v-show="photoPreview">
3 <span class="block rounded-full w-20 h-20"
4 :style="'background-size: cover; background-repeat: no-repeat; background-position: center center; background-image: url(\'' + photoPreview + '\');'">
5 </span>
6</div>
7 
8<jet-secondary-button class="mt-2 mr-2" type="button" @click.prevent="selectNewPhoto">
9Select A New Photo
10</jet-secondary-button>
11 
12<jet-secondary-button type="button" class="mt-2" @click.prevent="deletePhoto" v-if="user.profile_photo_path">
13Remove Photo
14</jet-secondary-button>
15 
16<jet-input-error :message="form.errors.photo" class="mt-2" />

This will remove the upload profile picture button from the profile settings page.

4. Link to gravatar.com to change profile picture

Now that we changed the entire profile picture functionality to use gravatar.com, we need to link back to gravatar.com so, our users knows where to update their profile picture. Let's add the following piece of code to our profile settings page to link to gravatar.com.

1<p class="mt-2">Update your profile photo on <a href="https://gravatar.com" target="_blank" class="text-indigo-700">gravatar.com</a></p>

Livewire Stack

Add the above code in resources/views/profile/update-profile-information-form.blade.php file below the profile picture. Around line 33 as shown below.

1<!-- Current Profile Photo -->
2<div class="mt-2" x-show="! photoPreview">
3 <img src="{{ $this->user->profile_photo_url }}" alt="{{ $this->user->name }}" class="rounded-full h-20 w-20 object-cover">
4</div>
5<p class="mt-2">Update your profile photo on <a href="https://gravatar.com" target="_blank" class="text-indigo-700">gravatar.com</a></p>

Inertia Stack

Add the above code in resources/js/Pages/Profile/UpdateProfileInformationForm.vue file below the profile picture. Around line 25 as shown below.

1<!-- Current Profile Photo -->
2<div class="mt-2" v-show="! photoPreview">
3 <img :src="user.profile_photo_url" :alt="user.name" class="rounded-full h-20 w-20 object-cover">
4</div>
5<p class="mt-2">Update your profile photo on <a href="https://gravatar.com" target="_blank" class="text-indigo-700">gravatar.com</a></p>

5. Disable profile picture uploads in backend code

By following all the above steps, We are now successfully using gravatar images for user profiles and also disabled uploading of profile images from the UI. There is one step remaining which is disabling of profile images from backend code. We can do this by overriding the updateProfilePhoto and deleteProfilePhoto methods of HasProfilePhoto trait which is added to our user model.

Add the below two methods to your user model.

1// app/Models/User.php
2 
3/**
4 * @param \Illuminate\Http\UploadedFile $photo
5 * @return void
6 */
7public function updateProfilePhoto(\Illuminate\Http\UploadedFile $photo)
8{
9 return;
10}
11 
12/**
13 * @return void
14 */
15public function deleteProfilePhoto()
16{
17 return;
18}

6. Optional - Disable file uploads completely

As I mentioned initially, If your application does not have any feature which allows a user to upload a file, It is better to disable file uploads completely to avoid attackers exploiting any known vulnerabilities in third party packages which allows file uploads. You can disable file uploads by settings file_uploads=Off in your php.ini configuration file.

For daily laravel tips and interesting finds, Follow me on X