I'm trying to implement a new service to our application using Google Drive Java API v3 that is responsible for uploading files to a specific folder in Google Team Drive. I use the service account that my company has created specifically for this project and also generated a JSON file from Google Developer Console that contains a private key. I have also shared the folder to the service account using its email [email protected] and granted rights of Content Manager to the shared Team Drive. Furthermore, G Suite domain-wide of authority has not been granted to this service account for a few reasons.
What am I trying to achieve here:
I want to build and return an authorized Google Drive client service using the service account’s generated private key and therefore be able to send the requests to upload files to the folder in Google Team Drive.
What I currently use:
What is the problem:
I’m unable to return the authorized Google Drive client service successfully and the requests to upload files are not being sent at all. What makes it more confusing is that there are no exceptions thrown. However, a credential is returned successfully with the access token and an expiration time.
What I have already read/found:
Using OAuth2.0 for Server to Server Application: https://developers.google.com/identity/protocols/OAuth2ServiceAccount
Java Quickstart on creating simple requests to the Drive API: https://developers.google.com/drive/api/v3/quickstart/java
JavaDoc reference for the Drive API: https://developers.google.com/resources/api-libraries/documentation/drive/v3/java/latest/
How to upload file to google drive with service account credential: How to upload file to google drive with service account credential
How to access Team Drive using service account with Google Drive .NET API v3: How to access Team Drive using service account with Google Drive .NET API v3
Authentication to upload files in my drive using Google drive API client library for Java Authentication to upload files in my drive using Google drive API client library for Java
What I have already tried:
The relevant part of ContractStateUpdateService.java:
File fileMetadata = new File();
fileMetadata.setName(fileTitle);
// setting the id of folder to which the file must be inserted to
fileMetadata.setParents(Collections.singletonList("dumbFolderId"));
fileMetadata.setMimeType("application/pdf");
byte[] pdfBytes = Base64.getDecoder().decode(base64File.getBytes(StandardCharsets.UTF_8));
InputStream inputStream = new ByteArrayInputStream(pdfBytes);
// decoding base64 to PDF and its contents to a byte array without saving the file on the file system
InputStreamContent mediaContent = new InputStreamContent("application/pdf", inputStream);
logger.info("Starting to send the request to drive api");
File file = DriveUtils.getDriveService().files().create(fileMetadata, mediaContent).execute();
logger.info("Succesfully uploaded file: " + file.getDriveId());
DriveUtils.java:
public class DriveUtils {
private static final String APPLICATION_NAME = "Google Drive Service";
// setting the Drive scope since it is essential to access Team Drive
private static List<String> SCOPES = Collections.singletonList(DriveScopes.DRIVE);
// private key is stored at the root of the project for now
private static String PRIVATE_KEY_PATH = "/path/to/private_key.json";
private static final Logger logger = LoggerFactory.getLogger(DriveUtils.class);
// build and return an authorized drive client service
public static Drive getDriveService() throws IOException, GeneralSecurityException {
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
GoogleCredentials credentials;
try (FileInputStream inputStream = new FileInputStream(PRIVATE_KEY_PATH)){
credentials = ServiceAccountCredentials.fromStream(inputStream).createScoped(SCOPES);
credentials.refreshIfExpired();
AccessToken token = credentials.getAccessToken();
logger.info("credentials: " + token.getTokenValue());
} catch (FileNotFoundException ex) {
logger.error("File not found: {}", PRIVATE_KEY_PATH);
throw new FileNotFoundException("File not found: " + ex.getMessage());
}
logger.info("Instantiating client next");
// Instantiating a client: this is where the client should be built but nothing happens... no exceptions!
Drive service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, (HttpRequestInitializer) credentials)
.setApplicationName(APPLICATION_NAME)
.build();
// this log should appear immediately after the client has been instantiated but still nothing happens
logger.info("Client instantiated");
return service;
}
}
pom.xml:
<!-- https://mvnrepository.com/artifact/com.google.api-client/google-api-client -->
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.29.2</version>
</dependency>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-drive</artifactId>
<version>v3-rev165-1.25.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.auth/google-auth-library-oauth2-http -->
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>0.16.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.security.oauth/spring-security-oauth2 -->
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.6.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.oauth-client/google-oauth-client-jetty -->
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client-jetty</artifactId>
<version>1.29.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
I'm sure I'm missing something here and I apologize for my English in advance. Any help will be appreciated.
Thank you for your comments, the advices here have been helpful and were worth to look into. However, the solution I'm going to present here isn't going to answer to my question directly on how or why my code didn't produce any error messages. So for now, this is my workaround solution to the problem:
pom.xml:
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>1.23.0</version>
</dependency>
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-drive</artifactId>
<version>v3-rev110-1.23.0</version>
</dependency>
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client-jetty</artifactId>
<version>1.23.0</version>
</dependency>
setSupportsTeamDrive to true. Without the property we wouldn't have been able to save files to the shared folder in Team Drive at all.ContractStateUpdateService.java:
File fileMetadata = new File();
fileMetadata.setName(fileTitle);
// setting the id of folder to which the file must be inserted to
fileMetadata.setParents(Collections.singletonList("dumbTeamDriveId"));
fileMetadata.setMimeType("application/pdf");
// decoding base64 to PDF and its contents to a byte array without saving the file on the file system
byte[] pdfBytes = Base64.getDecoder().decode(base64File.getBytes(StandardCharsets.UTF_8);
InputStream inputStream = new ByteArrayInputStream(pdfBytes);
InputStreamContent mediaContent = new InputStreamContent("application/pdf", inputStream);
try {
// upload updated agreement as a PDF file to the Team Drive folder
DriveUtils.getDriveService().files().create(fileMetadata, mediaContent)
.setSupportsTeamDrives(true) // remember to set this property to true!
.execute();
} catch (IOException ex) {
logger.error("Exception: {}", ex.getMessage());
throw new IOException("Exception: " + ex.getMessage());
} catch (GeneralSecurityException ex) {
logger.error("Exception: {}", ex.getMessage());
throw new GeneralSecurityException("Exception: " + ex.getMessage());
}
Updated code from DriveUtils-class:
// create and return credential
private static Credential getCredentials() throws IOException {
GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream(PRIVATE_KEY_PATH))
.createScoped(SCOPES);
return credential;
}
// build and return an authorized drive client service
public static Drive getDriveService() throws IOException, GeneralSecurityException {
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
// Instantiating a client
Drive service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials())
.setApplicationName(APPLICATION_NAME)
.build();
return service;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With