I’m working on a PHP script that needs to upload files to Google Drive automatically without user interaction. I want to use a service account for this background process, but I keep getting an error that says the authenticated user hasn’t installed the app.
The error message I’m seeing is: Error 403: The authenticated user has not installed the app with client id [my_client_id]
I’ve already enabled the Drive API in the Google Cloud Console and set up all the required configurations. I even published the app to Chrome Web Store for testing and installed it in my browser.
Here’s my PHP code:
<?php
require_once 'vendor/google-client/src/Client.php';
require_once 'vendor/google-client/src/Service/Drive.php';
$client = new Google_Client();
$client->setClientId(CLIENT_ID);
$client->setClientSecret(CLIENT_SECRET);
$client->setAuthConfig(new Google_Service_Account_Credentials(
SERVICE_EMAIL,
['https://www.googleapis.com/auth/drive'],
file_get_contents(PRIVATE_KEY_PATH)
));
$driveService = new Google_Service_Drive($client);
$document = new Google_Service_Drive_DriveFile();
$document->setName('test-document.txt');
$document->setMimeType('text/plain');
$uploadedFile = $driveService->files->create($document, [
'data' => 'This is the file content',
'mimeType' => 'text/plain'
]);
?>
I thought service accounts could work independently without user permission prompts. How exactly does the authentication work in this case? Am I missing something in my setup?
Your code is mixing service account credentials with OAuth client credentials, which is causing the issue. With service accounts, you do not need CLIENT_ID and CLIENT_SECRET; those are specific to OAuth flows. I encountered this problem last year when I transitioned from user authentication to service accounts. The solution is to completely remove the setClientId() and setClientSecret() calls. Instead, use setAuthConfig() with the path to your service account JSON file. Also, be aware that service accounts create files in their own Drive space by default. To have files show up in a specific user’s Drive, either share the service account’s Drive folder with that user or use domain-wide delegation if you are in a Google Workspace environment. The service account acts like its own user with separate Drive storage.
You’re overcomplicating this. Just use setAuthConfig('/path/to/service-account.json') and skip the client ID/secret stuff. Service accounts don’t need OAuth. Also check that your service account has the right scopes in the JSON file.
You’re initializing the Google_Service_Account_Credentials class wrong. I hit this same issue six months ago when we switched our file processing to service accounts. Your constructor parameters are off. Just use the path to your service account JSON file from Google Cloud Console in setAuthConfig(). Ditch the CLIENT_ID and CLIENT_SECRET lines completely - service accounts don’t use that stuff. The JSON file has everything you need, including the private key. Make sure you actually downloaded the JSON key file when you created the service account, not just copied the email and private key separately. Fix the credential setup and the 403 error goes away. You’re mixing OAuth with service account auth right now.