How to use Google Drive storage as filesystem in Laravel

Published 20 September 2020 09:06 (8-minute read)

For some projects, we use Google Drive (in combination with a personal @gmail.com account or G Suite account) as a storage provider in Laravel projects. In this post, I'll show how you can set up Google Drive as a storage disk via the Laravel filesystem.

First I'll cover how you set up Google Drive as an external disk in your Laravel application. After that the process of requesting a client for Google Drive via Google API console.

Also, it's possible to use multiple Google Drive connections at the same time as separate disks, that's the latest chapter in the post.

Prepare Laravel application

I'm using an external package, "nao-pon/flysystem-google-drive" for this. Version 1.1 uses the Google Drive API V3, which at the time of writing is not deprecated whereas Google Drive API v2 is.

composer require nao-pon/flysystem-google-drive:~1.1

With the power of the Laravel filesystem, it is possible to set up multiple storage disks that can be used within the same application, but in this example, I'm showing you the basic setup.

In your .env file you need to set the correct credentials to connect to Google Drive APIs.

# file: .env
FILESYSTEM_CLOUD=google # need to exists in config/filesystems.php
GOOGLE_DRIVE_CLIENT_ID=xxx.apps.googleusercontent.com
GOOGLE_DRIVE_CLIENT_SECRET=xxx
GOOGLE_DRIVE_REFRESH_TOKEN=xxx
GOOGLE_DRIVE_FOLDER_ID=null

# want to use shared drives/team drive? 
# open the shared drive and get the id from the URL
#GOOGLE_DRIVE_TEAM_DRIVE_ID=xxx 

In the config/filesystems.php you need to define a storage disk that links the provider with the needed credentials stored in your .env.

// file: config/filesystems.php
<?php
// ...
'disks' => [
    // ...
    'google' => [
        'driver' => 'google',
        'clientId' => env('MAIN_GOOGLE_DRIVE_CLIENT_ID'),
        'clientSecret' => env('MAIN_GOOGLE_DRIVE_CLIENT_SECRET'),
        'refreshToken' => env('MAIN_GOOGLE_DRIVE_REFRESH_TOKEN'),
        'folderId' => env('MAIN_GOOGLE_DRIVE_FOLDER_ID'),
    ],
    // ...
  ],
  // ...
];

We create a custom service provider in app/Providers/GoogleDriveServiceProvider.php where we extend the storage with a custom filesystem driver.

// file: app/Providers/GoogleDriveServiceProvider.php
<?php

namespace App\Providers;

use Google_Client;
use Hypweb\Flysystem\GoogleDrive\GoogleDriveAdapter;
use Illuminate\Support\ServiceProvider;
use League\Flysystem\Filesystem;
use Storage;

class GoogleDriveServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        Storage::extend('google', function($app, $config) {
            $client = new Google_Client();
            $client->setClientId($config['clientId']);
            $client->setClientSecret($config['clientSecret']);
            $client->refreshToken($config['refreshToken']);
            $service = new \Google_Service_Drive($client);

            $options = [];
            if(isset($config['teamDriveId'])) {
                $options['teamDriveId'] = $config['teamDriveId'];
            }

            $adapter = new GoogleDriveAdapter($service, $config['folderId'], $options);

            return new Filesystem($adapter);
        });
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

We need to register our GoogleDriveServiceProvider in config/app.php.

// file: config/app.php
<?php
return [
    // ...
    'providers' => [
        // ...
        App\Providers\GoogleDriveServiceProvider::class,
        // ...
    ],
    // ...
];

Now your Laravel application is ready to connect to Google Drive, but to authenticate you have to request a client from the Google API console.

Setup Google API authentication

This chapter is split into three separate chapters.

  1. Create Google API Client
  2. Get the refresh token
  3. Get the folder id

1, create Google API Client

To request an API client from Google you have to log in to Google Cloud Console and create a project (if you don't have one, it may take some seconds to create).

Next, you can search for the "Google Drive API".

If you don't have the Google Drive API enabled in your Google Cloud project, you need to enable it (may take some seconds to enable).

After you've enabled the Google Drive API you will be redirected to a view where you see some details/statistics about the Google Drive AP. You have to make an OAuth client, this can be done under the "credentials" tab.

At the top of the screen you can create new credentials, you need to use "OAuth client ID".

It's also possible to make a "Service account", but then it's not possible to authenticate multiple users. A "service account" needs to be added to the folder/file/Shared Drive to use it.

You are creating an OAuth client for your usage, so it's not needed to get it reviewed by Google.

In our example, we defined the following details for the OAuth client.

  • Application type: "web application"
  • Name: "web client 3" (or something you can recognise)
  • URIs: "https://developers.google.com/oauthplayground"

After you created the OAuth client you receive 2 keys, those keys are needed to authenticate the user a user for your application. You have to store these items in the .env file:

MAIN_GOOGLE_DRIVE_CLIENT_ID=xxxxxx.apps.googleusercontent.com
MAIN_GOOGLE_DRIVE_CLIENT_SECRET=xxxxxxx

The "Client Secret" is only visible once, after you closed the modal it's not possible to see anymore.

Now the client is created and you can continue to the next step, where you execute the actual authentication.

2, get the refresh token

To get the refresh token we use Google OAuth playground, that's an easy way to test and get your authentication credentials for connecting to the Google APIs.

Go to developers.google.com/oauthplayground and configure the playground to use your Google API client created in step 1.

Next, you have to select the needed API ("Drive API V3" > "https://www.googleapis.com/auth/drive") and click on the "Authorize APIs" button. This will redirect you to a screen where you give permissions to the client (created in step 1) to access your Google Drive.

You may see a screen: "OAuth client is not validated by Google and may be insecure, are you sure you want to continue". You can continue because you made the client yourself.

After the authentication you will be redirected to the OAuth playground where you see the "authorization code" filled, this is a code that is valid for 30 seconds. This code can be used one time to get the refresh & access token.

This can be done using the "exchange authorization code for tokens".

You will receive the "refresh token" & "access token". The "access token" can be used for 3600 seconds and after that, it's not valid anymore.

With the "refresh token" you can receive a new "access token" that's valid for the next 3600 seconds.

Copy the "refresh token" to your .env file (in the example we use the MAIN_GOOGLE_DRIVE_REFRESH_TOKEN key). The package uses this key to get an access token to connect to your Google Drive via the APIs.

3, get the folder id

To select in which folder (or Shared Drive) in Google Drive your application has to store its data you must provide a folder id. This folder id can you get from the URL within Google Drive. Therefore you go to drive.google.com, select the wanted place, and look at the URL. Take the part highlighted in the following images and store them in your .env file.

In our case this is the folder id: "1jH09RbtkNC8dvpo_Xji8eAVhlTh5-T0f".

From that moment your application can use that folder as a disk in your application.

You can set the main cloud disk via .env:

FILESYSTEM_CLOUD=google

Or you can use it programmatically in your applications:

Storage::disk('google')->allFiles()

Use Shared Drives

When you want to use Shared Drives (or Team Drives) you have to provide an extra parameter "teamDriveId" in the config. The config may look like:

// file: config/filesystems.php
<?php
// ...
'disks' => [
    // ...
    'google' => [
        'driver' => 'google',
        'clientId' => env('MAIN_GOOGLE_DRIVE_CLIENT_ID'),
        'clientSecret' => env('MAIN_GOOGLE_DRIVE_CLIENT_SECRET'),
        'refreshToken' => env('MAIN_GOOGLE_DRIVE_REFRESH_TOKEN'),
        'folderId' => env('MAIN_GOOGLE_DRIVE_FOLDER_ID'),
        'teamDriveId' => env('MAIN_GOOGLE_DRIVE_TEAM_DRIVE_ID'),
    ],
    // ...
  ],
  // ...
];

Use multiple Google Drive connections at the same time

It's possible to use multiple Google Drive connections at the same time in your Laravel applications. Therefore you need to add a second disk in config/filesystems.php. For example, it can look like this:

// file: config/filesystems.php
<?php
// ...
'disks' => [
    // ...
    'google' => [
        'driver' => 'google',
        'clientId' => env('MAIN_GOOGLE_DRIVE_CLIENT_ID'),
        'clientSecret' => env('MAIN_GOOGLE_DRIVE_CLIENT_SECRET'),
        'refreshToken' => env('MAIN_GOOGLE_DRIVE_REFRESH_TOKEN'),
        'folderId' => env('MAIN_GOOGLE_DRIVE_FOLDER_ID'),
    ],
   
    'second_google' => [
        'driver' => 'google',
        'clientId' => env('SECOND_GOOGLE_DRIVE_CLIENT_ID'),
        'clientSecret' => env('SECOND_GOOGLE_DRIVE_CLIENT_SECRET'),
        'refreshToken' => env('SECOND_GOOGLE_DRIVE_REFRESH_TOKEN'),
        'folderId' => env('SECOND_GOOGLE_DRIVE_FOLDER_ID'),
    ], 
    // ...
  ],
  // ...
];

And after you set the correct SECOND_GOOGLE disk credentials in your .env you can use the second disk as:

Storage::disk('second_google')->allFiles();

Do you have something to add to this article? Let me know!

Robin Dirksen
Robin Dirksen

Follow me on Twitter, there I post web-related content, tips/tricks, and other interesting things.

On my blog, you can find articles that I've found useful or wanted to share with anyone else.

If you want to know more about this article or just want to talk to me, don't hesitate to reach out.

Webmention by Famdirksen
Famdirksen mentioned on 2nd October 2020