applicationDefaultCredentialsAuthenticator function

Future<HttpBasedAuthenticator> applicationDefaultCredentialsAuthenticator(
  1. List<String> scopes
)

Create an HttpBasedAuthenticator using Application Default Credentials.

Looks for credentials in the following order of preference:

  1. A JSON file whose path is specified by GOOGLE_APPLICATION_CREDENTIALS, this file typically contains exported service account keys.
  2. A JSON file created by gcloud auth application-default login in a well-known location (%APPDATA%/gcloud/application_default_credentials.json on Windows and $HOME/.config/gcloud/application_default_credentials.json on Linux/Mac).
  3. On Google Compute Engine and App Engine Flex we fetch credentials from GCE metadata service.

Implementation

Future<HttpBasedAuthenticator> applicationDefaultCredentialsAuthenticator(
  List<String> scopes,
) async {
  File? credFile;
  String? fileSource;
  // If env var specifies a file to load credentials from we'll do that.
  final credsEnv = Platform.environment['GOOGLE_APPLICATION_CREDENTIALS'];
  if (credsEnv != null && credsEnv.isNotEmpty) {
    // If env var is specified and not empty, we always try to load, even if
    // the file doesn't exist.
    credFile = File(credsEnv);
    fileSource = 'GOOGLE_APPLICATION_CREDENTIALS';
  }

  // Attempt to use file created by `gcloud auth application-default login`
  File gcloudAdcFile;
  if (Platform.isWindows) {
    gcloudAdcFile = File.fromUri(Uri.directory(Platform.environment['APPDATA']!)
        .resolve('gcloud/application_default_credentials.json'));
  } else {
    gcloudAdcFile = File.fromUri(Uri.directory(Platform.environment['HOME']!)
        .resolve('.config/gcloud/application_default_credentials.json'));
  }
  // Only try to load from gcloudAdcFile if it exists.
  if (credFile == null && await gcloudAdcFile.exists()) {
    credFile = gcloudAdcFile;
    fileSource = '`gcloud auth application-default login`';
  }

  // Attempt to load form credFile, if detected
  if (credFile != null) {
    Object? credentials;
    try {
      credentials = json.decode(await credFile.readAsString());
    } on IOException {
      throw Exception(
        'Failed to read credentials file from $fileSource',
      );
    } on FormatException {
      throw Exception(
        'Failed to parse JSON from credentials file from $fileSource',
      );
    }

    if (credentials is Map && credentials['type'] == 'authorized_user') {
      final clientId = auth.ClientId(
        credentials['client_id'],
        credentials['client_secret'],
      );

      final client = http.Client();
      try {
        final accessCreds = await auth.refreshCredentials(
          clientId,
          auth.AccessCredentials(
            // Hack: Create empty credentials that have expired.
            auth.AccessToken('Bearer', '', DateTime(0).toUtc()),
            credentials['refresh_token'],
            scopes,
          ),
          client,
        );
        return _CredentialsRefreshingAuthenticator(
          clientId,
          accessCreds,
          credentials['quota_project_id'],
        );
      } finally {
        client.close();
      }
    }

    return ServiceAccountAuthenticator(json.encode(credentials), scopes);
  }

  return ComputeEngineAuthenticator();
}