@@ -74,6 +74,8 @@ func NewJWTAccessFromKey(jsonKey []byte) (credentials.PerRPCCredentials, error)
74
74
}
75
75
76
76
func (j jwtAccess ) GetRequestMetadata (ctx context.Context , uri ... string ) (map [string ]string , error ) {
77
+ // TODO: the returned TokenSource is reusable. Store it in a sync.Map, with
78
+ // uri as the key, to avoid recreating for every RPC.
77
79
ts , err := google .JWTAccessTokenSourceFromJSON (j .jsonKey , uri [0 ])
78
80
if err != nil {
79
81
return nil , err
@@ -177,9 +179,43 @@ func NewServiceAccountFromFile(keyFile string, scope ...string) (credentials.Per
177
179
// NewApplicationDefault returns "Application Default Credentials". For more
178
180
// detail, see https://developers.google.com/accounts/docs/application-default-credentials.
179
181
func NewApplicationDefault (ctx context.Context , scope ... string ) (credentials.PerRPCCredentials , error ) {
180
- t , err := google .DefaultTokenSource (ctx , scope ... )
182
+ creds , err := google .FindDefaultCredentials (ctx , scope ... )
181
183
if err != nil {
182
184
return nil , err
183
185
}
184
- return TokenSource {t }, nil
186
+
187
+ // If JSON is nil, the authentication is provided by the environment and not
188
+ // with a credentials file, e.g. when code is running on Google Cloud
189
+ // Platform. Use the returned token source.
190
+ if creds .JSON == nil {
191
+ return TokenSource {creds .TokenSource }, nil
192
+ }
193
+
194
+ // If auth is provided by env variable or creds file, the behavior will be
195
+ // different based on whether scope is set. Because the returned
196
+ // creds.TokenSource does oauth with jwt by default, and it requires scope.
197
+ // We can only use it if scope is not empty, otherwise it will fail with
198
+ // missing scope error.
199
+ //
200
+ // If scope is set, use it, it should just work.
201
+ //
202
+ // If scope is not set, we try to use jwt directly without oauth (this only
203
+ // works if it's a service account).
204
+
205
+ if len (scope ) != 0 {
206
+ return TokenSource {creds .TokenSource }, nil
207
+ }
208
+
209
+ // Try to convert JSON to a jwt config without setting the optional scope
210
+ // parameter to check if it's a service account (the function errors if it's
211
+ // not). This is necessary because the returned config doesn't show the type
212
+ // of the account.
213
+ if _ , err := google .JWTConfigFromJSON (creds .JSON ); err != nil {
214
+ // If this fails, it's not a service account, return the original
215
+ // TokenSource from above.
216
+ return TokenSource {creds .TokenSource }, nil
217
+ }
218
+
219
+ // If it's a service account, create a JWT only access with the key.
220
+ return NewJWTAccessFromKey (creds .JSON )
185
221
}
0 commit comments