@@ -271,6 +271,12 @@ public static GoogleCredential fromStream(InputStream credentialStream, HttpTran
271271 */
272272 private String serviceAccountId ;
273273
274+ /**
275+ * Service account Project ID or {@code null} if not present, either because this is not using the
276+ * service account flow, or is using an older version of the service account configuration.
277+ */
278+ private String serviceAccountProjectId ;
279+
274280 /**
275281 * Collection of OAuth scopes to use with the service account flow or {@code null} if not
276282 * using the service account flow.
@@ -318,6 +324,7 @@ protected GoogleCredential(Builder builder) {
318324 && builder .serviceAccountScopes == null && builder .serviceAccountUser == null );
319325 } else {
320326 serviceAccountId = Preconditions .checkNotNull (builder .serviceAccountId );
327+ serviceAccountProjectId = builder .serviceAccountProjectId ;
321328 serviceAccountScopes = Collections .unmodifiableCollection (builder .serviceAccountScopes );
322329 serviceAccountPrivateKey = builder .serviceAccountPrivateKey ;
323330 serviceAccountPrivateKeyId = builder .serviceAccountPrivateKeyId ;
@@ -397,6 +404,15 @@ public final String getServiceAccountId() {
397404 return serviceAccountId ;
398405 }
399406
407+ /**
408+ * Returns the service account Project ID or {@code null} if not present, either because this is
409+ * not using the service account flow, or is using an older version of the service account
410+ * configuration.
411+ */
412+ public final String getServiceAccountProjectId () {
413+ return serviceAccountProjectId ;
414+ }
415+
400416 /**
401417 * Returns a collection of OAuth scopes to use with the service account flow or {@code null}
402418 * if not using the service account flow.
@@ -500,6 +516,9 @@ public static class Builder extends Credential.Builder {
500516 /** Id of the private key to use with the service account flow or {@code null} for none. */
501517 String serviceAccountPrivateKeyId ;
502518
519+ /** Project Id associated with the Service Account */
520+ String serviceAccountProjectId ;
521+
503522 /**
504523 * Email address of the user the application is trying to impersonate in the service account
505524 * flow or {@code null} for none.
@@ -582,6 +601,26 @@ public Builder setServiceAccountId(String serviceAccountId) {
582601 return this ;
583602 }
584603
604+ /**
605+ * Returns the service account Project ID or {@code null} for none.
606+ */
607+ public final String getServiceAccountProjectId () {
608+ return serviceAccountProjectId ;
609+ }
610+
611+ /**
612+ * Sets the service account Project ID or {@code null} for none.
613+ *
614+ * <p>
615+ * Overriding is only supported for the purpose of calling the super implementation and changing
616+ * the return type, but nothing else.
617+ * </p>
618+ */
619+ public Builder setServiceAccountProjectId (String serviceAccountProjectId ) {
620+ this .serviceAccountProjectId = serviceAccountProjectId ;
621+ return this ;
622+ }
623+
585624 /**
586625 * Returns a collection of OAuth scopes to use with the service account flow or {@code null}
587626 * for none.
@@ -780,7 +819,8 @@ private static GoogleCredential fromStreamServiceAccount(GenericJson fileContent
780819 String clientEmail = (String ) fileContents .get ("client_email" );
781820 String privateKeyPem = (String ) fileContents .get ("private_key" );
782821 String privateKeyId = (String ) fileContents .get ("private_key_id" );
783- if (clientId == null || clientEmail == null || privateKeyPem == null || privateKeyId == null ) {
822+ if (clientId == null || clientEmail == null || privateKeyPem == null
823+ || privateKeyId == null ) {
784824 throw new IOException ("Error reading service account credential from stream, "
785825 + "expecting 'client_id', 'client_email', 'private_key' and 'private_key_id'." );
786826 }
@@ -800,6 +840,11 @@ private static GoogleCredential fromStreamServiceAccount(GenericJson fileContent
800840 if (tokenUri != null ) {
801841 credentialBuilder .setTokenServerEncodedUrl (tokenUri );
802842 }
843+ String projectId = (String ) fileContents .get ("project_id" );
844+ if (projectId != null ) {
845+ credentialBuilder .setServiceAccountProjectId (projectId );
846+ }
847+
803848 // Don't do a refresh at this point, as it will always fail before the scopes are added.
804849 return credentialBuilder .build ();
805850 }
0 commit comments