Index: vendor/google/auth/COPYING
===================================================================
--- vendor/google/auth/COPYING	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/COPYING	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2015 Google Inc.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
Index: vendor/google/auth/LICENSE
===================================================================
--- vendor/google/auth/LICENSE	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/LICENSE	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,203 @@
+Apache License
+Version 2.0, January 2004
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction,
+and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by
+the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all
+other entities that control, are controlled by, or are under common
+control with that entity. For the purposes of this definition,
+"control" means (i) the power, direct or indirect, to cause the
+direction or management of such entity, whether by contract or
+otherwise, or (ii) ownership of fifty percent (50%) or more of the
+outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity
+exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications,
+including but not limited to software source code, documentation
+source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical
+transformation or translation of a Source form, including but
+not limited to compiled object code, generated documentation,
+and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or
+Object form, made available under the License, as indicated by a
+copyright notice that is included in or attached to the work
+(an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object
+form, that is based on (or derived from) the Work and for which the
+editorial revisions, annotations, elaborations, or other modifications
+represent, as a whole, an original work of authorship. For the purposes
+of this License, Derivative Works shall not include works that remain
+separable from, or merely link (or bind by name) to the interfaces of,
+the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including
+the original version of the Work and any modifications or additions
+to that Work or Derivative Works thereof, that is intentionally
+submitted to Licensor for inclusion in the Work by the copyright owner
+or by an individual or Legal Entity authorized to submit on behalf of
+the copyright owner. For the purposes of this definition, "submitted"
+means any form of electronic, verbal, or written communication sent
+to the Licensor or its representatives, including but not limited to
+communication on electronic mailing lists, source code control systems,
+and issue tracking systems that are managed by, or on behalf of, the
+Licensor for the purpose of discussing and improving the Work, but
+excluding communication that is conspicuously marked or otherwise
+designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity
+on behalf of whom a Contribution has been received by Licensor and
+subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+this License, each Contributor hereby grants to You a perpetual,
+worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+copyright license to reproduce, prepare Derivative Works of,
+publicly display, publicly perform, sublicense, and distribute the
+Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+this License, each Contributor hereby grants to You a perpetual,
+worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+(except as stated in this section) patent license to make, have made,
+use, offer to sell, sell, import, and otherwise transfer the Work,
+where such license applies only to those patent claims licensable
+by such Contributor that are necessarily infringed by their
+Contribution(s) alone or by combination of their Contribution(s)
+with the Work to which such Contribution(s) was submitted. If You
+institute patent litigation against any entity (including a
+cross-claim or counterclaim in a lawsuit) alleging that the Work
+or a Contribution incorporated within the Work constitutes direct
+or contributory patent infringement, then any patent licenses
+granted to You under this License for that Work shall terminate
+as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+Work or Derivative Works thereof in any medium, with or without
+modifications, and in Source or Object form, provided that You
+meet the following conditions:
+
+(a) You must give any other recipients of the Work or
+Derivative Works a copy of this License; and
+
+(b) You must cause any modified files to carry prominent notices
+stating that You changed the files; and
+
+(c) You must retain, in the Source form of any Derivative Works
+that You distribute, all copyright, patent, trademark, and
+attribution notices from the Source form of the Work,
+excluding those notices that do not pertain to any part of
+the Derivative Works; and
+
+(d) If the Work includes a "NOTICE" text file as part of its
+distribution, then any Derivative Works that You distribute must
+include a readable copy of the attribution notices contained
+within such NOTICE file, excluding those notices that do not
+pertain to any part of the Derivative Works, in at least one
+of the following places: within a NOTICE text file distributed
+as part of the Derivative Works; within the Source form or
+documentation, if provided along with the Derivative Works; or,
+within a display generated by the Derivative Works, if and
+wherever such third-party notices normally appear. The contents
+of the NOTICE file are for informational purposes only and
+do not modify the License. You may add Your own attribution
+notices within Derivative Works that You distribute, alongside
+or as an addendum to the NOTICE text from the Work, provided
+that such additional attribution notices cannot be construed
+as modifying the License.
+
+You may add Your own copyright statement to Your modifications and
+may provide additional or different license terms and conditions
+for use, reproduction, or distribution of Your modifications, or
+for any such Derivative Works as a whole, provided Your use,
+reproduction, and distribution of the Work otherwise complies with
+the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+any Contribution intentionally submitted for inclusion in the Work
+by You to the Licensor shall be under the terms and conditions of
+this License, without any additional terms or conditions.
+Notwithstanding the above, nothing herein shall supersede or modify
+the terms of any separate license agreement you may have executed
+with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+names, trademarks, service marks, or product names of the Licensor,
+except as required for reasonable and customary use in describing the
+origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+agreed to in writing, Licensor provides the Work (and each
+Contributor provides its Contributions) on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+implied, including, without limitation, any warranties or conditions
+of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+PARTICULAR PURPOSE. You are solely responsible for determining the
+appropriateness of using or redistributing the Work and assume any
+risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+whether in tort (including negligence), contract, or otherwise,
+unless required by applicable law (such as deliberate and grossly
+negligent acts) or agreed to in writing, shall any Contributor be
+liable to You for damages, including any direct, indirect, special,
+incidental, or consequential damages of any character arising as a
+result of this License or out of the use or inability to use the
+Work (including but not limited to damages for loss of goodwill,
+work stoppage, computer failure or malfunction, or any and all
+other commercial damages or losses), even if such Contributor
+has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+the Work or Derivative Works thereof, You may choose to offer,
+and charge a fee for, acceptance of support, warranty, indemnity,
+or other liability obligations and/or rights consistent with this
+License. However, in accepting such obligations, You may act only
+on Your own behalf and on Your sole responsibility, not on behalf
+of any other Contributor, and only if You agree to indemnify,
+defend, and hold each Contributor harmless for any liability
+incurred by, or claims asserted against, such Contributor by reason
+of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+To apply the Apache License to your work, attach the following
+boilerplate notice, with the fields enclosed by brackets "[]"
+replaced with your own identifying information. (Don't include
+the brackets!) The text should be enclosed in the appropriate
+comment syntax for the file format. We also recommend that a
+file or class name and description of purpose be included on the
+same "printed page" as the copyright notice for easier
+identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+
Index: vendor/google/auth/README.md
===================================================================
--- vendor/google/auth/README.md	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/README.md	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,361 @@
+# Google Auth Library for PHP
+
+<dl>
+  <dt>Homepage</dt><dd><a href="http://www.github.com/google/google-auth-library-php">http://www.github.com/google/google-auth-library-php</a></dd>
+  <dt>Reference Docs</dt><dd><a href="https://googleapis.github.io/google-auth-library-php/main/">https://googleapis.github.io/google-auth-library-php/main/</a></dd>
+  <dt>Authors</dt>
+    <dd><a href="mailto:temiola@google.com">Tim Emiola</a></dd>
+    <dd><a href="mailto:stanleycheung@google.com">Stanley Cheung</a></dd>
+    <dd><a href="mailto:betterbrent@google.com">Brent Shaffer</a></dd>
+  <dt>Copyright</dt><dd>Copyright © 2015 Google, Inc.</dd>
+  <dt>License</dt><dd>Apache 2.0</dd>
+</dl>
+
+## Description
+
+This is Google's officially supported PHP client library for using OAuth 2.0
+authorization and authentication with Google APIs.
+
+### Installing via Composer
+
+The recommended way to install the google auth library is through
+[Composer](http://getcomposer.org).
+
+```bash
+# Install Composer
+curl -sS https://getcomposer.org/installer | php
+```
+
+Next, run the Composer command to install the latest stable version:
+
+```bash
+composer.phar require google/auth
+```
+
+## Application Default Credentials
+
+This library provides an implementation of
+[Application Default Credentials (ADC)][application default credentials] for PHP.
+
+Application Default Credentials provides a simple way to get authorization
+credentials for use in calling Google APIs, and is
+the recommended approach to authorize calls to Cloud APIs.
+
+### Set up ADC
+
+To use ADC, you must set it up by providing credentials.
+How you set up ADC depends on the environment where your code is running,
+and whether you are running code in a test or production environment.
+
+For more information, see [Set up Application Default Credentials][set-up-adc].
+
+### Enable the API you want to use
+
+Before making your API call, you must be sure the API you're calling has been
+enabled. Go to **APIs & Auth** > **APIs** in the
+[Google Developers Console][developer console] and enable the APIs you'd like to
+call. For the example below, you must enable the `Drive API`.
+
+### Call the APIs
+
+As long as you update the environment variable below to point to *your* JSON
+credentials file, the following code should output a list of your Drive files.
+
+```php
+use Google\Auth\ApplicationDefaultCredentials;
+use GuzzleHttp\Client;
+use GuzzleHttp\HandlerStack;
+
+// specify the path to your application credentials
+putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/my/credentials.json');
+
+// define the scopes for your API call
+$scopes = ['https://www.googleapis.com/auth/drive.readonly'];
+
+// create middleware
+$middleware = ApplicationDefaultCredentials::getMiddleware($scopes);
+$stack = HandlerStack::create();
+$stack->push($middleware);
+
+// create the HTTP client
+$client = new Client([
+  'handler' => $stack,
+  'base_uri' => 'https://www.googleapis.com',
+  'auth' => 'google_auth'  // authorize all requests
+]);
+
+// make the request
+$response = $client->get('drive/v2/files');
+
+// show the result!
+print_r((string) $response->getBody());
+```
+
+##### Guzzle 5 Compatibility
+
+If you are using [Guzzle 5][Guzzle 5], replace the `create middleware` and
+`create the HTTP Client` steps with the following:
+
+```php
+// create the HTTP client
+$client = new Client([
+  'base_url' => 'https://www.googleapis.com',
+  'auth' => 'google_auth'  // authorize all requests
+]);
+
+// create subscriber
+$subscriber = ApplicationDefaultCredentials::getSubscriber($scopes);
+$client->getEmitter()->attach($subscriber);
+```
+
+#### Call using an ID Token
+If your application is running behind Cloud Run, or using Cloud Identity-Aware
+Proxy (IAP), you will need to fetch an ID token to access your application. For
+this, use the static method `getIdTokenMiddleware` on
+`ApplicationDefaultCredentials`.
+
+```php
+use Google\Auth\ApplicationDefaultCredentials;
+use GuzzleHttp\Client;
+use GuzzleHttp\HandlerStack;
+
+// specify the path to your application credentials
+putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/my/credentials.json');
+
+// Provide the ID token audience. This can be a Client ID associated with an IAP application,
+// Or the URL associated with a CloudRun App
+//    $targetAudience = 'IAP_CLIENT_ID.apps.googleusercontent.com';
+//    $targetAudience = 'https://service-1234-uc.a.run.app';
+$targetAudience = 'YOUR_ID_TOKEN_AUDIENCE';
+
+// create middleware
+$middleware = ApplicationDefaultCredentials::getIdTokenMiddleware($targetAudience);
+$stack = HandlerStack::create();
+$stack->push($middleware);
+
+// create the HTTP client
+$client = new Client([
+  'handler' => $stack,
+  'auth' => 'google_auth',
+  // Cloud Run, IAP, or custom resource URL
+  'base_uri' => 'https://YOUR_PROTECTED_RESOURCE',
+]);
+
+// make the request
+$response = $client->get('/');
+
+// show the result!
+print_r((string) $response->getBody());
+```
+
+For invoking Cloud Run services, your service account will need the
+[`Cloud Run Invoker`](https://cloud.google.com/run/docs/authenticating/service-to-service)
+IAM permission.
+
+For invoking Cloud Identity-Aware Proxy, you will need to pass the Client ID
+used when you set up your protected resource as the target audience. See how to
+[secure your IAP app with signed headers](https://cloud.google.com/iap/docs/signed-headers-howto).
+
+#### Call using a specific JSON key
+If you want to use a specific JSON key instead of using `GOOGLE_APPLICATION_CREDENTIALS` environment variable, you can
+ do this:
+
+```php
+use Google\Auth\CredentialsLoader;
+use Google\Auth\Middleware\AuthTokenMiddleware;
+use GuzzleHttp\Client;
+use GuzzleHttp\HandlerStack;
+
+// Define the Google Application Credentials array
+$jsonKey = ['key' => 'value'];
+
+// define the scopes for your API call
+$scopes = ['https://www.googleapis.com/auth/drive.readonly'];
+
+// Load credentials
+$creds = CredentialsLoader::makeCredentials($scopes, $jsonKey);
+
+// optional caching
+// $creds = new FetchAuthTokenCache($creds, $cacheConfig, $cache);
+
+// create middleware
+$middleware = new AuthTokenMiddleware($creds);
+$stack = HandlerStack::create();
+$stack->push($middleware);
+
+// create the HTTP client
+$client = new Client([
+  'handler' => $stack,
+  'base_uri' => 'https://www.googleapis.com',
+  'auth' => 'google_auth'  // authorize all requests
+]);
+
+// make the request
+$response = $client->get('drive/v2/files');
+
+// show the result!
+print_r((string) $response->getBody());
+
+```
+
+#### Call using Proxy-Authorization Header
+If your application is behind a proxy such as [Google Cloud IAP][iap-proxy-header],
+and your application occupies the `Authorization` request header,
+you can include the ID token in a `Proxy-Authorization: Bearer`
+header instead. If a valid ID token is found in a `Proxy-Authorization` header,
+IAP authorizes the request with it. After authorizing the request, IAP passes
+the Authorization header to your application without processing the content.
+For this, use the static method `getProxyIdTokenMiddleware` on
+`ApplicationDefaultCredentials`.
+
+```php
+use Google\Auth\ApplicationDefaultCredentials;
+use GuzzleHttp\Client;
+use GuzzleHttp\HandlerStack;
+
+// specify the path to your application credentials
+putenv('GOOGLE_APPLICATION_CREDENTIALS=/path/to/my/credentials.json');
+
+// Provide the ID token audience. This can be a Client ID associated with an IAP application
+//    $targetAudience = 'IAP_CLIENT_ID.apps.googleusercontent.com';
+$targetAudience = 'YOUR_ID_TOKEN_AUDIENCE';
+
+// create middleware
+$middleware = ApplicationDefaultCredentials::getProxyIdTokenMiddleware($targetAudience);
+$stack = HandlerStack::create();
+$stack->push($middleware);
+
+// create the HTTP client
+$client = new Client([
+  'handler' => $stack,
+  'auth' => ['username', 'pass'], // auth option handled by your application
+  'proxy_auth' => 'google_auth',
+]);
+
+// make the request
+$response = $client->get('/');
+
+// show the result!
+print_r((string) $response->getBody());
+```
+
+[iap-proxy-header]: https://cloud.google.com/iap/docs/authentication-howto#authenticating_from_proxy-authorization_header
+
+#### External credentials (Workload identity federation)
+
+Using workload identity federation, your application can access Google Cloud resources from Amazon Web Services (AWS),
+Microsoft Azure or any identity provider that supports OpenID Connect (OIDC).
+
+Traditionally, applications running outside Google Cloud have used service account keys to access Google Cloud
+resources. Using identity federation, you can allow your workload to impersonate a service account. This lets you access
+Google Cloud resources directly, eliminating the maintenance and security burden associated with service account keys.
+
+Follow the detailed instructions on how to
+[Configure Workload Identity Federation](https://cloud.google.com/iam/docs/workload-identity-federation-with-other-clouds).
+
+#### Verifying JWTs
+
+If you are [using Google ID tokens to authenticate users][google-id-tokens], use
+the `Google\Auth\AccessToken` class to verify the ID token:
+
+```php
+use Google\Auth\AccessToken;
+
+$auth = new AccessToken();
+$auth->verify($idToken);
+```
+
+If your app is running behind [Google Identity-Aware Proxy][iap-id-tokens]
+(IAP), you can verify the ID token coming from the IAP server by pointing to the
+appropriate certificate URL for IAP. This is because IAP signs the ID
+tokens with a different key than the Google Identity service:
+
+```php
+use Google\Auth\AccessToken;
+
+$auth = new AccessToken();
+$auth->verify($idToken, [
+  'certsLocation' => AccessToken::IAP_CERT_URL
+]);
+```
+
+[google-id-tokens]: https://developers.google.com/identity/sign-in/web/backend-auth
+[iap-id-tokens]: https://cloud.google.com/iap/docs/signed-headers-howto
+
+## Caching
+Caching is enabled by passing a PSR-6 `CacheItemPoolInterface`
+instance to the constructor when instantiating the credentials.
+
+We offer some caching classes out of the box under the `Google\Auth\Cache` namespace.
+
+```php
+use Google\Auth\ApplicationDefaultCredentials;
+use Google\Auth\Cache\MemoryCacheItemPool;
+
+// Cache Instance
+$memoryCache = new MemoryCacheItemPool;
+
+// Get the credentials
+// From here, the credentials will cache the access token
+$middleware = ApplicationDefaultCredentials::getCredentials($scope, cache: $memoryCache);
+```
+
+### FileSystemCacheItemPool Cache
+The `FileSystemCacheItemPool` class is a `PSR-6` compliant cache that stores its
+serialized objects on disk, caching data between processes and making it possible 
+to use data between different requests.
+
+```php
+use Google\Auth\Cache\FileSystemCacheItemPool;
+use Google\Auth\ApplicationDefaultCredentials;
+
+// Create a Cache pool instance
+$cache = new FileSystemCacheItemPool(__DIR__ . '/cache');
+
+// Pass your Cache to the Auth Library
+$credentials = ApplicationDefaultCredentials::getCredentials($scope, cache: $cache);
+
+// This token will be cached and be able to be used for the next request
+$token = $credentials->fetchAuthToken();
+```
+
+### Integrating with a third party cache
+You can use a third party that follows the `PSR-6` interface of your choice.
+
+```php
+// run "composer require symfony/cache"
+use Google\Auth\ApplicationDefaultCredentials;
+use Symfony\Component\Cache\Adapter\FilesystemAdapter;
+
+// Create the cache instance
+$filesystemCache = new FilesystemAdapter();
+
+// Create Get the credentials
+$credentials = ApplicationDefaultCredentials::getCredentials($targetAudience, cache: $filesystemCache);
+```
+
+## License
+
+This library is licensed under Apache 2.0. Full license text is
+available in [COPYING][copying].
+
+## Contributing
+
+See [CONTRIBUTING][contributing].
+
+## Support
+
+Please
+[report bugs at the project on Github](https://github.com/google/google-auth-library-php/issues). Don't
+hesitate to
+[ask questions](http://stackoverflow.com/questions/tagged/google-auth-library-php)
+about the client or APIs on [StackOverflow](http://stackoverflow.com).
+
+[google-apis-php-client]: https://github.com/google/google-api-php-client
+[application default credentials]: https://cloud.google.com/docs/authentication/application-default-credentials
+[contributing]: https://github.com/google/google-auth-library-php/tree/main/.github/CONTRIBUTING.md
+[copying]: https://github.com/google/google-auth-library-php/tree/main/COPYING
+[Guzzle]: https://github.com/guzzle/guzzle
+[Guzzle 5]: http://docs.guzzlephp.org/en/5.3
+[developer console]: https://console.developers.google.com
+[set-up-adc]: https://cloud.google.com/docs/authentication/provide-credentials-adc
Index: vendor/google/auth/SECURITY.md
===================================================================
--- vendor/google/auth/SECURITY.md	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/SECURITY.md	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,7 @@
+# Security Policy
+
+To report a security issue, please use [g.co/vulnz](https://g.co/vulnz).
+
+The Google Security Team will respond within 5 working days of your report on g.co/vulnz.
+
+We use g.co/vulnz for our intake, and do coordination and disclosure here using GitHub Security Advisory to privately discuss and fix the issue.
Index: vendor/google/auth/VERSION
===================================================================
--- vendor/google/auth/VERSION	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/VERSION	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,1 @@
+1.43.0
Index: vendor/google/auth/autoload.php
===================================================================
--- vendor/google/auth/autoload.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/autoload.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,34 @@
+<?php
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+function oauth2client_php_autoload($className)
+{
+    $classPath = explode('_', $className);
+    if ($classPath[0] != 'Google') {
+        return;
+    }
+    if (count($classPath) > 3) {
+        // Maximum class file path depth in this project is 3.
+        $classPath = array_slice($classPath, 0, 3);
+    }
+    $filePath = dirname(__FILE__) . '/src/' . implode('/', $classPath) . '.php';
+    if (file_exists($filePath)) {
+        require_once $filePath;
+    }
+}
+
+spl_autoload_register('oauth2client_php_autoload');
Index: vendor/google/auth/composer.json
===================================================================
--- vendor/google/auth/composer.json	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/composer.json	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,43 @@
+{
+  "name": "google/auth",
+  "type": "library",
+  "description": "Google Auth Library for PHP",
+  "keywords": ["google", "oauth2", "authentication"],
+  "homepage": "http://github.com/google/google-auth-library-php",
+  "license": "Apache-2.0",
+  "support": {
+    "docs": "https://googleapis.github.io/google-auth-library-php/main/"
+  },
+  "require": {
+    "php": "^8.1",
+    "firebase/php-jwt": "^6.0",
+    "guzzlehttp/guzzle": "^7.4.5",
+    "guzzlehttp/psr7": "^2.4.5",
+    "psr/http-message": "^1.1||^2.0",
+    "psr/cache": "^2.0||^3.0"
+  },
+  "require-dev": {
+    "guzzlehttp/promises": "^2.0",
+    "squizlabs/php_codesniffer": "^3.5",
+    "phpunit/phpunit": "^9.6",
+    "phpspec/prophecy-phpunit": "^2.1",
+    "sebastian/comparator": ">=1.2.3",
+    "phpseclib/phpseclib": "^3.0.35",
+    "kelvinmo/simplejwt": "0.7.1",
+    "webmozart/assert": "^1.11",
+    "symfony/process": "^6.0||^7.0"
+  },
+  "suggest": {
+    "phpseclib/phpseclib": "May be used in place of OpenSSL for signing strings or for token management. Please require version ^2."
+  },
+  "autoload": {
+    "psr-4": {
+      "Google\\Auth\\": "src"
+    }
+  },
+  "autoload-dev": {
+    "psr-4": {
+      "Google\\Auth\\Tests\\": "tests"
+    }
+  }
+}
Index: vendor/google/auth/src/AccessToken.php
===================================================================
--- vendor/google/auth/src/AccessToken.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/AccessToken.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,473 @@
+<?php
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+use DateTime;
+use Firebase\JWT\ExpiredException;
+use Firebase\JWT\JWT;
+use Firebase\JWT\Key;
+use Firebase\JWT\SignatureInvalidException;
+use Google\Auth\Cache\MemoryCacheItemPool;
+use Google\Auth\HttpHandler\HttpClientCache;
+use Google\Auth\HttpHandler\HttpHandlerFactory;
+use GuzzleHttp\Psr7\Request;
+use GuzzleHttp\Psr7\Utils;
+use InvalidArgumentException;
+use phpseclib3\Crypt\PublicKeyLoader;
+use phpseclib3\Crypt\RSA;
+use phpseclib3\Math\BigInteger;
+use Psr\Cache\CacheItemPoolInterface;
+use RuntimeException;
+use SimpleJWT\InvalidTokenException;
+use SimpleJWT\JWT as SimpleJWT;
+use SimpleJWT\Keys\KeyFactory;
+use SimpleJWT\Keys\KeySet;
+use TypeError;
+use UnexpectedValueException;
+
+/**
+ * Wrapper around Google Access Tokens which provides convenience functions.
+ *
+ * @experimental
+ */
+class AccessToken
+{
+    const FEDERATED_SIGNON_CERT_URL = 'https://www.googleapis.com/oauth2/v3/certs';
+    const IAP_CERT_URL = 'https://www.gstatic.com/iap/verify/public_key-jwk';
+    const IAP_ISSUER = 'https://cloud.google.com/iap';
+    const OAUTH2_ISSUER = 'accounts.google.com';
+    const OAUTH2_ISSUER_HTTPS = 'https://accounts.google.com';
+    const OAUTH2_REVOKE_URI = 'https://oauth2.googleapis.com/revoke';
+
+    /**
+     * @var callable
+     */
+    private $httpHandler;
+
+    /**
+     * @var CacheItemPoolInterface
+     */
+    private $cache;
+
+    /**
+     * @param callable|null $httpHandler [optional] An HTTP Handler to deliver PSR-7 requests.
+     * @param CacheItemPoolInterface|null $cache [optional] A PSR-6 compatible cache implementation.
+     */
+    public function __construct(
+        ?callable $httpHandler = null,
+        ?CacheItemPoolInterface $cache = null
+    ) {
+        $this->httpHandler = $httpHandler
+            ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+        $this->cache = $cache ?: new MemoryCacheItemPool();
+    }
+
+    /**
+     * Verifies an id token and returns the authenticated apiLoginTicket.
+     * Throws an exception if the id token is not valid.
+     * The audience parameter can be used to control which id tokens are
+     * accepted.  By default, the id token must have been issued to this OAuth2 client.
+     *
+     * @param string $token The JSON Web Token to be verified.
+     * @param array<mixed> $options [optional] {
+     *     Configuration options.
+     *     @type string $audience The indended recipient of the token.
+     *     @type string $issuer The intended issuer of the token.
+     *     @type string $cacheKey The cache key of the cached certs. Defaults to
+     *        the sha1 of $certsLocation if provided, otherwise is set to
+     *        "federated_signon_certs_v3".
+     *     @type string $certsLocation The location (remote or local) from which
+     *        to retrieve certificates, if not cached. This value should only be
+     *        provided in limited circumstances in which you are sure of the
+     *        behavior.
+     *     @type bool $throwException Whether the function should throw an
+     *        exception if the verification fails. This is useful for
+     *        determining the reason verification failed.
+     * }
+     * @return array<mixed>|false the token payload, if successful, or false if not.
+     * @throws InvalidArgumentException If certs could not be retrieved from a local file.
+     * @throws InvalidArgumentException If received certs are in an invalid format.
+     * @throws InvalidArgumentException If the cert alg is not supported.
+     * @throws RuntimeException If certs could not be retrieved from a remote location.
+     * @throws UnexpectedValueException If the token issuer does not match.
+     * @throws UnexpectedValueException If the token audience does not match.
+     */
+    public function verify($token, array $options = [])
+    {
+        $audience = $options['audience'] ?? null;
+        $issuer = $options['issuer'] ?? null;
+        $certsLocation = $options['certsLocation'] ?? self::FEDERATED_SIGNON_CERT_URL;
+        $cacheKey = $options['cacheKey'] ?? $this->getCacheKeyFromCertLocation($certsLocation);
+        $throwException = $options['throwException'] ?? false; // for backwards compatibility
+
+        // Check signature against each available cert.
+        $certs = $this->getCerts($certsLocation, $cacheKey, $options);
+        $alg = $this->determineAlg($certs);
+        if (!in_array($alg, ['RS256', 'ES256'])) {
+            throw new InvalidArgumentException(
+                'unrecognized "alg" in certs, expected ES256 or RS256'
+            );
+        }
+        try {
+            if ($alg == 'RS256') {
+                return $this->verifyRs256($token, $certs, $audience, $issuer);
+            }
+            return $this->verifyEs256($token, $certs, $audience, $issuer);
+        } catch (ExpiredException $e) {  // firebase/php-jwt 5+
+        } catch (SignatureInvalidException $e) {  // firebase/php-jwt 5+
+        } catch (InvalidTokenException $e) { // simplejwt
+        } catch (InvalidArgumentException $e) {
+        } catch (UnexpectedValueException $e) {
+        }
+
+        if ($throwException) {
+            throw $e;
+        }
+
+        return false;
+    }
+
+    /**
+     * Identifies the expected algorithm to verify by looking at the "alg" key
+     * of the provided certs.
+     *
+     * @param array<mixed> $certs Certificate array according to the JWK spec (see
+     *                     https://tools.ietf.org/html/rfc7517).
+     * @return string The expected algorithm, such as "ES256" or "RS256".
+     */
+    private function determineAlg(array $certs)
+    {
+        $alg = null;
+        foreach ($certs as $cert) {
+            if (empty($cert['alg'])) {
+                throw new InvalidArgumentException(
+                    'certs expects "alg" to be set'
+                );
+            }
+            $alg = $alg ?: $cert['alg'];
+
+            if ($alg != $cert['alg']) {
+                throw new InvalidArgumentException(
+                    'More than one alg detected in certs'
+                );
+            }
+        }
+        return $alg;
+    }
+
+    /**
+     * Verifies an ES256-signed JWT.
+     *
+     * @param string $token The JSON Web Token to be verified.
+     * @param array<mixed> $certs Certificate array according to the JWK spec (see
+     *        https://tools.ietf.org/html/rfc7517).
+     * @param string|null $audience If set, returns false if the provided
+     *        audience does not match the "aud" claim on the JWT.
+     * @param string|null $issuer If set, returns false if the provided
+     *        issuer does not match the "iss" claim on the JWT.
+     * @return array<mixed> the token payload, if successful, or false if not.
+     */
+    private function verifyEs256($token, array $certs, $audience = null, $issuer = null)
+    {
+        $this->checkSimpleJwt();
+
+        $jwkset = new KeySet();
+        foreach ($certs as $cert) {
+            $jwkset->add(KeyFactory::create($cert, 'php'));
+        }
+
+        // Validate the signature using the key set and ES256 algorithm.
+        $jwt = $this->callSimpleJwtDecode([$token, $jwkset, 'ES256']);
+        $payload = $jwt->getClaims();
+
+        if ($audience) {
+            if (!isset($payload['aud']) || $payload['aud'] != $audience) {
+                throw new UnexpectedValueException('Audience does not match');
+            }
+        }
+
+        // @see https://cloud.google.com/iap/docs/signed-headers-howto#verifying_the_jwt_payload
+        $issuer = $issuer ?: self::IAP_ISSUER;
+        if (!isset($payload['iss']) || $payload['iss'] !== $issuer) {
+            throw new UnexpectedValueException('Issuer does not match');
+        }
+
+        return $payload;
+    }
+
+    /**
+     * Verifies an RS256-signed JWT.
+     *
+     * @param string $token The JSON Web Token to be verified.
+     * @param array<mixed> $certs Certificate array according to the JWK spec (see
+     *        https://tools.ietf.org/html/rfc7517).
+     * @param string|null $audience If set, returns false if the provided
+     *        audience does not match the "aud" claim on the JWT.
+     * @param string|null $issuer If set, returns false if the provided
+     *        issuer does not match the "iss" claim on the JWT.
+     * @return array<mixed> the token payload, if successful, or false if not.
+     */
+    private function verifyRs256($token, array $certs, $audience = null, $issuer = null)
+    {
+        $this->checkAndInitializePhpsec();
+        $keys = [];
+        foreach ($certs as $cert) {
+            if (empty($cert['kid'])) {
+                throw new InvalidArgumentException(
+                    'certs expects "kid" to be set'
+                );
+            }
+            if (empty($cert['n']) || empty($cert['e'])) {
+                throw new InvalidArgumentException(
+                    'RSA certs expects "n" and "e" to be set'
+                );
+            }
+            $publicKey = $this->loadPhpsecPublicKey($cert['n'], $cert['e']);
+
+            // create an array of key IDs to certs for the JWT library
+            $keys[$cert['kid']] = new Key($publicKey, 'RS256');
+        }
+
+        $payload = $this->callJwtStatic('decode', [
+            $token,
+            $keys,
+        ]);
+
+        if ($audience) {
+            if (!property_exists($payload, 'aud') || $payload->aud != $audience) {
+                throw new UnexpectedValueException('Audience does not match');
+            }
+        }
+
+        // support HTTP and HTTPS issuers
+        // @see https://developers.google.com/identity/sign-in/web/backend-auth
+        $issuers = $issuer ? [$issuer] : [self::OAUTH2_ISSUER, self::OAUTH2_ISSUER_HTTPS];
+        if (!isset($payload->iss) || !in_array($payload->iss, $issuers)) {
+            throw new UnexpectedValueException('Issuer does not match');
+        }
+
+        return (array) $payload;
+    }
+
+    /**
+     * Revoke an OAuth2 access token or refresh token. This method will revoke the current access
+     * token, if a token isn't provided.
+     *
+     * @param string|array<mixed> $token The token (access token or a refresh token) that should be revoked.
+     * @param array<mixed> $options [optional] Configuration options.
+     * @return bool Returns True if the revocation was successful, otherwise False.
+     */
+    public function revoke($token, array $options = [])
+    {
+        if (is_array($token)) {
+            if (isset($token['refresh_token'])) {
+                $token = $token['refresh_token'];
+            } else {
+                $token = $token['access_token'];
+            }
+        }
+
+        $body = Utils::streamFor(http_build_query(['token' => $token]));
+        $request = new Request('POST', self::OAUTH2_REVOKE_URI, [
+            'Cache-Control' => 'no-store',
+            'Content-Type'  => 'application/x-www-form-urlencoded',
+        ], $body);
+
+        $httpHandler = $this->httpHandler;
+
+        $response = $httpHandler($request, $options);
+
+        return $response->getStatusCode() == 200;
+    }
+
+    /**
+     * Gets federated sign-on certificates to use for verifying identity tokens.
+     * Returns certs as array structure, where keys are key ids, and values
+     * are PEM encoded certificates.
+     *
+     * @param string $location The location from which to retrieve certs.
+     * @param string $cacheKey The key under which to cache the retrieved certs.
+     * @param array<mixed> $options [optional] Configuration options.
+     * @return array<mixed>
+     * @throws InvalidArgumentException If received certs are in an invalid format.
+     */
+    private function getCerts($location, $cacheKey, array $options = [])
+    {
+        $cacheItem = $this->cache->getItem($cacheKey);
+        $certs = $cacheItem ? $cacheItem->get() : null;
+
+        $expireTime = null;
+        if (!$certs) {
+            list($certs, $expireTime) = $this->retrieveCertsFromLocation($location, $options);
+        }
+
+        if (!isset($certs['keys'])) {
+            if ($location !== self::IAP_CERT_URL) {
+                throw new InvalidArgumentException(
+                    'federated sign-on certs expects "keys" to be set'
+                );
+            }
+            throw new InvalidArgumentException(
+                'certs expects "keys" to be set'
+            );
+        }
+
+        // Push caching off until after verifying certs are in a valid format.
+        // Don't want to cache bad data.
+        if ($expireTime) {
+            $cacheItem->expiresAt(new DateTime($expireTime));
+            $cacheItem->set($certs);
+            $this->cache->save($cacheItem);
+        }
+
+        return $certs['keys'];
+    }
+
+    /**
+     * Retrieve and cache a certificates file.
+     *
+     * @param string $url location
+     * @param array<mixed> $options [optional] Configuration options.
+     * @return array{array<mixed>, string}
+     * @throws InvalidArgumentException If certs could not be retrieved from a local file.
+     * @throws RuntimeException If certs could not be retrieved from a remote location.
+     */
+    private function retrieveCertsFromLocation($url, array $options = [])
+    {
+        // If we're retrieving a local file, just grab it.
+        $expireTime = '+1 hour';
+        if (strpos($url, 'http') !== 0) {
+            if (!file_exists($url)) {
+                throw new InvalidArgumentException(sprintf(
+                    'Failed to retrieve verification certificates from path: %s.',
+                    $url
+                ));
+            }
+
+            return [
+                json_decode((string) file_get_contents($url), true),
+                $expireTime
+            ];
+        }
+
+        $httpHandler = $this->httpHandler;
+        $response = $httpHandler(new Request('GET', $url), $options);
+
+        if ($response->getStatusCode() == 200) {
+            if ($cacheControl = $response->getHeaderLine('Cache-Control')) {
+                array_map(function ($value) use (&$expireTime) {
+                    list($key, $value) = explode('=', $value) + [null, null];
+                    if (trim($key) == 'max-age') {
+                        $expireTime = '+' . $value . ' seconds';
+                    }
+                }, explode(',', $cacheControl));
+            }
+            return [
+                json_decode((string) $response->getBody(), true),
+                $expireTime
+            ];
+        }
+
+        throw new RuntimeException(sprintf(
+            'Failed to retrieve verification certificates: "%s".',
+            $response->getBody()->getContents()
+        ), $response->getStatusCode());
+    }
+
+    /**
+     * @return void
+     */
+    private function checkAndInitializePhpsec()
+    {
+        if (!class_exists(RSA::class)) {
+            throw new RuntimeException('Please require phpseclib/phpseclib v3 to use this utility.');
+        }
+    }
+
+    /**
+     * @return string
+     * @throws TypeError If the key cannot be initialized to a string.
+     */
+    private function loadPhpsecPublicKey(string $modulus, string $exponent): string
+    {
+        $key = PublicKeyLoader::load([
+            'n' => new BigInteger($this->callJwtStatic('urlsafeB64Decode', [
+                $modulus,
+            ]), 256),
+            'e' => new BigInteger($this->callJwtStatic('urlsafeB64Decode', [
+                $exponent
+            ]), 256),
+        ]);
+        $formattedPublicKey = $key->toString('PKCS8');
+        if (!is_string($formattedPublicKey)) {
+            throw new TypeError('Failed to initialize the key');
+        }
+        return $formattedPublicKey;
+    }
+
+    /**
+     * @return void
+     */
+    private function checkSimpleJwt()
+    {
+        // @codeCoverageIgnoreStart
+        if (!class_exists(SimpleJwt::class)) {
+            throw new RuntimeException('Please require kelvinmo/simplejwt ^0.2 to use this utility.');
+        }
+        // @codeCoverageIgnoreEnd
+    }
+
+    /**
+     * Provide a hook to mock calls to the JWT static methods.
+     *
+     * @param string $method
+     * @param array<mixed> $args
+     * @return mixed
+     */
+    protected function callJwtStatic($method, array $args = [])
+    {
+        return call_user_func_array([JWT::class, $method], $args); // @phpstan-ignore-line
+    }
+
+    /**
+     * Provide a hook to mock calls to the JWT static methods.
+     *
+     * @param array<mixed> $args
+     * @return mixed
+     */
+    protected function callSimpleJwtDecode(array $args = [])
+    {
+        return call_user_func_array([SimpleJwt::class, 'decode'], $args);
+    }
+
+    /**
+     * Generate a cache key based on the cert location using sha1 with the
+     * exception of using "federated_signon_certs_v3" to preserve BC.
+     *
+     * @param string $certsLocation
+     * @return string
+     */
+    private function getCacheKeyFromCertLocation($certsLocation)
+    {
+        $key = $certsLocation === self::FEDERATED_SIGNON_CERT_URL
+            ? 'federated_signon_certs_v3'
+            : sha1($certsLocation);
+
+        return 'google_auth_certs_cache|' . $key;
+    }
+}
Index: vendor/google/auth/src/ApplicationDefaultCredentials.php
===================================================================
--- vendor/google/auth/src/ApplicationDefaultCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/ApplicationDefaultCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,355 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+use DomainException;
+use Google\Auth\Credentials\AppIdentityCredentials;
+use Google\Auth\Credentials\GCECredentials;
+use Google\Auth\Credentials\ServiceAccountCredentials;
+use Google\Auth\Credentials\UserRefreshCredentials;
+use Google\Auth\HttpHandler\HttpClientCache;
+use Google\Auth\HttpHandler\HttpHandlerFactory;
+use Google\Auth\Middleware\AuthTokenMiddleware;
+use Google\Auth\Middleware\ProxyAuthTokenMiddleware;
+use Google\Auth\Subscriber\AuthTokenSubscriber;
+use GuzzleHttp\Client;
+use InvalidArgumentException;
+use Psr\Cache\CacheItemPoolInterface;
+
+/**
+ * ApplicationDefaultCredentials obtains the default credentials for
+ * authorizing a request to a Google service.
+ *
+ * Application Default Credentials are described here:
+ * https://developers.google.com/accounts/docs/application-default-credentials
+ *
+ * This class implements the search for the application default credentials as
+ * described in the link.
+ *
+ * It provides three factory methods:
+ * - #get returns the computed credentials object
+ * - #getSubscriber returns an AuthTokenSubscriber built from the credentials object
+ * - #getMiddleware returns an AuthTokenMiddleware built from the credentials object
+ *
+ * This allows it to be used as follows with GuzzleHttp\Client:
+ *
+ * ```
+ * use Google\Auth\ApplicationDefaultCredentials;
+ * use GuzzleHttp\Client;
+ * use GuzzleHttp\HandlerStack;
+ *
+ * $middleware = ApplicationDefaultCredentials::getMiddleware(
+ *     'https://www.googleapis.com/auth/taskqueue'
+ * );
+ * $stack = HandlerStack::create();
+ * $stack->push($middleware);
+ *
+ * $client = new Client([
+ *     'handler' => $stack,
+ *     'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
+ *     'auth' => 'google_auth' // authorize all requests
+ * ]);
+ *
+ * $res = $client->get('myproject/taskqueues/myqueue');
+ * ```
+ */
+class ApplicationDefaultCredentials
+{
+    /**
+     * @deprecated
+     *
+     * Obtains an AuthTokenSubscriber that uses the default FetchAuthTokenInterface
+     * implementation to use in this environment.
+     *
+     * If supplied, $scope is used to in creating the credentials instance if
+     * this does not fallback to the compute engine defaults.
+     *
+     * @param string|string[] $scope the scope of the access request, expressed
+     *        either as an Array or as a space-delimited String.
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @param array<mixed>|null $cacheConfig configuration for the cache when it's present
+     * @param CacheItemPoolInterface|null $cache A cache implementation, may be
+     *        provided if you have one already available for use.
+     * @return AuthTokenSubscriber
+     * @throws DomainException if no implementation can be obtained.
+     */
+    public static function getSubscriber(// @phpstan-ignore-line
+        $scope = null,
+        ?callable $httpHandler = null,
+        ?array $cacheConfig = null,
+        ?CacheItemPoolInterface $cache = null
+    ) {
+        $creds = self::getCredentials($scope, $httpHandler, $cacheConfig, $cache);
+
+        /** @phpstan-ignore-next-line */
+        return new AuthTokenSubscriber($creds, $httpHandler);
+    }
+
+    /**
+     * Obtains an AuthTokenMiddleware that uses the default FetchAuthTokenInterface
+     * implementation to use in this environment.
+     *
+     * If supplied, $scope is used to in creating the credentials instance if
+     * this does not fallback to the compute engine defaults.
+     *
+     * @param string|string[] $scope the scope of the access request, expressed
+     *        either as an Array or as a space-delimited String.
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @param array<mixed>|null $cacheConfig configuration for the cache when it's present
+     * @param CacheItemPoolInterface|null $cache A cache implementation, may be
+     *        provided if you have one already available for use.
+     * @param string $quotaProject specifies a project to bill for access
+     *   charges associated with the request.
+     * @return AuthTokenMiddleware
+     * @throws DomainException if no implementation can be obtained.
+     */
+    public static function getMiddleware(
+        $scope = null,
+        ?callable $httpHandler = null,
+        ?array $cacheConfig = null,
+        ?CacheItemPoolInterface $cache = null,
+        $quotaProject = null
+    ) {
+        $creds = self::getCredentials($scope, $httpHandler, $cacheConfig, $cache, $quotaProject);
+
+        return new AuthTokenMiddleware($creds, $httpHandler);
+    }
+
+    /**
+     * Obtains the default FetchAuthTokenInterface implementation to use
+     * in this environment.
+     *
+     * @param string|string[] $scope the scope of the access request, expressed
+     *        either as an Array or as a space-delimited String.
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @param array<mixed>|null $cacheConfig configuration for the cache when it's present
+     * @param CacheItemPoolInterface|null $cache A cache implementation, may be
+     *        provided if you have one already available for use.
+     * @param string|null $quotaProject specifies a project to bill for access
+     *   charges associated with the request.
+     * @param string|string[]|null $defaultScope The default scope to use if no
+     *   user-defined scopes exist, expressed either as an Array or as a
+     *   space-delimited string.
+     * @param string|null $universeDomain Specifies a universe domain to use for the
+     *   calling client library
+     *
+     * @return FetchAuthTokenInterface
+     * @throws DomainException if no implementation can be obtained.
+     */
+    public static function getCredentials(
+        $scope = null,
+        ?callable $httpHandler = null,
+        ?array $cacheConfig = null,
+        ?CacheItemPoolInterface $cache = null,
+        $quotaProject = null,
+        $defaultScope = null,
+        ?string $universeDomain = null
+    ) {
+        $creds = null;
+        $jsonKey = CredentialsLoader::fromEnv()
+            ?: CredentialsLoader::fromWellKnownFile();
+        $anyScope = $scope ?: $defaultScope;
+
+        if (!$httpHandler) {
+            if (!($client = HttpClientCache::getHttpClient())) {
+                $client = new Client();
+                HttpClientCache::setHttpClient($client);
+            }
+
+            $httpHandler = HttpHandlerFactory::build($client);
+        }
+
+        if (is_null($quotaProject)) {
+            // if a quota project isn't specified, try to get one from the env var
+            $quotaProject = CredentialsLoader::quotaProjectFromEnv();
+        }
+
+        if (!is_null($jsonKey)) {
+            if ($quotaProject) {
+                $jsonKey['quota_project_id'] = $quotaProject;
+            }
+            if ($universeDomain) {
+                $jsonKey['universe_domain'] = $universeDomain;
+            }
+            $creds = CredentialsLoader::makeCredentials(
+                $scope,
+                $jsonKey,
+                $defaultScope
+            );
+        } elseif (AppIdentityCredentials::onAppEngine() && !GCECredentials::onAppEngineFlexible()) {
+            $creds = new AppIdentityCredentials($anyScope);
+        } elseif (self::onGce($httpHandler, $cacheConfig, $cache)) {
+            $creds = new GCECredentials(null, $anyScope, null, $quotaProject, null, $universeDomain);
+            $creds->setIsOnGce(true); // save the credentials a trip to the metadata server
+        }
+
+        if (is_null($creds)) {
+            throw new DomainException(self::notFound());
+        }
+        if (!is_null($cache)) {
+            $creds = new FetchAuthTokenCache($creds, $cacheConfig, $cache);
+        }
+        return $creds;
+    }
+
+    /**
+     * Obtains an AuthTokenMiddleware which will fetch an ID token to use in the
+     * Authorization header. The middleware is configured with the default
+     * FetchAuthTokenInterface implementation to use in this environment.
+     *
+     * If supplied, $targetAudience is used to set the "aud" on the resulting
+     * ID token.
+     *
+     * @param string $targetAudience The audience for the ID token.
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @param array<mixed>|null $cacheConfig configuration for the cache when it's present
+     * @param CacheItemPoolInterface|null $cache A cache implementation, may be
+     *        provided if you have one already available for use.
+     * @return AuthTokenMiddleware
+     * @throws DomainException if no implementation can be obtained.
+     */
+    public static function getIdTokenMiddleware(
+        $targetAudience,
+        ?callable $httpHandler = null,
+        ?array $cacheConfig = null,
+        ?CacheItemPoolInterface $cache = null
+    ) {
+        $creds = self::getIdTokenCredentials($targetAudience, $httpHandler, $cacheConfig, $cache);
+
+        return new AuthTokenMiddleware($creds, $httpHandler);
+    }
+
+    /**
+     * Obtains an ProxyAuthTokenMiddleware which will fetch an ID token to use in the
+     * Authorization header. The middleware is configured with the default
+     * FetchAuthTokenInterface implementation to use in this environment.
+     *
+     * If supplied, $targetAudience is used to set the "aud" on the resulting
+     * ID token.
+     *
+     * @param string $targetAudience The audience for the ID token.
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @param array<mixed>|null $cacheConfig configuration for the cache when it's present
+     * @param CacheItemPoolInterface|null $cache A cache implementation, may be
+     *        provided if you have one already available for use.
+     * @return ProxyAuthTokenMiddleware
+     * @throws DomainException if no implementation can be obtained.
+     */
+    public static function getProxyIdTokenMiddleware(
+        $targetAudience,
+        ?callable $httpHandler = null,
+        ?array $cacheConfig = null,
+        ?CacheItemPoolInterface $cache = null
+    ) {
+        $creds = self::getIdTokenCredentials($targetAudience, $httpHandler, $cacheConfig, $cache);
+
+        return new ProxyAuthTokenMiddleware($creds, $httpHandler);
+    }
+
+    /**
+     * Obtains the default FetchAuthTokenInterface implementation to use
+     * in this environment, configured with a $targetAudience for fetching an ID
+     * token.
+     *
+     * @param string $targetAudience The audience for the ID token.
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @param array<mixed>|null $cacheConfig configuration for the cache when it's present
+     * @param CacheItemPoolInterface|null $cache A cache implementation, may be
+     *        provided if you have one already available for use.
+     * @return FetchAuthTokenInterface
+     * @throws DomainException if no implementation can be obtained.
+     * @throws InvalidArgumentException if JSON "type" key is invalid
+     */
+    public static function getIdTokenCredentials(
+        $targetAudience,
+        ?callable $httpHandler = null,
+        ?array $cacheConfig = null,
+        ?CacheItemPoolInterface $cache = null
+    ) {
+        $creds = null;
+        $jsonKey = CredentialsLoader::fromEnv()
+            ?: CredentialsLoader::fromWellKnownFile();
+
+        if (!$httpHandler) {
+            if (!($client = HttpClientCache::getHttpClient())) {
+                $client = new Client();
+                HttpClientCache::setHttpClient($client);
+            }
+
+            $httpHandler = HttpHandlerFactory::build($client);
+        }
+
+        if (!is_null($jsonKey)) {
+            if (!array_key_exists('type', $jsonKey)) {
+                throw new \InvalidArgumentException('json key is missing the type field');
+            }
+
+            if ($jsonKey['type'] == 'authorized_user') {
+                $creds = new UserRefreshCredentials(null, $jsonKey, $targetAudience);
+            } elseif ($jsonKey['type'] == 'service_account') {
+                $creds = new ServiceAccountCredentials(null, $jsonKey, null, $targetAudience);
+            } else {
+                throw new InvalidArgumentException('invalid value in the type field');
+            }
+        } elseif (self::onGce($httpHandler, $cacheConfig, $cache)) {
+            $creds = new GCECredentials(null, null, $targetAudience);
+            $creds->setIsOnGce(true); // save the credentials a trip to the metadata server
+        }
+
+        if (is_null($creds)) {
+            throw new DomainException(self::notFound());
+        }
+        if (!is_null($cache)) {
+            $creds = new FetchAuthTokenCache($creds, $cacheConfig, $cache);
+        }
+        return $creds;
+    }
+
+    /**
+     * @return string
+     */
+    private static function notFound()
+    {
+        $msg = 'Your default credentials were not found. To set up ';
+        $msg .= 'Application Default Credentials, see ';
+        $msg .= 'https://cloud.google.com/docs/authentication/external/set-up-adc';
+
+        return $msg;
+    }
+
+    /**
+     * @param callable|null $httpHandler
+     * @param array<mixed>|null $cacheConfig
+     * @param CacheItemPoolInterface|null $cache
+     * @return bool
+     */
+    private static function onGce(
+        ?callable $httpHandler = null,
+        ?array $cacheConfig = null,
+        ?CacheItemPoolInterface $cache = null
+    ) {
+        $gceCacheConfig = [];
+        foreach (['lifetime', 'prefix'] as $key) {
+            if (isset($cacheConfig['gce_' . $key])) {
+                $gceCacheConfig[$key] = $cacheConfig['gce_' . $key];
+            }
+        }
+
+        return (new GCECache($gceCacheConfig, $cache))->onGce($httpHandler);
+    }
+}
Index: vendor/google/auth/src/Cache/FileSystemCacheItemPool.php
===================================================================
--- vendor/google/auth/src/Cache/FileSystemCacheItemPool.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Cache/FileSystemCacheItemPool.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,230 @@
+<?php
+/**
+ * Copyright 2024 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Cache;
+
+use ErrorException;
+use Psr\Cache\CacheItemInterface;
+use Psr\Cache\CacheItemPoolInterface;
+
+class FileSystemCacheItemPool implements CacheItemPoolInterface
+{
+    /**
+     * @var string
+     */
+    private string $cachePath;
+
+    /**
+     * @var array<CacheItemInterface>
+     */
+    private array $buffer = [];
+
+    /**
+     * Creates a FileSystemCacheItemPool cache that stores values in local storage
+     *
+     * @param string $path The string representation of the path where the cache will store the serialized objects.
+     */
+    public function __construct(string $path)
+    {
+        $this->cachePath = $path;
+
+        if (is_dir($this->cachePath)) {
+            return;
+        }
+
+        if (!mkdir($this->cachePath)) {
+            throw new ErrorException("Cache folder couldn't be created.");
+        }
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getItem(string $key): CacheItemInterface
+    {
+        if (!$this->validKey($key)) {
+            throw new InvalidArgumentException("The key '$key' is not valid. The key should follow the pattern |^[a-zA-Z0-9_\.! ]+$|");
+        }
+
+        $item = new TypedItem($key);
+
+        $itemPath = $this->cacheFilePath($key);
+
+        if (!file_exists($itemPath)) {
+            return $item;
+        }
+
+        $serializedItem = file_get_contents($itemPath);
+
+        if ($serializedItem === false) {
+            return $item;
+        }
+
+        $item->set(unserialize($serializedItem));
+
+        return $item;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return iterable<CacheItemInterface> An iterable object containing all the
+     *   A traversable collection of Cache Items keyed by the cache keys of
+     *   each item. A Cache item will be returned for each key, even if that
+     *   key is not found. However, if no keys are specified then an empty
+     *   traversable MUST be returned instead.
+     */
+    public function getItems(array $keys = []): iterable
+    {
+        $result = [];
+
+        foreach ($keys as $key) {
+            $result[$key] = $this->getItem($key);
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function save(CacheItemInterface $item): bool
+    {
+        if (!$this->validKey($item->getKey())) {
+            return false;
+        }
+
+        $itemPath = $this->cacheFilePath($item->getKey());
+        $serializedItem = serialize($item->get());
+
+        $result = file_put_contents($itemPath, $serializedItem);
+
+        // 0 bytes write is considered a successful operation
+        if ($result === false) {
+            return false;
+        }
+
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function hasItem(string $key): bool
+    {
+        return $this->getItem($key)->isHit();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function clear(): bool
+    {
+        $this->buffer = [];
+
+        if (!is_dir($this->cachePath)) {
+            return false;
+        }
+
+        $files = scandir($this->cachePath);
+        if (!$files) {
+            return false;
+        }
+
+        foreach ($files as $fileName) {
+            if ($fileName === '.' || $fileName === '..') {
+                continue;
+            }
+
+            if (!unlink($this->cachePath . '/' . $fileName)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteItem(string $key): bool
+    {
+        if (!$this->validKey($key)) {
+            throw new InvalidArgumentException("The key '$key' is not valid. The key should follow the pattern |^[a-zA-Z0-9_\.! ]+$|");
+        }
+
+        $itemPath = $this->cacheFilePath($key);
+
+        if (!file_exists($itemPath)) {
+            return true;
+        }
+
+        return unlink($itemPath);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteItems(array $keys): bool
+    {
+        $result = true;
+
+        foreach ($keys as $key) {
+            if (!$this->deleteItem($key)) {
+                $result = false;
+            }
+        }
+
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function saveDeferred(CacheItemInterface $item): bool
+    {
+        array_push($this->buffer, $item);
+
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function commit(): bool
+    {
+        $result = true;
+
+        foreach ($this->buffer as $item) {
+            if (!$this->save($item)) {
+                $result = false;
+            }
+        }
+
+        return $result;
+    }
+
+    private function cacheFilePath(string $key): string
+    {
+        return $this->cachePath . '/' . $key;
+    }
+
+    private function validKey(string $key): bool
+    {
+        return (bool) preg_match('|^[a-zA-Z0-9_\.]+$|', $key);
+    }
+}
Index: vendor/google/auth/src/Cache/InvalidArgumentException.php
===================================================================
--- vendor/google/auth/src/Cache/InvalidArgumentException.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Cache/InvalidArgumentException.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,24 @@
+<?php
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Cache;
+
+use Psr\Cache\InvalidArgumentException as PsrInvalidArgumentException;
+
+class InvalidArgumentException extends \InvalidArgumentException implements PsrInvalidArgumentException
+{
+}
Index: vendor/google/auth/src/Cache/Item.php
===================================================================
--- vendor/google/auth/src/Cache/Item.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Cache/Item.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,175 @@
+<?php
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Cache;
+
+use DateTime;
+use DateTimeInterface;
+use DateTimeZone;
+use Psr\Cache\CacheItemInterface;
+use TypeError;
+
+/**
+ * A cache item.
+ *
+ * This class will be used by MemoryCacheItemPool and SysVCacheItemPool
+ * on PHP 7.4 and below. It is compatible with psr/cache 1.0 and 2.0 (PSR-6).
+ * @deprecated
+ * @see TypedItem for compatiblity with psr/cache 3.0.
+ */
+final class Item implements CacheItemInterface
+{
+    /**
+     * @var string
+     */
+    private $key;
+
+    /**
+     * @var mixed
+     */
+    private $value;
+
+    /**
+     * @var DateTimeInterface|null
+     */
+    private $expiration;
+
+    /**
+     * @var bool
+     */
+    private $isHit = false;
+
+    /**
+     * @param string $key
+     */
+    public function __construct($key)
+    {
+        $this->key = $key;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getKey()
+    {
+        return $this->key;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function get()
+    {
+        return $this->isHit() ? $this->value : null;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isHit()
+    {
+        if (!$this->isHit) {
+            return false;
+        }
+
+        if ($this->expiration === null) {
+            return true;
+        }
+
+        return $this->currentTime()->getTimestamp() < $this->expiration->getTimestamp();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function set($value)
+    {
+        $this->isHit = true;
+        $this->value = $value;
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function expiresAt($expiration)
+    {
+        if ($this->isValidExpiration($expiration)) {
+            $this->expiration = $expiration;
+
+            return $this;
+        }
+
+        $error = sprintf(
+            'Argument 1 passed to %s::expiresAt() must implement interface DateTimeInterface, %s given',
+            get_class($this),
+            gettype($expiration)
+        );
+
+        throw new TypeError($error);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function expiresAfter($time)
+    {
+        if (is_int($time)) {
+            $this->expiration = $this->currentTime()->add(new \DateInterval("PT{$time}S"));
+        } elseif ($time instanceof \DateInterval) {
+            $this->expiration = $this->currentTime()->add($time);
+        } elseif ($time === null) {
+            $this->expiration = $time;
+        } else {
+            $message = 'Argument 1 passed to %s::expiresAfter() must be an ' .
+                       'instance of DateInterval or of the type integer, %s given';
+            $error = sprintf($message, get_class($this), gettype($time));
+
+            throw new TypeError($error);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Determines if an expiration is valid based on the rules defined by PSR6.
+     *
+     * @param mixed $expiration
+     * @return bool
+     */
+    private function isValidExpiration($expiration)
+    {
+        if ($expiration === null) {
+            return true;
+        }
+
+        if ($expiration instanceof DateTimeInterface) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @return DateTime
+     */
+    protected function currentTime()
+    {
+        return new DateTime('now', new DateTimeZone('UTC'));
+    }
+}
Index: vendor/google/auth/src/Cache/MemoryCacheItemPool.php
===================================================================
--- vendor/google/auth/src/Cache/MemoryCacheItemPool.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Cache/MemoryCacheItemPool.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,182 @@
+<?php
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Cache;
+
+use Psr\Cache\CacheItemInterface;
+use Psr\Cache\CacheItemPoolInterface;
+
+/**
+ * Simple in-memory cache implementation.
+ */
+final class MemoryCacheItemPool implements CacheItemPoolInterface
+{
+    /**
+     * @var CacheItemInterface[]
+     */
+    private $items;
+
+    /**
+     * @var CacheItemInterface[]
+     */
+    private $deferredItems;
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return CacheItemInterface The corresponding Cache Item.
+     */
+    public function getItem($key): CacheItemInterface
+    {
+        return current($this->getItems([$key]));  // @phpstan-ignore-line
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return iterable<CacheItemInterface>
+     *   A traversable collection of Cache Items keyed by the cache keys of
+     *   each item. A Cache item will be returned for each key, even if that
+     *   key is not found. However, if no keys are specified then an empty
+     *   traversable MUST be returned instead.
+     */
+    public function getItems(array $keys = []): iterable
+    {
+        $items = [];
+        foreach ($keys as $key) {
+            $items[$key] = $this->hasItem($key) ? clone $this->items[$key] : new TypedItem($key);
+        }
+
+        return $items;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     *   True if item exists in the cache, false otherwise.
+     */
+    public function hasItem($key): bool
+    {
+        $this->isValidKey($key);
+
+        return isset($this->items[$key]) && $this->items[$key]->isHit();
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     *   True if the pool was successfully cleared. False if there was an error.
+     */
+    public function clear(): bool
+    {
+        $this->items = [];
+        $this->deferredItems = [];
+
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     *   True if the item was successfully removed. False if there was an error.
+     */
+    public function deleteItem($key): bool
+    {
+        return $this->deleteItems([$key]);
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     *   True if the items were successfully removed. False if there was an error.
+     */
+    public function deleteItems(array $keys): bool
+    {
+        array_walk($keys, [$this, 'isValidKey']);
+
+        foreach ($keys as $key) {
+            unset($this->items[$key]);
+        }
+
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     *   True if the item was successfully persisted. False if there was an error.
+     */
+    public function save(CacheItemInterface $item): bool
+    {
+        $this->items[$item->getKey()] = $item;
+
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     *   False if the item could not be queued or if a commit was attempted and failed. True otherwise.
+     */
+    public function saveDeferred(CacheItemInterface $item): bool
+    {
+        $this->deferredItems[$item->getKey()] = $item;
+
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @return bool
+     *   True if all not-yet-saved items were successfully saved or there were none. False otherwise.
+     */
+    public function commit(): bool
+    {
+        foreach ($this->deferredItems as $item) {
+            $this->save($item);
+        }
+
+        $this->deferredItems = [];
+
+        return true;
+    }
+
+    /**
+     * Determines if the provided key is valid.
+     *
+     * @param string $key
+     * @return bool
+     * @throws InvalidArgumentException
+     */
+    private function isValidKey($key)
+    {
+        $invalidCharacters = '{}()/\\\\@:';
+
+        if (!is_string($key) || preg_match("#[$invalidCharacters]#", $key)) {
+            throw new InvalidArgumentException('The provided key is not valid: ' . var_export($key, true));
+        }
+
+        return true;
+    }
+}
Index: vendor/google/auth/src/Cache/SysVCacheItemPool.php
===================================================================
--- vendor/google/auth/src/Cache/SysVCacheItemPool.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Cache/SysVCacheItemPool.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,248 @@
+<?php
+/**
+ * Copyright 2018 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Google\Auth\Cache;
+
+use Psr\Cache\CacheItemInterface;
+use Psr\Cache\CacheItemPoolInterface;
+
+/**
+ * SystemV shared memory based CacheItemPool implementation.
+ *
+ * This CacheItemPool implementation can be used among multiple processes, but
+ * it doesn't provide any locking mechanism. If multiple processes write to
+ * this ItemPool, you have to avoid race condition manually in your code.
+ */
+class SysVCacheItemPool implements CacheItemPoolInterface
+{
+    const VAR_KEY = 1;
+
+    const DEFAULT_PROJ = 'A';
+
+    const DEFAULT_MEMSIZE = 10000;
+
+    const DEFAULT_PERM = 0600;
+
+    /**
+     * @var int
+     */
+    private $sysvKey;
+
+    /**
+     * @var CacheItemInterface[]
+     */
+    private $items;
+
+    /**
+     * @var CacheItemInterface[]
+     */
+    private $deferredItems;
+
+    /**
+     * @var array<mixed>
+     */
+    private $options;
+
+    /**
+     * @var bool
+     */
+    private $hasLoadedItems = false;
+
+    /**
+     * Create a SystemV shared memory based CacheItemPool.
+     *
+     * @param array<mixed> $options {
+     *     [optional] Configuration options.
+     *
+     *     @type int    $variableKey The variable key for getting the data from the shared memory. **Defaults to** 1.
+     *     @type string $proj        The project identifier for ftok. This needs to be a one character string.
+     *                               **Defaults to** 'A'.
+     *     @type int    $memsize     The memory size in bytes for shm_attach. **Defaults to** 10000.
+     *     @type int    $perm        The permission for shm_attach. **Defaults to** 0600.
+     * }
+     */
+    public function __construct($options = [])
+    {
+        if (! extension_loaded('sysvshm')) {
+            throw new \RuntimeException(
+                'sysvshm extension is required to use this ItemPool'
+            );
+        }
+        $this->options = $options + [
+            'variableKey' => self::VAR_KEY,
+            'proj' => self::DEFAULT_PROJ,
+            'memsize' => self::DEFAULT_MEMSIZE,
+            'perm' => self::DEFAULT_PERM
+        ];
+        $this->items = [];
+        $this->deferredItems = [];
+        $this->sysvKey = ftok(__FILE__, $this->options['proj']);
+    }
+
+    /**
+     * @param mixed $key
+     * @return CacheItemInterface
+     */
+    public function getItem($key): CacheItemInterface
+    {
+        $this->loadItems();
+        return current($this->getItems([$key])); // @phpstan-ignore-line
+    }
+
+    /**
+     * @param array<mixed> $keys
+     * @return iterable<CacheItemInterface>
+     */
+    public function getItems(array $keys = []): iterable
+    {
+        $this->loadItems();
+        $items = [];
+        foreach ($keys as $key) {
+            $items[$key] = $this->hasItem($key) ?
+                clone $this->items[$key] :
+                new TypedItem($key);
+        }
+        return $items;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function hasItem($key): bool
+    {
+        $this->loadItems();
+        return isset($this->items[$key]) && $this->items[$key]->isHit();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function clear(): bool
+    {
+        $this->items = [];
+        $this->deferredItems = [];
+        return $this->saveCurrentItems();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteItem($key): bool
+    {
+        return $this->deleteItems([$key]);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function deleteItems(array $keys): bool
+    {
+        if (!$this->hasLoadedItems) {
+            $this->loadItems();
+        }
+
+        foreach ($keys as $key) {
+            unset($this->items[$key]);
+        }
+        return $this->saveCurrentItems();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function save(CacheItemInterface $item): bool
+    {
+        if (!$this->hasLoadedItems) {
+            $this->loadItems();
+        }
+
+        $this->items[$item->getKey()] = $item;
+        return $this->saveCurrentItems();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function saveDeferred(CacheItemInterface $item): bool
+    {
+        $this->deferredItems[$item->getKey()] = $item;
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function commit(): bool
+    {
+        foreach ($this->deferredItems as $item) {
+            if ($this->save($item) === false) {
+                return false;
+            }
+        }
+        $this->deferredItems = [];
+        return true;
+    }
+
+    /**
+     * Save the current items.
+     *
+     * @return bool true when success, false upon failure
+     */
+    private function saveCurrentItems()
+    {
+        $shmid = shm_attach(
+            $this->sysvKey,
+            $this->options['memsize'],
+            $this->options['perm']
+        );
+        if ($shmid !== false) {
+            $ret = shm_put_var(
+                $shmid,
+                $this->options['variableKey'],
+                $this->items
+            );
+            shm_detach($shmid);
+            return $ret;
+        }
+        return false;
+    }
+
+    /**
+     * Load the items from the shared memory.
+     *
+     * @return bool true when success, false upon failure
+     */
+    private function loadItems()
+    {
+        $shmid = shm_attach(
+            $this->sysvKey,
+            $this->options['memsize'],
+            $this->options['perm']
+        );
+        if ($shmid !== false) {
+            $data = @shm_get_var($shmid, $this->options['variableKey']);
+            if (!empty($data)) {
+                $this->items = $data;
+            } else {
+                $this->items = [];
+            }
+            shm_detach($shmid);
+            $this->hasLoadedItems = true;
+            return true;
+        }
+        return false;
+    }
+}
Index: vendor/google/auth/src/Cache/TypedItem.php
===================================================================
--- vendor/google/auth/src/Cache/TypedItem.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Cache/TypedItem.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,170 @@
+<?php
+/*
+ * Copyright 2022 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Cache;
+
+use Psr\Cache\CacheItemInterface;
+
+/**
+ * A cache item.
+ *
+ * This class will be used by MemoryCacheItemPool and SysVCacheItemPool
+ * on PHP 8.0 and above. It is compatible with psr/cache 3.0 (PSR-6).
+ * @see Item for compatiblity with previous versions of PHP.
+ */
+final class TypedItem implements CacheItemInterface
+{
+    /**
+     * @var mixed
+     */
+    private mixed $value;
+
+    /**
+     * @var \DateTimeInterface|null
+     */
+    private ?\DateTimeInterface $expiration;
+
+    /**
+     * @var bool
+     */
+    private bool $isHit = false;
+
+    /**
+     * @param string $key
+     */
+    public function __construct(
+        private string $key
+    ) {
+        $this->key = $key;
+        $this->expiration = null;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getKey(): string
+    {
+        return $this->key;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function get(): mixed
+    {
+        return $this->isHit() ? $this->value : null;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isHit(): bool
+    {
+        if (!$this->isHit) {
+            return false;
+        }
+
+        if ($this->expiration === null) {
+            return true;
+        }
+
+        return $this->currentTime()->getTimestamp() < $this->expiration->getTimestamp();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function set(mixed $value): static
+    {
+        $this->isHit = true;
+        $this->value = $value;
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function expiresAt($expiration): static
+    {
+        if ($this->isValidExpiration($expiration)) {
+            $this->expiration = $expiration;
+
+            return $this;
+        }
+
+        $error = sprintf(
+            'Argument 1 passed to %s::expiresAt() must implement interface DateTimeInterface, %s given',
+            get_class($this),
+            gettype($expiration)
+        );
+
+        throw new \TypeError($error);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function expiresAfter($time): static
+    {
+        if (is_int($time)) {
+            $this->expiration = $this->currentTime()->add(new \DateInterval("PT{$time}S"));
+        } elseif ($time instanceof \DateInterval) {
+            $this->expiration = $this->currentTime()->add($time);
+        } elseif ($time === null) {
+            $this->expiration = $time;
+        } else {
+            $message = 'Argument 1 passed to %s::expiresAfter() must be an ' .
+                       'instance of DateInterval or of the type integer, %s given';
+            $error = sprintf($message, get_class($this), gettype($time));
+
+            throw new \TypeError($error);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Determines if an expiration is valid based on the rules defined by PSR6.
+     *
+     * @param mixed $expiration
+     * @return bool
+     */
+    private function isValidExpiration($expiration)
+    {
+        if ($expiration === null) {
+            return true;
+        }
+
+        // We test for two types here due to the fact the DateTimeInterface
+        // was not introduced until PHP 5.5. Checking for the DateTime type as
+        // well allows us to support 5.4.
+        if ($expiration instanceof \DateTimeInterface) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @return \DateTime
+     */
+    protected function currentTime()
+    {
+        return new \DateTime('now', new \DateTimeZone('UTC'));
+    }
+}
Index: vendor/google/auth/src/CacheTrait.php
===================================================================
--- vendor/google/auth/src/CacheTrait.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/CacheTrait.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,110 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+use Psr\Cache\CacheItemPoolInterface;
+
+trait CacheTrait
+{
+    /**
+     * @var int
+     */
+    private $maxKeyLength = 64;
+
+    /**
+     * @var array<mixed>
+     */
+    private $cacheConfig;
+
+    /**
+     * @var ?CacheItemPoolInterface
+     */
+    private $cache;
+
+    /**
+     * Gets the cached value if it is present in the cache when that is
+     * available.
+     *
+     * @param mixed $k
+     *
+     * @return mixed
+     */
+    private function getCachedValue($k)
+    {
+        if (is_null($this->cache)) {
+            return null;
+        }
+
+        $key = $this->getFullCacheKey($k);
+        if (is_null($key)) {
+            return null;
+        }
+
+        $cacheItem = $this->cache->getItem($key);
+        if ($cacheItem->isHit()) {
+            return $cacheItem->get();
+        }
+    }
+
+    /**
+     * Saves the value in the cache when that is available.
+     *
+     * @param mixed $k
+     * @param mixed $v
+     * @return mixed
+     */
+    private function setCachedValue($k, $v)
+    {
+        if (is_null($this->cache)) {
+            return null;
+        }
+
+        $key = $this->getFullCacheKey($k);
+        if (is_null($key)) {
+            return null;
+        }
+
+        $cacheItem = $this->cache->getItem($key);
+        $cacheItem->set($v);
+        $cacheItem->expiresAfter($this->cacheConfig['lifetime']);
+        return $this->cache->save($cacheItem);
+    }
+
+    /**
+     * @param null|string $key
+     * @return null|string
+     */
+    private function getFullCacheKey($key)
+    {
+        if (is_null($key)) {
+            return null;
+        }
+
+        $key = $this->cacheConfig['prefix'] . $key;
+
+        // ensure we do not have illegal characters
+        $key = preg_replace('|[^a-zA-Z0-9_\.!]|', '', $key);
+
+        // Hash keys if they exceed $maxKeyLength (defaults to 64)
+        if ($this->maxKeyLength && strlen($key) > $this->maxKeyLength) {
+            $key = substr(hash('sha256', $key), 0, $this->maxKeyLength);
+        }
+
+        return $key;
+    }
+}
Index: vendor/google/auth/src/CredentialSource/AwsNativeSource.php
===================================================================
--- vendor/google/auth/src/CredentialSource/AwsNativeSource.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/CredentialSource/AwsNativeSource.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,375 @@
+<?php
+/*
+ * Copyright 2023 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\CredentialSource;
+
+use Google\Auth\ExternalAccountCredentialSourceInterface;
+use Google\Auth\HttpHandler\HttpClientCache;
+use Google\Auth\HttpHandler\HttpHandlerFactory;
+use GuzzleHttp\Psr7\Request;
+
+/**
+ * Authenticates requests using AWS credentials.
+ */
+class AwsNativeSource implements ExternalAccountCredentialSourceInterface
+{
+    private const CRED_VERIFICATION_QUERY = 'Action=GetCallerIdentity&Version=2011-06-15';
+
+    private string $audience;
+    private string $regionalCredVerificationUrl;
+    private ?string $regionUrl;
+    private ?string $securityCredentialsUrl;
+    private ?string $imdsv2SessionTokenUrl;
+
+    /**
+     * @param string $audience The audience for the credential.
+     * @param string $regionalCredVerificationUrl The regional AWS GetCallerIdentity action URL used to determine the
+     *                                            AWS account ID and its roles. This is not called by this library, but
+     *                                            is sent in the subject token to be called by the STS token server.
+     * @param string|null $regionUrl This URL should be used to determine the current AWS region needed for the signed
+     *                               request construction.
+     * @param string|null $securityCredentialsUrl The AWS metadata server URL used to retrieve the access key, secret
+     *                                            key and security token needed to sign the GetCallerIdentity request.
+     * @param string|null $imdsv2SessionTokenUrl Presence of this URL enforces the auth libraries to fetch a Session
+     *                                           Token from AWS. This field is required for EC2 instances using IMDSv2.
+     */
+    public function __construct(
+        string $audience,
+        string $regionalCredVerificationUrl,
+        ?string $regionUrl = null,
+        ?string $securityCredentialsUrl = null,
+        ?string $imdsv2SessionTokenUrl = null
+    ) {
+        $this->audience = $audience;
+        $this->regionalCredVerificationUrl = $regionalCredVerificationUrl;
+        $this->regionUrl = $regionUrl;
+        $this->securityCredentialsUrl = $securityCredentialsUrl;
+        $this->imdsv2SessionTokenUrl = $imdsv2SessionTokenUrl;
+    }
+
+    public function fetchSubjectToken(?callable $httpHandler = null): string
+    {
+        if (is_null($httpHandler)) {
+            $httpHandler = HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+        }
+
+        $headers = [];
+        if ($this->imdsv2SessionTokenUrl) {
+            $headers = [
+                'X-aws-ec2-metadata-token' => self::getImdsV2SessionToken($this->imdsv2SessionTokenUrl, $httpHandler)
+            ];
+        }
+
+        if (!$signingVars = self::getSigningVarsFromEnv()) {
+            if (!$this->securityCredentialsUrl) {
+                throw new \LogicException('Unable to get credentials from ENV, and no security credentials URL provided');
+            }
+            $signingVars = self::getSigningVarsFromUrl(
+                $httpHandler,
+                $this->securityCredentialsUrl,
+                self::getRoleName($httpHandler, $this->securityCredentialsUrl, $headers),
+                $headers
+            );
+        }
+
+        if (!$region = self::getRegionFromEnv()) {
+            if (!$this->regionUrl) {
+                throw new \LogicException('Unable to get region from ENV, and no region URL provided');
+            }
+            $region = self::getRegionFromUrl($httpHandler, $this->regionUrl, $headers);
+        }
+        $url = str_replace('{region}', $region, $this->regionalCredVerificationUrl);
+        $host = parse_url($url)['host'] ?? '';
+
+        // From here we use the signing vars to create the signed request to receive a token
+        [$accessKeyId, $secretAccessKey, $securityToken] = $signingVars;
+        $headers = self::getSignedRequestHeaders($region, $host, $accessKeyId, $secretAccessKey, $securityToken);
+
+        // Inject x-goog-cloud-target-resource into header
+        $headers['x-goog-cloud-target-resource'] = $this->audience;
+
+        // Format headers as they're expected in the subject token
+        $formattedHeaders = array_map(
+            fn ($k, $v) => ['key' => $k, 'value' => $v],
+            array_keys($headers),
+            $headers,
+        );
+
+        $request = [
+            'headers' => $formattedHeaders,
+            'method' => 'POST',
+            'url' => $url,
+        ];
+
+        return urlencode(json_encode($request) ?: '');
+    }
+
+    /**
+     * @internal
+     */
+    public static function getImdsV2SessionToken(string $imdsV2Url, callable $httpHandler): string
+    {
+        $headers = [
+            'X-aws-ec2-metadata-token-ttl-seconds' => '21600'
+        ];
+        $request = new Request(
+            'PUT',
+            $imdsV2Url,
+            $headers
+        );
+
+        $response = $httpHandler($request);
+        return (string) $response->getBody();
+    }
+
+    /**
+     * @see http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
+     *
+     * @internal
+     *
+     * @return array<string, string>
+     */
+    public static function getSignedRequestHeaders(
+        string $region,
+        string $host,
+        string $accessKeyId,
+        string $secretAccessKey,
+        ?string $securityToken
+    ): array {
+        $service = 'sts';
+
+        # Create a date for headers and the credential string in ISO-8601 format
+        $amzdate = gmdate('Ymd\THis\Z');
+        $datestamp = gmdate('Ymd'); # Date w/o time, used in credential scope
+
+        # Create the canonical headers and signed headers. Header names
+        # must be trimmed and lowercase, and sorted in code point order from
+        # low to high. Note that there is a trailing \n.
+        $canonicalHeaders = sprintf("host:%s\nx-amz-date:%s\n", $host, $amzdate);
+        if ($securityToken) {
+            $canonicalHeaders .= sprintf("x-amz-security-token:%s\n", $securityToken);
+        }
+
+        # Step 5: Create the list of signed headers. This lists the headers
+        # in the canonicalHeaders list, delimited with ";" and in alpha order.
+        # Note: The request can include any headers; $canonicalHeaders and
+        # $signedHeaders lists those that you want to be included in the
+        # hash of the request. "Host" and "x-amz-date" are always required.
+        $signedHeaders = 'host;x-amz-date';
+        if ($securityToken) {
+            $signedHeaders .= ';x-amz-security-token';
+        }
+
+        # Step 6: Create payload hash (hash of the request body content). For GET
+        # requests, the payload is an empty string ("").
+        $payloadHash = hash('sha256', '');
+
+        # Step 7: Combine elements to create canonical request
+        $canonicalRequest = implode("\n", [
+            'POST', // method
+            '/',   // canonical URL
+            self::CRED_VERIFICATION_QUERY, // query string
+            $canonicalHeaders,
+            $signedHeaders,
+            $payloadHash
+        ]);
+
+        # ************* TASK 2: CREATE THE STRING TO SIGN*************
+        # Match the algorithm to the hashing algorithm you use, either SHA-1 or
+        # SHA-256 (recommended)
+        $algorithm = 'AWS4-HMAC-SHA256';
+        $scope = implode('/', [$datestamp, $region, $service, 'aws4_request']);
+        $stringToSign = implode("\n", [$algorithm, $amzdate, $scope, hash('sha256', $canonicalRequest)]);
+
+        # ************* TASK 3: CALCULATE THE SIGNATURE *************
+        # Create the signing key using the function defined above.
+        // (done above)
+        $signingKey = self::getSignatureKey($secretAccessKey, $datestamp, $region, $service);
+
+        # Sign the string_to_sign using the signing_key
+        $signature = bin2hex(self::hmacSign($signingKey, $stringToSign));
+
+        # ************* TASK 4: ADD SIGNING INFORMATION TO THE REQUEST *************
+        # The signing information can be either in a query string value or in
+        # a header named Authorization. This code shows how to use a header.
+        # Create authorization header and add to request headers
+        $authorizationHeader = sprintf(
+            '%s Credential=%s/%s, SignedHeaders=%s, Signature=%s',
+            $algorithm,
+            $accessKeyId,
+            $scope,
+            $signedHeaders,
+            $signature
+        );
+
+        # The request can include any headers, but MUST include "host", "x-amz-date",
+        # and (for this scenario) "Authorization". "host" and "x-amz-date" must
+        # be included in the canonical_headers and signed_headers, as noted
+        # earlier. Order here is not significant.
+        $headers = [
+            'host' => $host,
+            'x-amz-date' => $amzdate,
+            'Authorization' => $authorizationHeader,
+        ];
+        if ($securityToken) {
+            $headers['x-amz-security-token'] = $securityToken;
+        }
+
+        return $headers;
+    }
+
+    /**
+     * @internal
+     */
+    public static function getRegionFromEnv(): ?string
+    {
+        $region = getenv('AWS_REGION');
+        if (empty($region)) {
+            $region = getenv('AWS_DEFAULT_REGION');
+        }
+        return $region ?: null;
+    }
+
+    /**
+     * @internal
+     *
+     * @param callable $httpHandler
+     * @param string $regionUrl
+     * @param array<string, string|string[]> $headers Request headers to send in with the request.
+     */
+    public static function getRegionFromUrl(callable $httpHandler, string $regionUrl, array $headers): string
+    {
+        // get the region/zone from the region URL
+        $regionRequest = new Request('GET', $regionUrl, $headers);
+        $regionResponse = $httpHandler($regionRequest);
+
+        // Remove last character. For example, if us-east-2b is returned,
+        // the region would be us-east-2.
+        return substr((string) $regionResponse->getBody(), 0, -1);
+    }
+
+    /**
+     * @internal
+     *
+     * @param callable $httpHandler
+     * @param string $securityCredentialsUrl
+     * @param array<string, string|string[]> $headers Request headers to send in with the request.
+     */
+    public static function getRoleName(callable $httpHandler, string $securityCredentialsUrl, array $headers): string
+    {
+        // Get the AWS role name
+        $roleRequest = new Request('GET', $securityCredentialsUrl, $headers);
+        $roleResponse = $httpHandler($roleRequest);
+        $roleName = (string) $roleResponse->getBody();
+
+        return $roleName;
+    }
+
+    /**
+     * @internal
+     *
+     * @param callable $httpHandler
+     * @param string $securityCredentialsUrl
+     * @param array<string, string|string[]> $headers Request headers to send in with the request.
+     * @return array{string, string, ?string}
+     */
+    public static function getSigningVarsFromUrl(
+        callable $httpHandler,
+        string $securityCredentialsUrl,
+        string $roleName,
+        array $headers
+    ): array {
+        // Get the AWS credentials
+        $credsRequest = new Request(
+            'GET',
+            $securityCredentialsUrl . '/' . $roleName,
+            $headers
+        );
+        $credsResponse = $httpHandler($credsRequest);
+        $awsCreds = json_decode((string) $credsResponse->getBody(), true);
+        return [
+            $awsCreds['AccessKeyId'], // accessKeyId
+            $awsCreds['SecretAccessKey'], // secretAccessKey
+            $awsCreds['Token'], // token
+        ];
+    }
+
+    /**
+     * @internal
+     *
+     * @return array{string, string, ?string}
+     */
+    public static function getSigningVarsFromEnv(): ?array
+    {
+        $accessKeyId = getenv('AWS_ACCESS_KEY_ID');
+        $secretAccessKey = getenv('AWS_SECRET_ACCESS_KEY');
+        if ($accessKeyId && $secretAccessKey) {
+            return [
+                $accessKeyId,
+                $secretAccessKey,
+                getenv('AWS_SESSION_TOKEN') ?: null, // session token (can be null)
+            ];
+        }
+
+        return null;
+    }
+
+    /**
+     * Gets the unique key for caching
+     * For AwsNativeSource the values are:
+     * Imdsv2SessionTokenUrl.SecurityCredentialsUrl.RegionUrl.RegionalCredVerificationUrl
+     *
+     * @return string
+     */
+    public function getCacheKey(): string
+    {
+        return ($this->imdsv2SessionTokenUrl ?? '') .
+            '.' . ($this->securityCredentialsUrl ?? '') .
+            '.' . $this->regionUrl .
+            '.' . $this->regionalCredVerificationUrl;
+    }
+
+    /**
+     * Return HMAC hash in binary string
+     */
+    private static function hmacSign(string $key, string $msg): string
+    {
+        return hash_hmac('sha256', self::utf8Encode($msg), $key, true);
+    }
+
+    /**
+     * @TODO add a fallback when mbstring is not available
+     */
+    private static function utf8Encode(string $string): string
+    {
+        return mb_convert_encoding($string, 'UTF-8', 'ISO-8859-1');
+    }
+
+    private static function getSignatureKey(
+        string $key,
+        string $dateStamp,
+        string $regionName,
+        string $serviceName
+    ): string {
+        $kDate = self::hmacSign(self::utf8Encode('AWS4' . $key), $dateStamp);
+        $kRegion = self::hmacSign($kDate, $regionName);
+        $kService = self::hmacSign($kRegion, $serviceName);
+        $kSigning = self::hmacSign($kService, 'aws4_request');
+
+        return $kSigning;
+    }
+}
Index: vendor/google/auth/src/CredentialSource/ExecutableSource.php
===================================================================
--- vendor/google/auth/src/CredentialSource/ExecutableSource.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/CredentialSource/ExecutableSource.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,272 @@
+<?php
+/*
+ * Copyright 2024 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\CredentialSource;
+
+use Google\Auth\ExecutableHandler\ExecutableHandler;
+use Google\Auth\ExecutableHandler\ExecutableResponseError;
+use Google\Auth\ExternalAccountCredentialSourceInterface;
+use RuntimeException;
+
+/**
+ * ExecutableSource enables the exchange of workload identity pool external credentials for
+ * Google access tokens by retrieving 3rd party tokens through a user supplied executable. These
+ * scripts/executables are completely independent of the Google Cloud Auth libraries. These
+ * credentials plug into ADC and will call the specified executable to retrieve the 3rd party token
+ * to be exchanged for a Google access token.
+ *
+ * To use these credentials, the GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES environment variable
+ * must be set to '1'. This is for security reasons.
+ *
+ * Both OIDC and SAML are supported. The executable must adhere to a specific response format
+ * defined below.
+ *
+ * The executable must print out the 3rd party token to STDOUT in JSON format. When an
+ * output_file is specified in the credential configuration, the executable must also handle writing the
+ * JSON response to this file.
+ *
+ * <pre>
+ * OIDC response sample:
+ * {
+ *   "version": 1,
+ *   "success": true,
+ *   "token_type": "urn:ietf:params:oauth:token-type:id_token",
+ *   "id_token": "HEADER.PAYLOAD.SIGNATURE",
+ *   "expiration_time": 1620433341
+ * }
+ *
+ * SAML2 response sample:
+ * {
+ *   "version": 1,
+ *   "success": true,
+ *   "token_type": "urn:ietf:params:oauth:token-type:saml2",
+ *   "saml_response": "...",
+ *   "expiration_time": 1620433341
+ * }
+ *
+ * Error response sample:
+ * {
+ *   "version": 1,
+ *   "success": false,
+ *   "code": "401",
+ *   "message": "Error message."
+ * }
+ * </pre>
+ *
+ * The "expiration_time" field in the JSON response is only required for successful
+ * responses when an output file was specified in the credential configuration
+ *
+ * The auth libraries will populate certain environment variables that will be accessible by the
+ * executable, such as: GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE, GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE,
+ * GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE, GOOGLE_EXTERNAL_ACCOUNT_IMPERSONATED_EMAIL, and
+ * GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE.
+ */
+class ExecutableSource implements ExternalAccountCredentialSourceInterface
+{
+    private const GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES = 'GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES';
+    private const SAML_SUBJECT_TOKEN_TYPE = 'urn:ietf:params:oauth:token-type:saml2';
+    private const OIDC_SUBJECT_TOKEN_TYPE1 = 'urn:ietf:params:oauth:token-type:id_token';
+    private const OIDC_SUBJECT_TOKEN_TYPE2 = 'urn:ietf:params:oauth:token-type:jwt';
+
+    private string $command;
+    private ExecutableHandler $executableHandler;
+    private ?string $outputFile;
+
+    /**
+     * @param string $command    The string command to run to get the subject token.
+     * @param string|null $outputFile
+     */
+    public function __construct(
+        string $command,
+        ?string $outputFile,
+        ?ExecutableHandler $executableHandler = null,
+    ) {
+        $this->command = $command;
+        $this->outputFile = $outputFile;
+        $this->executableHandler = $executableHandler ?: new ExecutableHandler();
+    }
+
+    /**
+     * Gets the unique key for caching
+     * The format for the cache key is:
+     * Command.OutputFile
+     *
+     * @return ?string
+     */
+    public function getCacheKey(): ?string
+    {
+        return $this->command . '.' . $this->outputFile;
+    }
+
+    /**
+     * @param callable|null $httpHandler unused.
+     * @return string
+     * @throws RuntimeException if the executable is not allowed to run.
+     * @throws ExecutableResponseError if the executable response is invalid.
+     */
+    public function fetchSubjectToken(?callable $httpHandler = null): string
+    {
+        // Check if the executable is allowed to run.
+        if (getenv(self::GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES) !== '1') {
+            throw new RuntimeException(
+                'Pluggable Auth executables need to be explicitly allowed to run by '
+                . 'setting the GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES environment '
+                . 'Variable to 1.'
+            );
+        }
+
+        if (!$executableResponse = $this->getCachedExecutableResponse()) {
+            // Run the executable.
+            $exitCode = ($this->executableHandler)($this->command);
+            $output = $this->executableHandler->getOutput();
+
+            // If the exit code is not 0, throw an exception with the output as the error details
+            if ($exitCode !== 0) {
+                throw new ExecutableResponseError(
+                    'The executable failed to run'
+                    . ($output ? ' with the following error: ' . $output : '.'),
+                    (string) $exitCode
+                );
+            }
+
+            $executableResponse = $this->parseExecutableResponse($output);
+
+            // Validate expiration.
+            if (isset($executableResponse['expiration_time']) && time() >= $executableResponse['expiration_time']) {
+                throw new ExecutableResponseError('Executable response is expired.');
+            }
+        }
+
+        // Throw error when the request was unsuccessful
+        if ($executableResponse['success'] === false) {
+            throw new ExecutableResponseError($executableResponse['message'], (string) $executableResponse['code']);
+        }
+
+        // Return subject token field based on the token type
+        return $executableResponse['token_type'] === self::SAML_SUBJECT_TOKEN_TYPE
+            ? $executableResponse['saml_response']
+            : $executableResponse['id_token'];
+    }
+
+    /**
+     * @return array<string, mixed>|null
+     */
+    private function getCachedExecutableResponse(): ?array
+    {
+        if (
+            $this->outputFile
+            && file_exists($this->outputFile)
+            && !empty(trim($outputFileContents = (string) file_get_contents($this->outputFile)))
+        ) {
+            try {
+                $executableResponse = $this->parseExecutableResponse($outputFileContents);
+            } catch (ExecutableResponseError $e) {
+                throw new ExecutableResponseError(
+                    'Error in output file: ' . $e->getMessage(),
+                    'INVALID_OUTPUT_FILE'
+                );
+            }
+
+            if ($executableResponse['success'] === false) {
+                // If the cached token was unsuccessful, run the executable to get a new one.
+                return null;
+            }
+
+            if (isset($executableResponse['expiration_time']) && time() >= $executableResponse['expiration_time']) {
+                // If the cached token is expired, run the executable to get a new one.
+                return null;
+            }
+
+            return $executableResponse;
+        }
+
+        return null;
+    }
+
+    /**
+     * @return array<string, mixed>
+     */
+    private function parseExecutableResponse(string $response): array
+    {
+        $executableResponse = json_decode($response, true);
+        if (json_last_error() !== JSON_ERROR_NONE) {
+            throw new ExecutableResponseError(
+                'The executable returned an invalid response: ' . $response,
+                'INVALID_RESPONSE'
+            );
+        }
+        if (!array_key_exists('version', $executableResponse)) {
+            throw new ExecutableResponseError('Executable response must contain a "version" field.');
+        }
+        if (!array_key_exists('success', $executableResponse)) {
+            throw new ExecutableResponseError('Executable response must contain a "success" field.');
+        }
+
+        // Validate required fields for a successful response.
+        if ($executableResponse['success']) {
+            // Validate token type field.
+            $tokenTypes = [self::SAML_SUBJECT_TOKEN_TYPE, self::OIDC_SUBJECT_TOKEN_TYPE1, self::OIDC_SUBJECT_TOKEN_TYPE2];
+            if (!isset($executableResponse['token_type'])) {
+                throw new ExecutableResponseError(
+                    'Executable response must contain a "token_type" field when successful'
+                );
+            }
+            if (!in_array($executableResponse['token_type'], $tokenTypes)) {
+                throw new ExecutableResponseError(sprintf(
+                    'Executable response "token_type" field must be one of %s.',
+                    implode(', ', $tokenTypes)
+                ));
+            }
+
+            // Validate subject token for SAML and OIDC.
+            if ($executableResponse['token_type'] === self::SAML_SUBJECT_TOKEN_TYPE) {
+                if (empty($executableResponse['saml_response'])) {
+                    throw new ExecutableResponseError(sprintf(
+                        'Executable response must contain a "saml_response" field when token_type=%s.',
+                        self::SAML_SUBJECT_TOKEN_TYPE
+                    ));
+                }
+            } elseif (empty($executableResponse['id_token'])) {
+                throw new ExecutableResponseError(sprintf(
+                    'Executable response must contain a "id_token" field when '
+                    . 'token_type=%s.',
+                    $executableResponse['token_type']
+                ));
+            }
+
+            // Validate expiration exists when an output file is specified.
+            if ($this->outputFile) {
+                if (!isset($executableResponse['expiration_time'])) {
+                    throw new ExecutableResponseError(
+                        'The executable response must contain a "expiration_time" field for successful responses ' .
+                        'when an output_file has been specified in the configuration.'
+                    );
+                }
+            }
+        } else {
+            // Both code and message must be provided for unsuccessful responses.
+            if (!array_key_exists('code', $executableResponse)) {
+                throw new ExecutableResponseError('Executable response must contain a "code" field when unsuccessful.');
+            }
+            if (empty($executableResponse['message'])) {
+                throw new ExecutableResponseError('Executable response must contain a "message" field when unsuccessful.');
+            }
+        }
+
+        return $executableResponse;
+    }
+}
Index: vendor/google/auth/src/CredentialSource/FileSource.php
===================================================================
--- vendor/google/auth/src/CredentialSource/FileSource.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/CredentialSource/FileSource.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,87 @@
+<?php
+/*
+ * Copyright 2023 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\CredentialSource;
+
+use Google\Auth\ExternalAccountCredentialSourceInterface;
+use InvalidArgumentException;
+use UnexpectedValueException;
+
+/**
+ * Retrieve a token from a file.
+ */
+class FileSource implements ExternalAccountCredentialSourceInterface
+{
+    private string $file;
+    private ?string $format;
+    private ?string $subjectTokenFieldName;
+
+    /**
+     * @param string $file                       The file to read the subject token from.
+     * @param string|null $format                The format of the token in the file. Can be null or "json".
+     * @param string|null $subjectTokenFieldName The name of the field containing the token in the file. This is required
+     *                                           when format is "json".
+     */
+    public function __construct(
+        string $file,
+        ?string $format = null,
+        ?string $subjectTokenFieldName = null
+    ) {
+        $this->file = $file;
+
+        if ($format === 'json' && is_null($subjectTokenFieldName)) {
+            throw new InvalidArgumentException(
+                'subject_token_field_name must be set when format is JSON'
+            );
+        }
+
+        $this->format = $format;
+        $this->subjectTokenFieldName = $subjectTokenFieldName;
+    }
+
+    public function fetchSubjectToken(?callable $httpHandler = null): string
+    {
+        $contents = file_get_contents($this->file);
+        if ($this->format === 'json') {
+            if (!$json = json_decode((string) $contents, true)) {
+                throw new UnexpectedValueException(
+                    'Unable to decode JSON file'
+                );
+            }
+            if (!isset($json[$this->subjectTokenFieldName])) {
+                throw new UnexpectedValueException(
+                    'subject_token_field_name not found in JSON file'
+                );
+            }
+            $contents = $json[$this->subjectTokenFieldName];
+        }
+
+        return $contents;
+    }
+
+    /**
+     * Gets the unique key for caching.
+     * The format for the cache key one of the following:
+     * Filename
+     *
+     * @return string
+     */
+    public function getCacheKey(): ?string
+    {
+        return $this->file;
+    }
+}
Index: vendor/google/auth/src/CredentialSource/UrlSource.php
===================================================================
--- vendor/google/auth/src/CredentialSource/UrlSource.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/CredentialSource/UrlSource.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,109 @@
+<?php
+/*
+ * Copyright 2023 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\CredentialSource;
+
+use Google\Auth\ExternalAccountCredentialSourceInterface;
+use Google\Auth\HttpHandler\HttpClientCache;
+use Google\Auth\HttpHandler\HttpHandlerFactory;
+use GuzzleHttp\Psr7\Request;
+use InvalidArgumentException;
+use UnexpectedValueException;
+
+/**
+ * Retrieve a token from a URL.
+ */
+class UrlSource implements ExternalAccountCredentialSourceInterface
+{
+    private string $url;
+    private ?string $format;
+    private ?string $subjectTokenFieldName;
+
+    /**
+     * @var array<string, string|string[]>
+     */
+    private ?array $headers;
+
+    /**
+     * @param string $url                        The URL to fetch the subject token from.
+     * @param string|null $format                The format of the token in the response. Can be null or "json".
+     * @param string|null $subjectTokenFieldName The name of the field containing the token in the response. This is required
+     *                                      when format is "json".
+     * @param array<string, string|string[]>|null $headers Request headers to send in with the request to the URL.
+     */
+    public function __construct(
+        string $url,
+        ?string $format = null,
+        ?string $subjectTokenFieldName = null,
+        ?array $headers = null
+    ) {
+        $this->url = $url;
+
+        if ($format === 'json' && is_null($subjectTokenFieldName)) {
+            throw new InvalidArgumentException(
+                'subject_token_field_name must be set when format is JSON'
+            );
+        }
+
+        $this->format = $format;
+        $this->subjectTokenFieldName = $subjectTokenFieldName;
+        $this->headers = $headers;
+    }
+
+    public function fetchSubjectToken(?callable $httpHandler = null): string
+    {
+        if (is_null($httpHandler)) {
+            $httpHandler = HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+        }
+
+        $request = new Request(
+            'GET',
+            $this->url,
+            $this->headers ?: []
+        );
+
+        $response = $httpHandler($request);
+        $body = (string) $response->getBody();
+        if ($this->format === 'json') {
+            if (!$json = json_decode((string) $body, true)) {
+                throw new UnexpectedValueException(
+                    'Unable to decode JSON response'
+                );
+            }
+            if (!isset($json[$this->subjectTokenFieldName])) {
+                throw new UnexpectedValueException(
+                    'subject_token_field_name not found in JSON file'
+                );
+            }
+            $body = $json[$this->subjectTokenFieldName];
+        }
+
+        return $body;
+    }
+
+    /**
+     * Get the cache key for the credentials.
+     * The format for the cache key is:
+     * URL
+     *
+     * @return ?string
+     */
+    public function getCacheKey(): ?string
+    {
+        return $this->url;
+    }
+}
Index: vendor/google/auth/src/Credentials/AppIdentityCredentials.php
===================================================================
--- vendor/google/auth/src/Credentials/AppIdentityCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Credentials/AppIdentityCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,238 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Credentials;
+
+/*
+ * The AppIdentityService class is automatically defined on App Engine,
+ * so including this dependency is not necessary, and will result in a
+ * PHP fatal error in the App Engine environment.
+ */
+use google\appengine\api\app_identity\AppIdentityService;
+use Google\Auth\CredentialsLoader;
+use Google\Auth\ProjectIdProviderInterface;
+use Google\Auth\SignBlobInterface;
+
+/**
+ * @deprecated
+ *
+ * AppIdentityCredentials supports authorization on Google App Engine.
+ *
+ * It can be used to authorize requests using the AuthTokenMiddleware or
+ * AuthTokenSubscriber, but will only succeed if being run on App Engine:
+ *
+ * Example:
+ * ```
+ * use Google\Auth\Credentials\AppIdentityCredentials;
+ * use Google\Auth\Middleware\AuthTokenMiddleware;
+ * use GuzzleHttp\Client;
+ * use GuzzleHttp\HandlerStack;
+ *
+ * $gae = new AppIdentityCredentials('https://www.googleapis.com/auth/books');
+ * $middleware = new AuthTokenMiddleware($gae);
+ * $stack = HandlerStack::create();
+ * $stack->push($middleware);
+ *
+ * $client = new Client([
+ *     'handler' => $stack,
+ *     'base_uri' => 'https://www.googleapis.com/books/v1',
+ *     'auth' => 'google_auth'
+ * ]);
+ *
+ * $res = $client->get('volumes?q=Henry+David+Thoreau&country=US');
+ * ```
+ */
+class AppIdentityCredentials extends CredentialsLoader implements
+    SignBlobInterface,
+    ProjectIdProviderInterface
+{
+    /**
+     * Result of fetchAuthToken.
+     *
+     * @var array<mixed>
+     */
+    protected $lastReceivedToken;
+
+    /**
+     * Array of OAuth2 scopes to be requested.
+     *
+     * @var string[]
+     */
+    private $scope;
+
+    /**
+     * @var string
+     */
+    private $clientName;
+
+    /**
+     * @param string|string[] $scope One or more scopes.
+     */
+    public function __construct($scope = [])
+    {
+        $this->scope = is_array($scope) ? $scope : explode(' ', (string) $scope);
+    }
+
+    /**
+     * Determines if this an App Engine instance, by accessing the
+     * SERVER_SOFTWARE environment variable (prod) or the APPENGINE_RUNTIME
+     * environment variable (dev).
+     *
+     * @return bool true if this an App Engine Instance, false otherwise
+     */
+    public static function onAppEngine()
+    {
+        $appEngineProduction = isset($_SERVER['SERVER_SOFTWARE']) &&
+            0 === strpos($_SERVER['SERVER_SOFTWARE'], 'Google App Engine');
+        if ($appEngineProduction) {
+            return true;
+        }
+        $appEngineDevAppServer = isset($_SERVER['APPENGINE_RUNTIME']) &&
+            $_SERVER['APPENGINE_RUNTIME'] == 'php';
+        if ($appEngineDevAppServer) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Implements FetchAuthTokenInterface#fetchAuthToken.
+     *
+     * Fetches the auth tokens using the AppIdentityService if available.
+     * As the AppIdentityService uses protobufs to fetch the access token,
+     * the GuzzleHttp\ClientInterface instance passed in will not be used.
+     *
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @return array<mixed> {
+     *     A set of auth related metadata, containing the following
+     *
+     *     @type string $access_token
+     *     @type string $expiration_time
+     * }
+     */
+    public function fetchAuthToken(?callable $httpHandler = null)
+    {
+        try {
+            $this->checkAppEngineContext();
+        } catch (\Exception $e) {
+            return [];
+        }
+
+        /** @phpstan-ignore-next-line */
+        $token = AppIdentityService::getAccessToken($this->scope);
+        $this->lastReceivedToken = $token;
+
+        return $token;
+    }
+
+    /**
+     * Sign a string using AppIdentityService.
+     *
+     * @param string $stringToSign The string to sign.
+     * @param bool $forceOpenSsl [optional] Does not apply to this credentials
+     *        type.
+     * @return string The signature, base64-encoded.
+     * @throws \Exception If AppEngine SDK or mock is not available.
+     */
+    public function signBlob($stringToSign, $forceOpenSsl = false)
+    {
+        $this->checkAppEngineContext();
+
+        /** @phpstan-ignore-next-line */
+        return base64_encode(AppIdentityService::signForApp($stringToSign)['signature']);
+    }
+
+    /**
+     * Get the project ID from AppIdentityService.
+     *
+     * Returns null if AppIdentityService is unavailable.
+     *
+     * @param callable|null $httpHandler Not used by this type.
+     * @return string|null
+     */
+    public function getProjectId(?callable $httpHandler = null)
+    {
+        try {
+            $this->checkAppEngineContext();
+        } catch (\Exception $e) {
+            return null;
+        }
+
+        /** @phpstan-ignore-next-line */
+        return AppIdentityService::getApplicationId();
+    }
+
+    /**
+     * Get the client name from AppIdentityService.
+     *
+     * Subsequent calls to this method will return a cached value.
+     *
+     * @param callable|null $httpHandler Not used in this implementation.
+     * @return string
+     * @throws \Exception If AppEngine SDK or mock is not available.
+     */
+    public function getClientName(?callable $httpHandler = null)
+    {
+        $this->checkAppEngineContext();
+
+        if (!$this->clientName) {
+            /** @phpstan-ignore-next-line */
+            $this->clientName = AppIdentityService::getServiceAccountName();
+        }
+
+        return $this->clientName;
+    }
+
+    /**
+     * @return array{access_token:string,expires_at:int}|null
+     */
+    public function getLastReceivedToken()
+    {
+        if ($this->lastReceivedToken) {
+            return [
+                'access_token' => $this->lastReceivedToken['access_token'],
+                'expires_at' => $this->lastReceivedToken['expiration_time'],
+            ];
+        }
+
+        return null;
+    }
+
+    /**
+     * Caching is handled by the underlying AppIdentityService, return empty string
+     * to prevent caching.
+     *
+     * @return string
+     */
+    public function getCacheKey()
+    {
+        return '';
+    }
+
+    /**
+     * @return void
+     */
+    private function checkAppEngineContext()
+    {
+        if (!self::onAppEngine() || !class_exists('google\appengine\api\app_identity\AppIdentityService')) {
+            throw new \Exception(
+                'This class must be run in App Engine, or you must include the AppIdentityService '
+                . 'mock class defined in tests/mocks/AppIdentityService.php'
+            );
+        }
+    }
+}
Index: vendor/google/auth/src/Credentials/ExternalAccountCredentials.php
===================================================================
--- vendor/google/auth/src/Credentials/ExternalAccountCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Credentials/ExternalAccountCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,378 @@
+<?php
+/*
+ * Copyright 2023 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Credentials;
+
+use Google\Auth\CredentialSource\AwsNativeSource;
+use Google\Auth\CredentialSource\ExecutableSource;
+use Google\Auth\CredentialSource\FileSource;
+use Google\Auth\CredentialSource\UrlSource;
+use Google\Auth\ExecutableHandler\ExecutableHandler;
+use Google\Auth\ExternalAccountCredentialSourceInterface;
+use Google\Auth\FetchAuthTokenInterface;
+use Google\Auth\GetQuotaProjectInterface;
+use Google\Auth\GetUniverseDomainInterface;
+use Google\Auth\HttpHandler\HttpClientCache;
+use Google\Auth\HttpHandler\HttpHandlerFactory;
+use Google\Auth\OAuth2;
+use Google\Auth\ProjectIdProviderInterface;
+use Google\Auth\UpdateMetadataInterface;
+use Google\Auth\UpdateMetadataTrait;
+use GuzzleHttp\Psr7\Request;
+use InvalidArgumentException;
+
+class ExternalAccountCredentials implements
+    FetchAuthTokenInterface,
+    UpdateMetadataInterface,
+    GetQuotaProjectInterface,
+    GetUniverseDomainInterface,
+    ProjectIdProviderInterface
+{
+    use UpdateMetadataTrait;
+
+    private const EXTERNAL_ACCOUNT_TYPE = 'external_account';
+    private const CLOUD_RESOURCE_MANAGER_URL = 'https://cloudresourcemanager.UNIVERSE_DOMAIN/v1/projects/%s';
+
+    private OAuth2 $auth;
+    private ?string $quotaProject;
+    private ?string $serviceAccountImpersonationUrl;
+    private ?string $workforcePoolUserProject;
+    private ?string $projectId;
+    private string $universeDomain;
+
+    /**
+     * @param string|string[] $scope   The scope of the access request, expressed either as an array
+     *                                 or as a space-delimited string.
+     * @param array<mixed>    $jsonKey JSON credentials as an associative array.
+     */
+    public function __construct(
+        $scope,
+        array $jsonKey
+    ) {
+        if (!array_key_exists('type', $jsonKey)) {
+            throw new InvalidArgumentException('json key is missing the type field');
+        }
+        if ($jsonKey['type'] !== self::EXTERNAL_ACCOUNT_TYPE) {
+            throw new InvalidArgumentException(sprintf(
+                'expected "%s" type but received "%s"',
+                self::EXTERNAL_ACCOUNT_TYPE,
+                $jsonKey['type']
+            ));
+        }
+
+        if (!array_key_exists('token_url', $jsonKey)) {
+            throw new InvalidArgumentException(
+                'json key is missing the token_url field'
+            );
+        }
+
+        if (!array_key_exists('audience', $jsonKey)) {
+            throw new InvalidArgumentException(
+                'json key is missing the audience field'
+            );
+        }
+
+        if (!array_key_exists('subject_token_type', $jsonKey)) {
+            throw new InvalidArgumentException(
+                'json key is missing the subject_token_type field'
+            );
+        }
+
+        if (!array_key_exists('credential_source', $jsonKey)) {
+            throw new InvalidArgumentException(
+                'json key is missing the credential_source field'
+            );
+        }
+
+        $this->serviceAccountImpersonationUrl = $jsonKey['service_account_impersonation_url'] ?? null;
+
+        $this->quotaProject = $jsonKey['quota_project_id'] ?? null;
+        $this->workforcePoolUserProject = $jsonKey['workforce_pool_user_project'] ?? null;
+        $this->universeDomain = $jsonKey['universe_domain'] ?? GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN;
+
+        $this->auth = new OAuth2([
+            'tokenCredentialUri' => $jsonKey['token_url'],
+            'audience' => $jsonKey['audience'],
+            'scope' => $scope,
+            'subjectTokenType' => $jsonKey['subject_token_type'],
+            'subjectTokenFetcher' => self::buildCredentialSource($jsonKey),
+            'additionalOptions' => $this->workforcePoolUserProject
+                ? ['userProject' => $this->workforcePoolUserProject]
+                : [],
+        ]);
+
+        if (!$this->isWorkforcePool() && $this->workforcePoolUserProject) {
+            throw new InvalidArgumentException(
+                'workforce_pool_user_project should not be set for non-workforce pool credentials.'
+            );
+        }
+    }
+
+    /**
+     * @param array<mixed> $jsonKey
+     */
+    private static function buildCredentialSource(array $jsonKey): ExternalAccountCredentialSourceInterface
+    {
+        $credentialSource = $jsonKey['credential_source'];
+        if (isset($credentialSource['file'])) {
+            return new FileSource(
+                $credentialSource['file'],
+                $credentialSource['format']['type'] ?? null,
+                $credentialSource['format']['subject_token_field_name'] ?? null
+            );
+        }
+
+        if (
+            isset($credentialSource['environment_id'])
+            && 1 === preg_match('/^aws(\d+)$/', $credentialSource['environment_id'], $matches)
+        ) {
+            if ($matches[1] !== '1') {
+                throw new InvalidArgumentException(
+                    "aws version \"$matches[1]\" is not supported in the current build."
+                );
+            }
+            if (!array_key_exists('regional_cred_verification_url', $credentialSource)) {
+                throw new InvalidArgumentException(
+                    'The regional_cred_verification_url field is required for aws1 credential source.'
+                );
+            }
+
+            return new AwsNativeSource(
+                $jsonKey['audience'],
+                $credentialSource['regional_cred_verification_url'],   // $regionalCredVerificationUrl
+                $credentialSource['region_url'] ?? null,               // $regionUrl
+                $credentialSource['url'] ?? null,                      // $securityCredentialsUrl
+                $credentialSource['imdsv2_session_token_url'] ?? null, // $imdsV2TokenUrl
+            );
+        }
+
+        if (isset($credentialSource['url'])) {
+            return new UrlSource(
+                $credentialSource['url'],
+                $credentialSource['format']['type'] ?? null,
+                $credentialSource['format']['subject_token_field_name'] ?? null,
+                $credentialSource['headers'] ?? null,
+            );
+        }
+
+        if (isset($credentialSource['executable'])) {
+            if (!array_key_exists('command', $credentialSource['executable'])) {
+                throw new InvalidArgumentException(
+                    'executable source requires a command to be set in the JSON file.'
+                );
+            }
+
+            // Build command environment variables
+            $env = [
+                'GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE' => $jsonKey['audience'],
+                'GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE' => $jsonKey['subject_token_type'],
+                // Always set to 0 because interactive mode is not supported.
+                'GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE' => '0',
+            ];
+
+            if ($outputFile = $credentialSource['executable']['output_file'] ?? null) {
+                $env['GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE'] = $outputFile;
+            }
+
+            if ($serviceAccountImpersonationUrl = $jsonKey['service_account_impersonation_url'] ?? null) {
+                // Parse email from URL. The formal looks as follows:
+                // https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/name@project-id.iam.gserviceaccount.com:generateAccessToken
+                $regex = '/serviceAccounts\/(?<email>[^:]+):generateAccessToken$/';
+                if (preg_match($regex, $serviceAccountImpersonationUrl, $matches)) {
+                    $env['GOOGLE_EXTERNAL_ACCOUNT_IMPERSONATED_EMAIL'] = $matches['email'];
+                }
+            }
+
+            $timeoutMs = $credentialSource['executable']['timeout_millis'] ?? null;
+
+            return new ExecutableSource(
+                $credentialSource['executable']['command'],
+                $outputFile,
+                $timeoutMs ? new ExecutableHandler($env, $timeoutMs) : new ExecutableHandler($env)
+            );
+        }
+
+        throw new InvalidArgumentException('Unable to determine credential source from json key.');
+    }
+
+    /**
+     * @param string $stsToken
+     * @param callable|null $httpHandler
+     *
+     * @return array<mixed> {
+     *     A set of auth related metadata, containing the following
+     *
+     *     @type string $access_token
+     *     @type int $expires_at
+     * }
+     */
+    private function getImpersonatedAccessToken(string $stsToken, ?callable $httpHandler = null): array
+    {
+        if (!isset($this->serviceAccountImpersonationUrl)) {
+            throw new InvalidArgumentException(
+                'service_account_impersonation_url must be set in JSON credentials.'
+            );
+        }
+        $request = new Request(
+            'POST',
+            $this->serviceAccountImpersonationUrl,
+            [
+                'Content-Type' => 'application/json',
+                'Authorization' => 'Bearer ' . $stsToken,
+            ],
+            (string) json_encode([
+                'lifetime' => sprintf('%ss', OAuth2::DEFAULT_EXPIRY_SECONDS),
+                'scope' => explode(' ', $this->auth->getScope()),
+            ]),
+        );
+        if (is_null($httpHandler)) {
+            $httpHandler = HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+        }
+        $response = $httpHandler($request);
+        $body = json_decode((string) $response->getBody(), true);
+        return [
+            'access_token' => $body['accessToken'],
+            'expires_at' => strtotime($body['expireTime']),
+        ];
+    }
+
+    /**
+     * @param callable|null $httpHandler
+     *
+     * @return array<mixed> {
+     *     A set of auth related metadata, containing the following
+     *
+     *     @type string $access_token
+     *     @type int $expires_at (impersonated service accounts only)
+     *     @type int $expires_in (identity pool only)
+     *     @type string $issued_token_type (identity pool only)
+     *     @type string $token_type (identity pool only)
+     * }
+     */
+    public function fetchAuthToken(?callable $httpHandler = null)
+    {
+        $stsToken = $this->auth->fetchAuthToken($httpHandler);
+
+        if (isset($this->serviceAccountImpersonationUrl)) {
+            return $this->getImpersonatedAccessToken($stsToken['access_token'], $httpHandler);
+        }
+
+        return $stsToken;
+    }
+
+    /**
+     * Get the cache token key for the credentials.
+     * The cache token key format depends on the type of source
+     * The format for the cache key one of the following:
+     * FetcherCacheKey.Scope.[ServiceAccount].[TokenType].[WorkforcePoolUserProject]
+     * FetcherCacheKey.Audience.[ServiceAccount].[TokenType].[WorkforcePoolUserProject]
+     *
+     * @return ?string;
+     */
+    public function getCacheKey(): ?string
+    {
+        $scopeOrAudience = $this->auth->getAudience();
+        if (!$scopeOrAudience) {
+            $scopeOrAudience = $this->auth->getScope();
+        }
+
+        return $this->auth->getSubjectTokenFetcher()->getCacheKey() .
+            '.' . $scopeOrAudience .
+            '.' . ($this->serviceAccountImpersonationUrl ?? '') .
+            '.' . ($this->auth->getSubjectTokenType() ?? '') .
+            '.' . ($this->workforcePoolUserProject ?? '');
+    }
+
+    public function getLastReceivedToken()
+    {
+        return $this->auth->getLastReceivedToken();
+    }
+
+    /**
+     * Get the quota project used for this API request
+     *
+     * @return string|null
+     */
+    public function getQuotaProject()
+    {
+        return $this->quotaProject;
+    }
+
+    /**
+     * Get the universe domain used for this API request
+     *
+     * @return string
+     */
+    public function getUniverseDomain(): string
+    {
+        return $this->universeDomain;
+    }
+
+    /**
+     * Get the project ID.
+     *
+     * @param callable|null $httpHandler Callback which delivers psr7 request
+     * @param string|null $accessToken The access token to use to sign the blob. If
+     *        provided, saves a call to the metadata server for a new access
+     *        token. **Defaults to** `null`.
+     * @return string|null
+     */
+    public function getProjectId(?callable $httpHandler = null, ?string $accessToken = null)
+    {
+        if (isset($this->projectId)) {
+            return $this->projectId;
+        }
+
+        $projectNumber = $this->getProjectNumber() ?: $this->workforcePoolUserProject;
+        if (!$projectNumber) {
+            return null;
+        }
+
+        if (is_null($httpHandler)) {
+            $httpHandler = HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+        }
+
+        $url = str_replace(
+            'UNIVERSE_DOMAIN',
+            $this->getUniverseDomain(),
+            sprintf(self::CLOUD_RESOURCE_MANAGER_URL, $projectNumber)
+        );
+
+        if (is_null($accessToken)) {
+            $accessToken = $this->fetchAuthToken($httpHandler)['access_token'];
+        }
+
+        $request = new Request('GET', $url, ['authorization' => 'Bearer ' . $accessToken]);
+        $response = $httpHandler($request);
+
+        $body = json_decode((string) $response->getBody(), true);
+        return $this->projectId = $body['projectId'];
+    }
+
+    private function getProjectNumber(): ?string
+    {
+        $parts = explode('/', $this->auth->getAudience());
+        $i = array_search('projects', $parts);
+        return $parts[$i + 1] ?? null;
+    }
+
+    private function isWorkforcePool(): bool
+    {
+        $regex = '#//iam\.googleapis\.com/locations/[^/]+/workforcePools/#';
+        return preg_match($regex, $this->auth->getAudience()) === 1;
+    }
+}
Index: vendor/google/auth/src/Credentials/GCECredentials.php
===================================================================
--- vendor/google/auth/src/Credentials/GCECredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Credentials/GCECredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,683 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Credentials;
+
+use COM;
+use com_exception;
+use Google\Auth\CredentialsLoader;
+use Google\Auth\GetQuotaProjectInterface;
+use Google\Auth\HttpHandler\HttpClientCache;
+use Google\Auth\HttpHandler\HttpHandlerFactory;
+use Google\Auth\Iam;
+use Google\Auth\IamSignerTrait;
+use Google\Auth\ProjectIdProviderInterface;
+use Google\Auth\SignBlobInterface;
+use GuzzleHttp\Exception\ClientException;
+use GuzzleHttp\Exception\ConnectException;
+use GuzzleHttp\Exception\RequestException;
+use GuzzleHttp\Exception\ServerException;
+use GuzzleHttp\Psr7\Request;
+use InvalidArgumentException;
+
+/**
+ * GCECredentials supports authorization on Google Compute Engine.
+ *
+ * It can be used to authorize requests using the AuthTokenMiddleware, but will
+ * only succeed if being run on GCE:
+ *
+ *   use Google\Auth\Credentials\GCECredentials;
+ *   use Google\Auth\Middleware\AuthTokenMiddleware;
+ *   use GuzzleHttp\Client;
+ *   use GuzzleHttp\HandlerStack;
+ *
+ *   $gce = new GCECredentials();
+ *   $middleware = new AuthTokenMiddleware($gce);
+ *   $stack = HandlerStack::create();
+ *   $stack->push($middleware);
+ *
+ *   $client = new Client([
+ *      'handler' => $stack,
+ *      'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
+ *      'auth' => 'google_auth'
+ *   ]);
+ *
+ *   $res = $client->get('myproject/taskqueues/myqueue');
+ */
+class GCECredentials extends CredentialsLoader implements
+    SignBlobInterface,
+    ProjectIdProviderInterface,
+    GetQuotaProjectInterface
+{
+    use IamSignerTrait;
+
+    // phpcs:disable
+    const cacheKey = 'GOOGLE_AUTH_PHP_GCE';
+    // phpcs:enable
+
+    /**
+     * The metadata IP address on appengine instances.
+     *
+     * The IP is used instead of the domain 'metadata' to avoid slow responses
+     * when not on Compute Engine.
+     */
+    const METADATA_IP = '169.254.169.254';
+
+    /**
+     * The metadata path of the default token.
+     */
+    const TOKEN_URI_PATH = 'v1/instance/service-accounts/default/token';
+
+    /**
+     * The metadata path of the default id token.
+     */
+    const ID_TOKEN_URI_PATH = 'v1/instance/service-accounts/default/identity';
+
+    /**
+     * The metadata path of the client ID.
+     */
+    const CLIENT_ID_URI_PATH = 'v1/instance/service-accounts/default/email';
+
+    /**
+     * The metadata path of the project ID.
+     */
+    const PROJECT_ID_URI_PATH = 'v1/project/project-id';
+
+    /**
+     * The metadata path of the project ID.
+     */
+    const UNIVERSE_DOMAIN_URI_PATH = 'v1/universe/universe-domain';
+
+    /**
+     * The header whose presence indicates GCE presence.
+     */
+    const FLAVOR_HEADER = 'Metadata-Flavor';
+
+    /**
+     * The Linux file which contains the product name.
+     */
+    private const GKE_PRODUCT_NAME_FILE = '/sys/class/dmi/id/product_name';
+
+    /**
+     * The Windows Registry key path to the product name
+     */
+    private const WINDOWS_REGISTRY_KEY_PATH = 'HKEY_LOCAL_MACHINE\\SYSTEM\\HardwareConfig\\Current\\';
+
+    /**
+     * The Windows registry key name for the product name
+     */
+    private const WINDOWS_REGISTRY_KEY_NAME = 'SystemProductName';
+
+    /**
+     * The Name of the product expected from the windows registry
+     */
+    private const PRODUCT_NAME = 'Google';
+
+    private const CRED_TYPE = 'mds';
+
+    /**
+     * Note: the explicit `timeout` and `tries` below is a workaround. The underlying
+     * issue is that resolving an unknown host on some networks will take
+     * 20-30 seconds; making this timeout short fixes the issue, but
+     * could lead to false negatives in the event that we are on GCE, but
+     * the metadata resolution was particularly slow. The latter case is
+     * "unlikely" since the expected 4-nines time is about 0.5 seconds.
+     * This allows us to limit the total ping maximum timeout to 1.5 seconds
+     * for developer desktop scenarios.
+     */
+    const MAX_COMPUTE_PING_TRIES = 3;
+    const COMPUTE_PING_CONNECTION_TIMEOUT_S = 0.5;
+
+    /**
+     * Flag used to ensure that the onGCE test is only done once;.
+     *
+     * @var bool
+     */
+    private $hasCheckedOnGce = false;
+
+    /**
+     * Flag that stores the value of the onGCE check.
+     *
+     * @var bool
+     */
+    private $isOnGce = false;
+
+    /**
+     * Result of fetchAuthToken.
+     *
+     * @var array<mixed>
+     */
+    protected $lastReceivedToken;
+
+    /**
+     * @var string|null
+     */
+    private $clientName;
+
+    /**
+     * @var string|null
+     */
+    private $projectId;
+
+    /**
+     * @var string
+     */
+    private $tokenUri;
+
+    /**
+     * @var string
+     */
+    private $targetAudience;
+
+    /**
+     * @var string|null
+     */
+    private $quotaProject;
+
+    /**
+     * @var string|null
+     */
+    private $serviceAccountIdentity;
+
+    /**
+     * @var string
+     */
+    private ?string $universeDomain;
+
+    /**
+     * @param Iam|null $iam [optional] An IAM instance.
+     * @param string|string[] $scope [optional] the scope of the access request,
+     *        expressed either as an array or as a space-delimited string.
+     * @param string $targetAudience [optional] The audience for the ID token.
+     * @param string $quotaProject [optional] Specifies a project to bill for access
+     *   charges associated with the request.
+     * @param string $serviceAccountIdentity [optional] Specify a service
+     *   account identity name to use instead of "default".
+     * @param string|null $universeDomain [optional] Specify a universe domain to use
+     *   instead of fetching one from the metadata server.
+     */
+    public function __construct(
+        ?Iam $iam = null,
+        $scope = null,
+        $targetAudience = null,
+        $quotaProject = null,
+        $serviceAccountIdentity = null,
+        ?string $universeDomain = null
+    ) {
+        $this->iam = $iam;
+
+        if ($scope && $targetAudience) {
+            throw new InvalidArgumentException(
+                'Scope and targetAudience cannot both be supplied'
+            );
+        }
+
+        $tokenUri = self::getTokenUri($serviceAccountIdentity);
+        if ($scope) {
+            if (is_string($scope)) {
+                $scope = explode(' ', $scope);
+            }
+
+            $scope = implode(',', $scope);
+
+            $tokenUri = $tokenUri . '?scopes=' . $scope;
+        } elseif ($targetAudience) {
+            $tokenUri = self::getIdTokenUri($serviceAccountIdentity);
+            $tokenUri = $tokenUri . '?audience=' . $targetAudience;
+            $this->targetAudience = $targetAudience;
+        }
+
+        $this->tokenUri = $tokenUri;
+        $this->quotaProject = $quotaProject;
+        $this->serviceAccountIdentity = $serviceAccountIdentity;
+        $this->universeDomain = $universeDomain;
+    }
+
+    /**
+     * The full uri for accessing the default token.
+     *
+     * @param string $serviceAccountIdentity [optional] Specify a service
+     *   account identity name to use instead of "default".
+     * @return string
+     */
+    public static function getTokenUri($serviceAccountIdentity = null)
+    {
+        $base = 'http://' . self::METADATA_IP . '/computeMetadata/';
+        $base .= self::TOKEN_URI_PATH;
+
+        if ($serviceAccountIdentity) {
+            return str_replace(
+                '/default/',
+                '/' . $serviceAccountIdentity . '/',
+                $base
+            );
+        }
+        return $base;
+    }
+
+    /**
+     * The full uri for accessing the default service account.
+     *
+     * @param string $serviceAccountIdentity [optional] Specify a service
+     *   account identity name to use instead of "default".
+     * @return string
+     */
+    public static function getClientNameUri($serviceAccountIdentity = null)
+    {
+        $base = 'http://' . self::METADATA_IP . '/computeMetadata/';
+        $base .= self::CLIENT_ID_URI_PATH;
+
+        if ($serviceAccountIdentity) {
+            return str_replace(
+                '/default/',
+                '/' . $serviceAccountIdentity . '/',
+                $base
+            );
+        }
+
+        return $base;
+    }
+
+    /**
+     * The full uri for accesesing the default identity token.
+     *
+     * @param string $serviceAccountIdentity [optional] Specify a service
+     *   account identity name to use instead of "default".
+     * @return string
+     */
+    private static function getIdTokenUri($serviceAccountIdentity = null)
+    {
+        $base = 'http://' . self::METADATA_IP . '/computeMetadata/';
+        $base .= self::ID_TOKEN_URI_PATH;
+
+        if ($serviceAccountIdentity) {
+            return str_replace(
+                '/default/',
+                '/' . $serviceAccountIdentity . '/',
+                $base
+            );
+        }
+
+        return $base;
+    }
+
+    /**
+     * The full uri for accessing the default project ID.
+     *
+     * @return string
+     */
+    private static function getProjectIdUri()
+    {
+        $base = 'http://' . self::METADATA_IP . '/computeMetadata/';
+
+        return $base . self::PROJECT_ID_URI_PATH;
+    }
+
+    /**
+     * The full uri for accessing the default universe domain.
+     *
+     * @return string
+     */
+    private static function getUniverseDomainUri()
+    {
+        $base = 'http://' . self::METADATA_IP . '/computeMetadata/';
+
+        return $base . self::UNIVERSE_DOMAIN_URI_PATH;
+    }
+
+    /**
+     * Determines if this an App Engine Flexible instance, by accessing the
+     * GAE_INSTANCE environment variable.
+     *
+     * @return bool true if this an App Engine Flexible Instance, false otherwise
+     */
+    public static function onAppEngineFlexible()
+    {
+        return substr((string) getenv('GAE_INSTANCE'), 0, 4) === 'aef-';
+    }
+
+    /**
+     * Determines if this a GCE instance, by accessing the expected metadata
+     * host.
+     * If $httpHandler is not specified a the default HttpHandler is used.
+     *
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @return bool True if this a GCEInstance, false otherwise
+     */
+    public static function onGce(?callable $httpHandler = null)
+    {
+        $httpHandler = $httpHandler
+            ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+
+        $checkUri = 'http://' . self::METADATA_IP;
+        for ($i = 1; $i <= self::MAX_COMPUTE_PING_TRIES; $i++) {
+            try {
+                // Comment from: oauth2client/client.py
+                //
+                // Note: the explicit `timeout` below is a workaround. The underlying
+                // issue is that resolving an unknown host on some networks will take
+                // 20-30 seconds; making this timeout short fixes the issue, but
+                // could lead to false negatives in the event that we are on GCE, but
+                // the metadata resolution was particularly slow. The latter case is
+                // "unlikely".
+                $resp = $httpHandler(
+                    new Request(
+                        'GET',
+                        $checkUri,
+                        [
+                            self::FLAVOR_HEADER => 'Google',
+                            self::$metricMetadataKey => self::getMetricsHeader('', 'mds')
+                        ]
+                    ),
+                    ['timeout' => self::COMPUTE_PING_CONNECTION_TIMEOUT_S]
+                );
+
+                return $resp->getHeaderLine(self::FLAVOR_HEADER) == 'Google';
+            } catch (ClientException $e) {
+            } catch (ServerException $e) {
+            } catch (RequestException $e) {
+            } catch (ConnectException $e) {
+            }
+        }
+
+        if (PHP_OS === 'Windows' || PHP_OS === 'WINNT') {
+            return self::detectResidencyWindows(
+                self::WINDOWS_REGISTRY_KEY_PATH . self::WINDOWS_REGISTRY_KEY_NAME
+            );
+        }
+
+        // Detect GCE residency on Linux
+        return self::detectResidencyLinux(self::GKE_PRODUCT_NAME_FILE);
+    }
+
+    private static function detectResidencyLinux(string $productNameFile): bool
+    {
+        if (file_exists($productNameFile)) {
+            $productName = trim((string) file_get_contents($productNameFile));
+            return 0 === strpos($productName, self::PRODUCT_NAME);
+        }
+        return false;
+    }
+
+    private static function detectResidencyWindows(string $registryProductKey): bool
+    {
+        if (!class_exists(COM::class)) {
+            // the COM extension must be installed and enabled to detect Windows residency
+            // see https://www.php.net/manual/en/book.com.php
+            return false;
+        }
+
+        $shell = new COM('WScript.Shell');
+        $productName = null;
+
+        try {
+            $productName = $shell->regRead($registryProductKey);
+        } catch (com_exception) {
+            // This means that we tried to read a key that doesn't exist on the registry
+            // which might mean that it is a windows instance that is not on GCE
+            return false;
+        }
+
+        return 0 === strpos($productName, self::PRODUCT_NAME);
+    }
+
+    /**
+     * Implements FetchAuthTokenInterface#fetchAuthToken.
+     *
+     * Fetches the auth tokens from the GCE metadata host if it is available.
+     * If $httpHandler is not specified a the default HttpHandler is used.
+     *
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     *
+     * @return array<mixed> {
+     *     A set of auth related metadata, based on the token type.
+     *
+     *     @type string $access_token for access tokens
+     *     @type int    $expires_in   for access tokens
+     *     @type string $token_type   for access tokens
+     *     @type string $id_token     for ID tokens
+     * }
+     * @throws \Exception
+     */
+    public function fetchAuthToken(?callable $httpHandler = null)
+    {
+        $httpHandler = $httpHandler
+            ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+
+        if (!$this->hasCheckedOnGce) {
+            $this->isOnGce = self::onGce($httpHandler);
+            $this->hasCheckedOnGce = true;
+        }
+        if (!$this->isOnGce) {
+            return [];  // return an empty array with no access token
+        }
+
+        $response = $this->getFromMetadata(
+            $httpHandler,
+            $this->tokenUri,
+            $this->applyTokenEndpointMetrics([], $this->targetAudience ? 'it' : 'at')
+        );
+
+        if ($this->targetAudience) {
+            return $this->lastReceivedToken = ['id_token' => $response];
+        }
+
+        if (null === $json = json_decode($response, true)) {
+            throw new \Exception('Invalid JSON response');
+        }
+
+        $json['expires_at'] = time() + $json['expires_in'];
+
+        // store this so we can retrieve it later
+        $this->lastReceivedToken = $json;
+
+        return $json;
+    }
+
+    /**
+     * Returns the Cache Key for the credential token.
+     * The format for the cache key is:
+     * TokenURI
+     *
+     * @return string
+     */
+    public function getCacheKey()
+    {
+        return $this->tokenUri;
+    }
+
+    /**
+     * @return array<mixed>|null
+     */
+    public function getLastReceivedToken()
+    {
+        if ($this->lastReceivedToken) {
+            if (array_key_exists('id_token', $this->lastReceivedToken)) {
+                return $this->lastReceivedToken;
+            }
+
+            return [
+                'access_token' => $this->lastReceivedToken['access_token'],
+                'expires_at' => $this->lastReceivedToken['expires_at']
+            ];
+        }
+
+        return null;
+    }
+
+    /**
+     * Get the client name from GCE metadata.
+     *
+     * Subsequent calls will return a cached value.
+     *
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @return string
+     */
+    public function getClientName(?callable $httpHandler = null)
+    {
+        if ($this->clientName) {
+            return $this->clientName;
+        }
+
+        $httpHandler = $httpHandler
+            ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+
+        if (!$this->hasCheckedOnGce) {
+            $this->isOnGce = self::onGce($httpHandler);
+            $this->hasCheckedOnGce = true;
+        }
+
+        if (!$this->isOnGce) {
+            return '';
+        }
+
+        $this->clientName = $this->getFromMetadata(
+            $httpHandler,
+            self::getClientNameUri($this->serviceAccountIdentity)
+        );
+
+        return $this->clientName;
+    }
+
+    /**
+     * Fetch the default Project ID from compute engine.
+     *
+     * Returns null if called outside GCE.
+     *
+     * @param callable|null $httpHandler Callback which delivers psr7 request
+     * @return string|null
+     */
+    public function getProjectId(?callable $httpHandler = null)
+    {
+        if ($this->projectId) {
+            return $this->projectId;
+        }
+
+        $httpHandler = $httpHandler
+            ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+
+        if (!$this->hasCheckedOnGce) {
+            $this->isOnGce = self::onGce($httpHandler);
+            $this->hasCheckedOnGce = true;
+        }
+
+        if (!$this->isOnGce) {
+            return null;
+        }
+
+        $this->projectId = $this->getFromMetadata($httpHandler, self::getProjectIdUri());
+        return $this->projectId;
+    }
+
+    /**
+     * Fetch the default universe domain from the metadata server.
+     *
+     * @param callable|null $httpHandler Callback which delivers psr7 request
+     * @return string
+     */
+    public function getUniverseDomain(?callable $httpHandler = null): string
+    {
+        if (null !== $this->universeDomain) {
+            return $this->universeDomain;
+        }
+
+        $httpHandler = $httpHandler
+            ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+
+        if (!$this->hasCheckedOnGce) {
+            $this->isOnGce = self::onGce($httpHandler);
+            $this->hasCheckedOnGce = true;
+        }
+
+        try {
+            $this->universeDomain = $this->getFromMetadata(
+                $httpHandler,
+                self::getUniverseDomainUri()
+            );
+        } catch (ClientException $e) {
+            // If the metadata server exists, but returns a 404 for the universe domain, the auth
+            // libraries should safely assume this is an older metadata server running in GCU, and
+            // should return the default universe domain.
+            if (!$e->hasResponse() || 404 != $e->getResponse()->getStatusCode()) {
+                throw $e;
+            }
+            $this->universeDomain = self::DEFAULT_UNIVERSE_DOMAIN;
+        }
+
+        // We expect in some cases the metadata server will return an empty string for the universe
+        // domain. In this case, the auth library MUST return the default universe domain.
+        if ('' === $this->universeDomain) {
+            $this->universeDomain = self::DEFAULT_UNIVERSE_DOMAIN;
+        }
+
+        return $this->universeDomain;
+    }
+
+    /**
+     * Fetch the value of a GCE metadata server URI.
+     *
+     * @param callable $httpHandler An HTTP Handler to deliver PSR7 requests.
+     * @param string $uri The metadata URI.
+     * @param array<mixed> $headers [optional] If present, add these headers to the token
+     *        endpoint request.
+     *
+     * @return string
+     */
+    private function getFromMetadata(callable $httpHandler, $uri, array $headers = [])
+    {
+        $resp = $httpHandler(
+            new Request(
+                'GET',
+                $uri,
+                [self::FLAVOR_HEADER => 'Google'] + $headers
+            )
+        );
+
+        return (string) $resp->getBody();
+    }
+
+    /**
+     * Get the quota project used for this API request
+     *
+     * @return string|null
+     */
+    public function getQuotaProject()
+    {
+        return $this->quotaProject;
+    }
+
+    /**
+     * Set whether or not we've already checked the GCE environment.
+     *
+     * @param bool $isOnGce
+     *
+     * @return void
+     */
+    public function setIsOnGce($isOnGce)
+    {
+        // Implicitly set hasCheckedGce to true
+        $this->hasCheckedOnGce = true;
+
+        // Set isOnGce
+        $this->isOnGce = $isOnGce;
+    }
+
+    protected function getCredType(): string
+    {
+        return self::CRED_TYPE;
+    }
+}
Index: vendor/google/auth/src/Credentials/IAMCredentials.php
===================================================================
--- vendor/google/auth/src/Credentials/IAMCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Credentials/IAMCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,91 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Credentials;
+
+/**
+ * Authenticates requests using IAM credentials.
+ */
+class IAMCredentials
+{
+    const SELECTOR_KEY = 'x-goog-iam-authority-selector';
+    const TOKEN_KEY = 'x-goog-iam-authorization-token';
+
+    /**
+     * @var string
+     */
+    private $selector;
+
+    /**
+     * @var string
+     */
+    private $token;
+
+    /**
+     * @param string $selector the IAM selector
+     * @param string $token the IAM token
+     */
+    public function __construct($selector, $token)
+    {
+        if (!is_string($selector)) {
+            throw new \InvalidArgumentException(
+                'selector must be a string'
+            );
+        }
+        if (!is_string($token)) {
+            throw new \InvalidArgumentException(
+                'token must be a string'
+            );
+        }
+
+        $this->selector = $selector;
+        $this->token = $token;
+    }
+
+    /**
+     * export a callback function which updates runtime metadata.
+     *
+     * @return callable updateMetadata function
+     */
+    public function getUpdateMetadataFunc()
+    {
+        return [$this, 'updateMetadata'];
+    }
+
+    /**
+     * Updates metadata with the appropriate header metadata.
+     *
+     * @param array<mixed> $metadata metadata hashmap
+     * @param string $unusedAuthUri optional auth uri
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     *        Note: this param is unused here, only included here for
+     *        consistency with other credentials class
+     *
+     * @return array<mixed> updated metadata hashmap
+     */
+    public function updateMetadata(
+        $metadata,
+        $unusedAuthUri = null,
+        ?callable $httpHandler = null
+    ) {
+        $metadata_copy = $metadata;
+        $metadata_copy[self::SELECTOR_KEY] = $this->selector;
+        $metadata_copy[self::TOKEN_KEY] = $this->token;
+
+        return $metadata_copy;
+    }
+}
Index: vendor/google/auth/src/Credentials/ImpersonatedServiceAccountCredentials.php
===================================================================
--- vendor/google/auth/src/Credentials/ImpersonatedServiceAccountCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Credentials/ImpersonatedServiceAccountCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,156 @@
+<?php
+
+/*
+ * Copyright 2022 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Credentials;
+
+use Google\Auth\CredentialsLoader;
+use Google\Auth\IamSignerTrait;
+use Google\Auth\SignBlobInterface;
+
+class ImpersonatedServiceAccountCredentials extends CredentialsLoader implements SignBlobInterface
+{
+    use IamSignerTrait;
+
+    private const CRED_TYPE = 'imp';
+
+    /**
+     * @var string
+     */
+    protected $impersonatedServiceAccountName;
+
+    /**
+     * @var UserRefreshCredentials
+     */
+    protected $sourceCredentials;
+
+    /**
+     * Instantiate an instance of ImpersonatedServiceAccountCredentials from a credentials file that
+     * has be created with the --impersonated-service-account flag.
+     *
+     * @param string|string[]     $scope   The scope of the access request, expressed either as an
+     *                                     array or as a space-delimited string.
+     * @param string|array<mixed> $jsonKey JSON credential file path or JSON credentials
+     *                                     as an associative array.
+     */
+    public function __construct(
+        $scope,
+        $jsonKey
+    ) {
+        if (is_string($jsonKey)) {
+            if (!file_exists($jsonKey)) {
+                throw new \InvalidArgumentException('file does not exist');
+            }
+            $json = file_get_contents($jsonKey);
+            if (!$jsonKey = json_decode((string) $json, true)) {
+                throw new \LogicException('invalid json for auth config');
+            }
+        }
+        if (!array_key_exists('service_account_impersonation_url', $jsonKey)) {
+            throw new \LogicException(
+                'json key is missing the service_account_impersonation_url field'
+            );
+        }
+        if (!array_key_exists('source_credentials', $jsonKey)) {
+            throw new \LogicException('json key is missing the source_credentials field');
+        }
+
+        $this->impersonatedServiceAccountName = $this->getImpersonatedServiceAccountNameFromUrl(
+            $jsonKey['service_account_impersonation_url']
+        );
+
+        $this->sourceCredentials = new UserRefreshCredentials(
+            $scope,
+            $jsonKey['source_credentials']
+        );
+    }
+
+    /**
+     * Helper function for extracting the Server Account Name from the URL saved in the account
+     * credentials file.
+     *
+     * @param $serviceAccountImpersonationUrl string URL from "service_account_impersonation_url"
+     * @return string Service account email or ID.
+     */
+    private function getImpersonatedServiceAccountNameFromUrl(
+        string $serviceAccountImpersonationUrl
+    ): string {
+        $fields = explode('/', $serviceAccountImpersonationUrl);
+        $lastField = end($fields);
+        $splitter = explode(':', $lastField);
+        return $splitter[0];
+    }
+
+    /**
+     * Get the client name from the keyfile
+     *
+     * In this implementation, it will return the issuers email from the oauth token.
+     *
+     * @param callable|null $unusedHttpHandler not used by this credentials type.
+     * @return string Token issuer email
+     */
+    public function getClientName(?callable $unusedHttpHandler = null)
+    {
+        return $this->impersonatedServiceAccountName;
+    }
+
+    /**
+     * @param callable|null $httpHandler
+     *
+     * @return array<mixed> {
+     *     A set of auth related metadata, containing the following
+     *
+     *     @type string $access_token
+     *     @type int $expires_in
+     *     @type string $scope
+     *     @type string $token_type
+     *     @type string $id_token
+     * }
+     */
+    public function fetchAuthToken(?callable $httpHandler = null)
+    {
+        // We don't support id token endpoint requests as of now for Impersonated Cred
+        return $this->sourceCredentials->fetchAuthToken(
+            $httpHandler,
+            $this->applyTokenEndpointMetrics([], 'at')
+        );
+    }
+
+    /**
+     * Returns the Cache Key for the credentials
+     * The cache key is the same as the UserRefreshCredentials class
+     *
+     * @return string
+     */
+    public function getCacheKey()
+    {
+        return $this->sourceCredentials->getCacheKey();
+    }
+
+    /**
+     * @return array<mixed>
+     */
+    public function getLastReceivedToken()
+    {
+        return $this->sourceCredentials->getLastReceivedToken();
+    }
+
+    protected function getCredType(): string
+    {
+        return self::CRED_TYPE;
+    }
+}
Index: vendor/google/auth/src/Credentials/InsecureCredentials.php
===================================================================
--- vendor/google/auth/src/Credentials/InsecureCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Credentials/InsecureCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,68 @@
+<?php
+/*
+ * Copyright 2018 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Credentials;
+
+use Google\Auth\FetchAuthTokenInterface;
+
+/**
+ * Provides a set of credentials that will always return an empty access token.
+ * This is useful for APIs which do not require authentication, for local
+ * service emulators, and for testing.
+ */
+class InsecureCredentials implements FetchAuthTokenInterface
+{
+    /**
+     * @var array{access_token:string}
+     */
+    private $token = [
+        'access_token' => ''
+    ];
+
+    /**
+     * Fetches the auth token. In this case it returns an empty string.
+     *
+     * @param callable|null $httpHandler
+     * @return array{access_token:string} A set of auth related metadata
+     */
+    public function fetchAuthToken(?callable $httpHandler = null)
+    {
+        return $this->token;
+    }
+
+    /**
+     * Returns the cache key. In this case it returns a null value, disabling
+     * caching.
+     *
+     * @return string|null
+     */
+    public function getCacheKey()
+    {
+        return null;
+    }
+
+    /**
+     * Fetches the last received token. In this case, it returns the same empty string
+     * auth token.
+     *
+     * @return array{access_token:string}
+     */
+    public function getLastReceivedToken()
+    {
+        return $this->token;
+    }
+}
Index: vendor/google/auth/src/Credentials/ServiceAccountCredentials.php
===================================================================
--- vendor/google/auth/src/Credentials/ServiceAccountCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Credentials/ServiceAccountCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,453 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Credentials;
+
+use Firebase\JWT\JWT;
+use Google\Auth\CredentialsLoader;
+use Google\Auth\GetQuotaProjectInterface;
+use Google\Auth\Iam;
+use Google\Auth\OAuth2;
+use Google\Auth\ProjectIdProviderInterface;
+use Google\Auth\ServiceAccountSignerTrait;
+use Google\Auth\SignBlobInterface;
+use InvalidArgumentException;
+
+/**
+ * ServiceAccountCredentials supports authorization using a Google service
+ * account.
+ *
+ * (cf https://developers.google.com/accounts/docs/OAuth2ServiceAccount)
+ *
+ * It's initialized using the json key file that's downloadable from developer
+ * console, which should contain a private_key and client_email fields that it
+ * uses.
+ *
+ * Use it with AuthTokenMiddleware to authorize http requests:
+ *
+ *   use Google\Auth\Credentials\ServiceAccountCredentials;
+ *   use Google\Auth\Middleware\AuthTokenMiddleware;
+ *   use GuzzleHttp\Client;
+ *   use GuzzleHttp\HandlerStack;
+ *
+ *   $sa = new ServiceAccountCredentials(
+ *       'https://www.googleapis.com/auth/taskqueue',
+ *       '/path/to/your/json/key_file.json'
+ *   );
+ *   $middleware = new AuthTokenMiddleware($sa);
+ *   $stack = HandlerStack::create();
+ *   $stack->push($middleware);
+ *
+ *   $client = new Client([
+ *       'handler' => $stack,
+ *       'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
+ *       'auth' => 'google_auth' // authorize all requests
+ *   ]);
+ *
+ *   $res = $client->get('myproject/taskqueues/myqueue');
+ */
+class ServiceAccountCredentials extends CredentialsLoader implements
+    GetQuotaProjectInterface,
+    SignBlobInterface,
+    ProjectIdProviderInterface
+{
+    use ServiceAccountSignerTrait;
+
+    /**
+     * Used in observability metric headers
+     *
+     * @var string
+     */
+    private const CRED_TYPE = 'sa';
+    private const IAM_SCOPE = 'https://www.googleapis.com/auth/iam';
+
+    /**
+     * The OAuth2 instance used to conduct authorization.
+     *
+     * @var OAuth2
+     */
+    protected $auth;
+
+    /**
+     * The quota project associated with the JSON credentials
+     *
+     * @var string
+     */
+    protected $quotaProject;
+
+    /**
+     * @var string|null
+     */
+    protected $projectId;
+
+    /**
+     * @var array<mixed>|null
+     */
+    private $lastReceivedJwtAccessToken;
+
+    /**
+     * @var bool
+     */
+    private $useJwtAccessWithScope = false;
+
+    /**
+     * @var ServiceAccountJwtAccessCredentials|null
+     */
+    private $jwtAccessCredentials;
+
+    /**
+     * @var string
+     */
+    private string $universeDomain;
+
+    /**
+     * Create a new ServiceAccountCredentials.
+     *
+     * @param string|string[]|null $scope the scope of the access request, expressed
+     *   either as an Array or as a space-delimited String.
+     * @param string|array<mixed> $jsonKey JSON credential file path or JSON credentials
+     *   as an associative array
+     * @param string $sub an email address account to impersonate, in situations when
+     *   the service account has been delegated domain wide access.
+     * @param string $targetAudience The audience for the ID token.
+     */
+    public function __construct(
+        $scope,
+        $jsonKey,
+        $sub = null,
+        $targetAudience = null
+    ) {
+        if (is_string($jsonKey)) {
+            if (!file_exists($jsonKey)) {
+                throw new \InvalidArgumentException('file does not exist');
+            }
+            $jsonKeyStream = file_get_contents($jsonKey);
+            if (!$jsonKey = json_decode((string) $jsonKeyStream, true)) {
+                throw new \LogicException('invalid json for auth config');
+            }
+        }
+        if (!array_key_exists('client_email', $jsonKey)) {
+            throw new \InvalidArgumentException(
+                'json key is missing the client_email field'
+            );
+        }
+        if (!array_key_exists('private_key', $jsonKey)) {
+            throw new \InvalidArgumentException(
+                'json key is missing the private_key field'
+            );
+        }
+        if (array_key_exists('quota_project_id', $jsonKey)) {
+            $this->quotaProject = (string) $jsonKey['quota_project_id'];
+        }
+        if ($scope && $targetAudience) {
+            throw new InvalidArgumentException(
+                'Scope and targetAudience cannot both be supplied'
+            );
+        }
+        $additionalClaims = [];
+        if ($targetAudience) {
+            $additionalClaims = ['target_audience' => $targetAudience];
+        }
+        $this->auth = new OAuth2([
+            'audience' => self::TOKEN_CREDENTIAL_URI,
+            'issuer' => $jsonKey['client_email'],
+            'scope' => $scope,
+            'signingAlgorithm' => 'RS256',
+            'signingKey' => $jsonKey['private_key'],
+            'signingKeyId' => $jsonKey['private_key_id'] ?? null,
+            'sub' => $sub,
+            'tokenCredentialUri' => self::TOKEN_CREDENTIAL_URI,
+            'additionalClaims' => $additionalClaims,
+        ]);
+
+        $this->projectId = $jsonKey['project_id'] ?? null;
+        $this->universeDomain = $jsonKey['universe_domain'] ?? self::DEFAULT_UNIVERSE_DOMAIN;
+    }
+
+    /**
+     * When called, the ServiceAccountCredentials will use an instance of
+     * ServiceAccountJwtAccessCredentials to fetch (self-sign) an access token
+     * even when only scopes are supplied. Otherwise,
+     * ServiceAccountJwtAccessCredentials is only called when no scopes and an
+     * authUrl (audience) is suppled.
+     *
+     * @return void
+     */
+    public function useJwtAccessWithScope()
+    {
+        $this->useJwtAccessWithScope = true;
+    }
+
+    /**
+     * @param callable|null $httpHandler
+     *
+     * @return array<mixed> {
+     *     A set of auth related metadata, containing the following
+     *
+     *     @type string $access_token
+     *     @type int $expires_in
+     *     @type string $token_type
+     * }
+     */
+    public function fetchAuthToken(?callable $httpHandler = null)
+    {
+        if ($this->useSelfSignedJwt()) {
+            $jwtCreds = $this->createJwtAccessCredentials();
+
+            $accessToken = $jwtCreds->fetchAuthToken($httpHandler);
+
+            if ($lastReceivedToken = $jwtCreds->getLastReceivedToken()) {
+                // Keep self-signed JWTs in memory as the last received token
+                $this->lastReceivedJwtAccessToken = $lastReceivedToken;
+            }
+
+            return $accessToken;
+        }
+
+        if ($this->isIdTokenRequest() && $this->getUniverseDomain() !== self::DEFAULT_UNIVERSE_DOMAIN) {
+            $now = time();
+            $jwt = Jwt::encode(
+                [
+                    'iss' => $this->auth->getIssuer(),
+                    'sub' => $this->auth->getIssuer(),
+                    'scope' => self::IAM_SCOPE,
+                    'exp' => ($now + $this->auth->getExpiry()),
+                    'iat' => ($now - OAuth2::DEFAULT_SKEW_SECONDS),
+                ],
+                $this->auth->getSigningKey(),
+                $this->auth->getSigningAlgorithm(),
+                $this->auth->getSigningKeyId()
+            );
+            // We create a new instance of Iam each time because the `$httpHandler` might change.
+            $idToken = (new Iam($httpHandler, $this->getUniverseDomain()))->generateIdToken(
+                $this->auth->getIssuer(),
+                $this->auth->getAdditionalClaims()['target_audience'],
+                $jwt,
+                $this->applyTokenEndpointMetrics([], 'it')
+            );
+            return ['id_token' => $idToken];
+        }
+        return $this->auth->fetchAuthToken(
+            $httpHandler,
+            $this->applyTokenEndpointMetrics([], $this->isIdTokenRequest() ? 'it' : 'at')
+        );
+    }
+
+    /**
+     * Return the Cache Key for the credentials.
+     * For the cache key format is one of the following:
+     * ClientEmail.Scope[.Sub]
+     * ClientEmail.Audience[.Sub]
+     *
+     * @return string
+     */
+    public function getCacheKey()
+    {
+        $scopeOrAudience = $this->auth->getScope();
+        if (!$scopeOrAudience) {
+            $scopeOrAudience = $this->auth->getAudience();
+        }
+
+        $key = $this->auth->getIssuer() . '.' . $scopeOrAudience;
+        if ($sub = $this->auth->getSub()) {
+            $key .= '.' . $sub;
+        }
+
+        return $key;
+    }
+
+    /**
+     * @return array<mixed>
+     */
+    public function getLastReceivedToken()
+    {
+        // If self-signed JWTs are being used, fetch the last received token
+        // from memory. Else, fetch it from OAuth2
+        return $this->useSelfSignedJwt()
+            ? $this->lastReceivedJwtAccessToken
+            : $this->auth->getLastReceivedToken();
+    }
+
+    /**
+     * Get the project ID from the service account keyfile.
+     *
+     * Returns null if the project ID does not exist in the keyfile.
+     *
+     * @param callable|null $httpHandler Not used by this credentials type.
+     * @return string|null
+     */
+    public function getProjectId(?callable $httpHandler = null)
+    {
+        return $this->projectId;
+    }
+
+    /**
+     * Updates metadata with the authorization token.
+     *
+     * @param array<mixed> $metadata metadata hashmap
+     * @param string $authUri optional auth uri
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @return array<mixed> updated metadata hashmap
+     */
+    public function updateMetadata(
+        $metadata,
+        $authUri = null,
+        ?callable $httpHandler = null
+    ) {
+        // scope exists. use oauth implementation
+        if (!$this->useSelfSignedJwt()) {
+            return parent::updateMetadata($metadata, $authUri, $httpHandler);
+        }
+
+        $jwtCreds = $this->createJwtAccessCredentials();
+        if ($this->auth->getScope()) {
+            // Prefer user-provided "scope" to "audience"
+            $updatedMetadata = $jwtCreds->updateMetadata($metadata, null, $httpHandler);
+        } else {
+            $updatedMetadata = $jwtCreds->updateMetadata($metadata, $authUri, $httpHandler);
+        }
+
+        if ($lastReceivedToken = $jwtCreds->getLastReceivedToken()) {
+            // Keep self-signed JWTs in memory as the last received token
+            $this->lastReceivedJwtAccessToken = $lastReceivedToken;
+        }
+
+        return $updatedMetadata;
+    }
+
+    /**
+     * @return ServiceAccountJwtAccessCredentials
+     */
+    private function createJwtAccessCredentials()
+    {
+        if (!$this->jwtAccessCredentials) {
+            // Create credentials for self-signing a JWT (JwtAccess)
+            $credJson = [
+                'private_key' => $this->auth->getSigningKey(),
+                'client_email' => $this->auth->getIssuer(),
+            ];
+            $this->jwtAccessCredentials = new ServiceAccountJwtAccessCredentials(
+                $credJson,
+                $this->auth->getScope()
+            );
+        }
+
+        return $this->jwtAccessCredentials;
+    }
+
+    /**
+     * @param string $sub an email address account to impersonate, in situations when
+     *   the service account has been delegated domain wide access.
+     * @return void
+     */
+    public function setSub($sub)
+    {
+        $this->auth->setSub($sub);
+    }
+
+    /**
+     * Get the client name from the keyfile.
+     *
+     * In this case, it returns the keyfile's client_email key.
+     *
+     * @param callable|null $httpHandler Not used by this credentials type.
+     * @return string
+     */
+    public function getClientName(?callable $httpHandler = null)
+    {
+        return $this->auth->getIssuer();
+    }
+
+    /**
+     * Get the private key from the keyfile.
+     *
+     * In this case, it returns the keyfile's private_key key, needed for JWT signing.
+     *
+     * @return string
+     */
+    public function getPrivateKey()
+    {
+        return $this->auth->getSigningKey();
+    }
+
+    /**
+     * Get the quota project used for this API request
+     *
+     * @return string|null
+     */
+    public function getQuotaProject()
+    {
+        return $this->quotaProject;
+    }
+
+    /**
+     * Get the universe domain configured in the JSON credential.
+     *
+     * @return string
+     */
+    public function getUniverseDomain(): string
+    {
+        return $this->universeDomain;
+    }
+
+    protected function getCredType(): string
+    {
+        return self::CRED_TYPE;
+    }
+
+    /**
+     * @return bool
+     */
+    private function useSelfSignedJwt()
+    {
+        // When a sub is supplied, the user is using domain-wide delegation, which not available
+        // with self-signed JWTs
+        if (null !== $this->auth->getSub()) {
+            // If we are outside the GDU, we can't use domain-wide delegation
+            if ($this->getUniverseDomain() !== self::DEFAULT_UNIVERSE_DOMAIN) {
+                throw new \LogicException(sprintf(
+                    'Service Account subject is configured for the credential. Domain-wide ' .
+                    'delegation is not supported in universes other than %s.',
+                    self::DEFAULT_UNIVERSE_DOMAIN
+                ));
+            }
+            return false;
+        }
+
+        // Do not use self-signed JWT for ID tokens
+        if ($this->isIdTokenRequest()) {
+            return false;
+        }
+
+        // When true, ServiceAccountCredentials will always use JwtAccess for access tokens
+        if ($this->useJwtAccessWithScope) {
+            return true;
+        }
+
+        // If the universe domain is outside the GDU, use JwtAccess for access tokens
+        if ($this->getUniverseDomain() !== self::DEFAULT_UNIVERSE_DOMAIN) {
+            return true;
+        }
+
+        return is_null($this->auth->getScope());
+    }
+
+    private function isIdTokenRequest(): bool
+    {
+        return !empty($this->auth->getAdditionalClaims()['target_audience']);
+    }
+}
Index: vendor/google/auth/src/Credentials/ServiceAccountJwtAccessCredentials.php
===================================================================
--- vendor/google/auth/src/Credentials/ServiceAccountJwtAccessCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Credentials/ServiceAccountJwtAccessCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,246 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Credentials;
+
+use Google\Auth\CredentialsLoader;
+use Google\Auth\GetQuotaProjectInterface;
+use Google\Auth\OAuth2;
+use Google\Auth\ProjectIdProviderInterface;
+use Google\Auth\ServiceAccountSignerTrait;
+use Google\Auth\SignBlobInterface;
+
+/**
+ * Authenticates requests using Google's Service Account credentials via
+ * JWT Access.
+ *
+ * This class allows authorizing requests for service accounts directly
+ * from credentials from a json key file downloaded from the developer
+ * console (via 'Generate new Json Key').  It is not part of any OAuth2
+ * flow, rather it creates a JWT and sends that as a credential.
+ */
+class ServiceAccountJwtAccessCredentials extends CredentialsLoader implements
+    GetQuotaProjectInterface,
+    SignBlobInterface,
+    ProjectIdProviderInterface
+{
+    use ServiceAccountSignerTrait;
+
+    /**
+     * Used in observability metric headers
+     *
+     * @var string
+     */
+    private const CRED_TYPE = 'jwt';
+
+    /**
+     * The OAuth2 instance used to conduct authorization.
+     *
+     * @var OAuth2
+     */
+    protected $auth;
+
+    /**
+     * The quota project associated with the JSON credentials
+     *
+     * @var string
+     */
+    protected $quotaProject;
+
+    /**
+     * @var string
+     */
+    public $projectId;
+
+    /**
+     * Create a new ServiceAccountJwtAccessCredentials.
+     *
+     * @param string|array<mixed> $jsonKey JSON credential file path or JSON credentials
+     *   as an associative array
+     * @param string|string[] $scope the scope of the access request, expressed
+     *   either as an Array or as a space-delimited String.
+     */
+    public function __construct($jsonKey, $scope = null)
+    {
+        if (is_string($jsonKey)) {
+            if (!file_exists($jsonKey)) {
+                throw new \InvalidArgumentException('file does not exist');
+            }
+            $jsonKeyStream = file_get_contents($jsonKey);
+            if (!$jsonKey = json_decode((string) $jsonKeyStream, true)) {
+                throw new \LogicException('invalid json for auth config');
+            }
+        }
+        if (!array_key_exists('client_email', $jsonKey)) {
+            throw new \InvalidArgumentException(
+                'json key is missing the client_email field'
+            );
+        }
+        if (!array_key_exists('private_key', $jsonKey)) {
+            throw new \InvalidArgumentException(
+                'json key is missing the private_key field'
+            );
+        }
+        if (array_key_exists('quota_project_id', $jsonKey)) {
+            $this->quotaProject = (string) $jsonKey['quota_project_id'];
+        }
+        $this->auth = new OAuth2([
+            'issuer' => $jsonKey['client_email'],
+            'sub' => $jsonKey['client_email'],
+            'signingAlgorithm' => 'RS256',
+            'signingKey' => $jsonKey['private_key'],
+            'scope' => $scope,
+        ]);
+
+        $this->projectId = $jsonKey['project_id'] ?? null;
+    }
+
+    /**
+     * Updates metadata with the authorization token.
+     *
+     * @param array<mixed> $metadata metadata hashmap
+     * @param string $authUri optional auth uri
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @return array<mixed> updated metadata hashmap
+     */
+    public function updateMetadata(
+        $metadata,
+        $authUri = null,
+        ?callable $httpHandler = null
+    ) {
+        $scope = $this->auth->getScope();
+        if (empty($authUri) && empty($scope)) {
+            return $metadata;
+        }
+
+        $this->auth->setAudience($authUri);
+
+        return parent::updateMetadata($metadata, $authUri, $httpHandler);
+    }
+
+    /**
+     * Implements FetchAuthTokenInterface#fetchAuthToken.
+     *
+     * @param callable|null $httpHandler
+     *
+     * @return null|array{access_token:string} A set of auth related metadata
+     */
+    public function fetchAuthToken(?callable $httpHandler = null)
+    {
+        $audience = $this->auth->getAudience();
+        $scope = $this->auth->getScope();
+        if (empty($audience) && empty($scope)) {
+            return null;
+        }
+
+        if (!empty($audience) && !empty($scope)) {
+            throw new \UnexpectedValueException(
+                'Cannot sign both audience and scope in JwtAccess'
+            );
+        }
+
+        $access_token = $this->auth->toJwt();
+
+        // Set the self-signed access token in OAuth2 for getLastReceivedToken
+        $this->auth->setAccessToken($access_token);
+
+        return [
+            'access_token' => $access_token,
+            'expires_in' => $this->auth->getExpiry(),
+            'token_type' => 'Bearer'
+        ];
+    }
+
+    /**
+     * Return the cache key for the credentials.
+     * The format for the Cache Key one of the following:
+     * ClientEmail.Scope
+     * ClientEmail.Audience
+     *
+     * @return string
+     */
+    public function getCacheKey()
+    {
+        $scopeOrAudience = $this->auth->getScope();
+        if (!$scopeOrAudience) {
+            $scopeOrAudience = $this->auth->getAudience();
+        }
+
+        return $this->auth->getIssuer() . '.' . $scopeOrAudience;
+    }
+
+    /**
+     * @return array<mixed>
+     */
+    public function getLastReceivedToken()
+    {
+        return $this->auth->getLastReceivedToken();
+    }
+
+    /**
+     * Get the project ID from the service account keyfile.
+     *
+     * Returns null if the project ID does not exist in the keyfile.
+     *
+     * @param callable|null $httpHandler Not used by this credentials type.
+     * @return string|null
+     */
+    public function getProjectId(?callable $httpHandler = null)
+    {
+        return $this->projectId;
+    }
+
+    /**
+     * Get the client name from the keyfile.
+     *
+     * In this case, it returns the keyfile's client_email key.
+     *
+     * @param callable|null $httpHandler Not used by this credentials type.
+     * @return string
+     */
+    public function getClientName(?callable $httpHandler = null)
+    {
+        return $this->auth->getIssuer();
+    }
+
+    /**
+     * Get the private key from the keyfile.
+     *
+     * In this case, it returns the keyfile's private_key key, needed for JWT signing.
+     *
+     * @return string
+     */
+    public function getPrivateKey()
+    {
+        return $this->auth->getSigningKey();
+    }
+
+    /**
+     * Get the quota project used for this API request
+     *
+     * @return string|null
+     */
+    public function getQuotaProject()
+    {
+        return $this->quotaProject;
+    }
+
+    protected function getCredType(): string
+    {
+        return self::CRED_TYPE;
+    }
+}
Index: vendor/google/auth/src/Credentials/UserRefreshCredentials.php
===================================================================
--- vendor/google/auth/src/Credentials/UserRefreshCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Credentials/UserRefreshCredentials.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,202 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Credentials;
+
+use Google\Auth\CredentialsLoader;
+use Google\Auth\GetQuotaProjectInterface;
+use Google\Auth\OAuth2;
+use InvalidArgumentException;
+use LogicException;
+
+/**
+ * Authenticates requests using User Refresh credentials.
+ *
+ * This class allows authorizing requests from user refresh tokens.
+ *
+ * This the end of the result of a 3LO flow.  E.g, the end result of
+ * 'gcloud auth login' saves a file with these contents in well known
+ * location
+ *
+ * @see [Application Default Credentials](http://goo.gl/mkAHpZ)
+ */
+class UserRefreshCredentials extends CredentialsLoader implements GetQuotaProjectInterface
+{
+    /**
+     * Used in observability metric headers
+     *
+     * @var string
+     */
+    private const CRED_TYPE = 'u';
+
+    /**
+     * The OAuth2 instance used to conduct authorization.
+     *
+     * @var OAuth2
+     */
+    protected $auth;
+
+    /**
+     * The quota project associated with the JSON credentials
+     *
+     * @var string
+     */
+    protected $quotaProject;
+
+    /**
+     * Whether this is an ID token request or an access token request. Used when
+     * building the metric header.
+     */
+    private bool $isIdTokenRequest = false;
+
+    /**
+     * Create a new UserRefreshCredentials.
+     *
+     * @param string|string[]|null $scope the scope of the access request, expressed
+     *   either as an Array or as a space-delimited String.
+     * @param string|array<mixed> $jsonKey JSON credential file path or JSON credentials
+     *   as an associative array
+     * @param string|null $targetAudience The audience for the ID token.
+     */
+    public function __construct(
+        $scope,
+        $jsonKey,
+        string $targetAudience = null
+    ) {
+        if (is_string($jsonKey)) {
+            if (!file_exists($jsonKey)) {
+                throw new InvalidArgumentException('file does not exist or is unreadable');
+            }
+            $json = file_get_contents($jsonKey);
+            if (!$jsonKey = json_decode((string) $json, true)) {
+                throw new LogicException('invalid json for auth config');
+            }
+        }
+        if (!array_key_exists('client_id', $jsonKey)) {
+            throw new InvalidArgumentException(
+                'json key is missing the client_id field'
+            );
+        }
+        if (!array_key_exists('client_secret', $jsonKey)) {
+            throw new InvalidArgumentException(
+                'json key is missing the client_secret field'
+            );
+        }
+        if (!array_key_exists('refresh_token', $jsonKey)) {
+            throw new InvalidArgumentException(
+                'json key is missing the refresh_token field'
+            );
+        }
+        if ($scope && $targetAudience) {
+            throw new InvalidArgumentException(
+                'Scope and targetAudience cannot both be supplied'
+            );
+        }
+        $additionalClaims = [];
+        if ($targetAudience) {
+            $additionalClaims = ['target_audience' => $targetAudience];
+            $this->isIdTokenRequest = true;
+        }
+        $this->auth = new OAuth2([
+            'clientId' => $jsonKey['client_id'],
+            'clientSecret' => $jsonKey['client_secret'],
+            'refresh_token' => $jsonKey['refresh_token'],
+            'scope' => $scope,
+            'tokenCredentialUri' => self::TOKEN_CREDENTIAL_URI,
+            'additionalClaims' => $additionalClaims,
+        ]);
+        if (array_key_exists('quota_project_id', $jsonKey)) {
+            $this->quotaProject = (string) $jsonKey['quota_project_id'];
+        }
+    }
+
+    /**
+     * @param callable|null $httpHandler
+     * @param array<mixed> $metricsHeader [optional] Metrics headers to be inserted
+     *     into the token endpoint request present.
+     *     This could be passed from ImersonatedServiceAccountCredentials as it uses
+     *     UserRefreshCredentials as source credentials.
+     *
+     * @return array<mixed> {
+     *     A set of auth related metadata, containing the following
+     *
+     *     @type string $access_token
+     *     @type int $expires_in
+     *     @type string $scope
+     *     @type string $token_type
+     *     @type string $id_token
+     * }
+     */
+    public function fetchAuthToken(?callable $httpHandler = null, array $metricsHeader = [])
+    {
+        return $this->auth->fetchAuthToken(
+            $httpHandler,
+            $this->applyTokenEndpointMetrics($metricsHeader, $this->isIdTokenRequest ? 'it' : 'at')
+        );
+    }
+
+    /**
+     * Return the Cache Key for the credentials.
+     * The format for the Cache key is one of the following:
+     * ClientId.Scope
+     * ClientId.Audience
+     *
+     * @return string
+     */
+    public function getCacheKey()
+    {
+        $scopeOrAudience = $this->auth->getScope();
+        if (!$scopeOrAudience) {
+            $scopeOrAudience = $this->auth->getAudience();
+        }
+
+        return $this->auth->getClientId() . '.' . $scopeOrAudience;
+    }
+
+    /**
+     * @return array<mixed>
+     */
+    public function getLastReceivedToken()
+    {
+        return $this->auth->getLastReceivedToken();
+    }
+
+    /**
+     * Get the quota project used for this API request
+     *
+     * @return string|null
+     */
+    public function getQuotaProject()
+    {
+        return $this->quotaProject;
+    }
+
+    /**
+     * Get the granted scopes (if they exist) for the last fetched token.
+     *
+     * @return string|null
+     */
+    public function getGrantedScope()
+    {
+        return $this->auth->getGrantedScope();
+    }
+
+    protected function getCredType(): string
+    {
+        return self::CRED_TYPE;
+    }
+}
Index: vendor/google/auth/src/CredentialsLoader.php
===================================================================
--- vendor/google/auth/src/CredentialsLoader.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/CredentialsLoader.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,288 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+use Google\Auth\Credentials\ExternalAccountCredentials;
+use Google\Auth\Credentials\ImpersonatedServiceAccountCredentials;
+use Google\Auth\Credentials\InsecureCredentials;
+use Google\Auth\Credentials\ServiceAccountCredentials;
+use Google\Auth\Credentials\UserRefreshCredentials;
+use RuntimeException;
+use UnexpectedValueException;
+
+/**
+ * CredentialsLoader contains the behaviour used to locate and find default
+ * credentials files on the file system.
+ */
+abstract class CredentialsLoader implements
+    GetUniverseDomainInterface,
+    FetchAuthTokenInterface,
+    UpdateMetadataInterface
+{
+    use UpdateMetadataTrait;
+
+    const TOKEN_CREDENTIAL_URI = 'https://oauth2.googleapis.com/token';
+    const ENV_VAR = 'GOOGLE_APPLICATION_CREDENTIALS';
+    const QUOTA_PROJECT_ENV_VAR = 'GOOGLE_CLOUD_QUOTA_PROJECT';
+    const WELL_KNOWN_PATH = 'gcloud/application_default_credentials.json';
+    const NON_WINDOWS_WELL_KNOWN_PATH_BASE = '.config';
+    const MTLS_WELL_KNOWN_PATH = '.secureConnect/context_aware_metadata.json';
+    const MTLS_CERT_ENV_VAR = 'GOOGLE_API_USE_CLIENT_CERTIFICATE';
+
+    /**
+     * @param string $cause
+     * @return string
+     */
+    private static function unableToReadEnv($cause)
+    {
+        $msg = 'Unable to read the credential file specified by ';
+        $msg .= ' GOOGLE_APPLICATION_CREDENTIALS: ';
+        $msg .= $cause;
+
+        return $msg;
+    }
+
+    /**
+     * @return bool
+     */
+    private static function isOnWindows()
+    {
+        return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
+    }
+
+    /**
+     * Load a JSON key from the path specified in the environment.
+     *
+     * Load a JSON key from the path specified in the environment
+     * variable GOOGLE_APPLICATION_CREDENTIALS. Return null if
+     * GOOGLE_APPLICATION_CREDENTIALS is not specified.
+     *
+     * @return array<mixed>|null JSON key | null
+     */
+    public static function fromEnv()
+    {
+        $path = getenv(self::ENV_VAR);
+        if (empty($path)) {
+            return null;
+        }
+        if (!file_exists($path)) {
+            $cause = 'file ' . $path . ' does not exist';
+            throw new \DomainException(self::unableToReadEnv($cause));
+        }
+        $jsonKey = file_get_contents($path);
+        return json_decode((string) $jsonKey, true);
+    }
+
+    /**
+     * Load a JSON key from a well known path.
+     *
+     * The well known path is OS dependent:
+     *
+     * * windows: %APPDATA%/gcloud/application_default_credentials.json
+     * * others: $HOME/.config/gcloud/application_default_credentials.json
+     *
+     * If the file does not exist, this returns null.
+     *
+     * @return array<mixed>|null JSON key | null
+     */
+    public static function fromWellKnownFile()
+    {
+        $rootEnv = self::isOnWindows() ? 'APPDATA' : 'HOME';
+        $path = [getenv($rootEnv)];
+        if (!self::isOnWindows()) {
+            $path[] = self::NON_WINDOWS_WELL_KNOWN_PATH_BASE;
+        }
+        $path[] = self::WELL_KNOWN_PATH;
+        $path = implode(DIRECTORY_SEPARATOR, $path);
+        if (!file_exists($path)) {
+            return null;
+        }
+        $jsonKey = file_get_contents($path);
+        return json_decode((string) $jsonKey, true);
+    }
+
+    /**
+     * Create a new Credentials instance.
+     *
+     * @param string|string[] $scope the scope of the access request, expressed
+     *        either as an Array or as a space-delimited String.
+     * @param array<mixed> $jsonKey the JSON credentials.
+     * @param string|string[] $defaultScope The default scope to use if no
+     *   user-defined scopes exist, expressed either as an Array or as a
+     *   space-delimited string.
+     *
+     * @return ServiceAccountCredentials|UserRefreshCredentials|ImpersonatedServiceAccountCredentials|ExternalAccountCredentials
+     */
+    public static function makeCredentials(
+        $scope,
+        array $jsonKey,
+        $defaultScope = null
+    ) {
+        if (!array_key_exists('type', $jsonKey)) {
+            throw new \InvalidArgumentException('json key is missing the type field');
+        }
+
+        if ($jsonKey['type'] == 'service_account') {
+            // Do not pass $defaultScope to ServiceAccountCredentials
+            return new ServiceAccountCredentials($scope, $jsonKey);
+        }
+
+        if ($jsonKey['type'] == 'authorized_user') {
+            $anyScope = $scope ?: $defaultScope;
+            return new UserRefreshCredentials($anyScope, $jsonKey);
+        }
+
+        if ($jsonKey['type'] == 'impersonated_service_account') {
+            $anyScope = $scope ?: $defaultScope;
+            return new ImpersonatedServiceAccountCredentials($anyScope, $jsonKey);
+        }
+
+        if ($jsonKey['type'] == 'external_account') {
+            $anyScope = $scope ?: $defaultScope;
+            return new ExternalAccountCredentials($anyScope, $jsonKey);
+        }
+
+        throw new \InvalidArgumentException('invalid value in the type field');
+    }
+
+    /**
+     * Create an authorized HTTP Client from an instance of FetchAuthTokenInterface.
+     *
+     * @param FetchAuthTokenInterface $fetcher is used to fetch the auth token
+     * @param array<mixed> $httpClientOptions (optional) Array of request options to apply.
+     * @param callable|null $httpHandler (optional) http client to fetch the token.
+     * @param callable|null $tokenCallback (optional) function to be called when a new token is fetched.
+     * @return \GuzzleHttp\Client
+     */
+    public static function makeHttpClient(
+        FetchAuthTokenInterface $fetcher,
+        array $httpClientOptions = [],
+        ?callable $httpHandler = null,
+        ?callable $tokenCallback = null
+    ) {
+        $middleware = new Middleware\AuthTokenMiddleware(
+            $fetcher,
+            $httpHandler,
+            $tokenCallback
+        );
+        $stack = \GuzzleHttp\HandlerStack::create();
+        $stack->push($middleware);
+
+        return new \GuzzleHttp\Client([
+            'handler' => $stack,
+            'auth' => 'google_auth',
+        ] + $httpClientOptions);
+    }
+
+    /**
+     * Create a new instance of InsecureCredentials.
+     *
+     * @return InsecureCredentials
+     */
+    public static function makeInsecureCredentials()
+    {
+        return new InsecureCredentials();
+    }
+
+    /**
+     * Fetch a quota project from the environment variable
+     * GOOGLE_CLOUD_QUOTA_PROJECT. Return null if
+     * GOOGLE_CLOUD_QUOTA_PROJECT is not specified.
+     *
+     * @return string|null
+     */
+    public static function quotaProjectFromEnv()
+    {
+        return getenv(self::QUOTA_PROJECT_ENV_VAR) ?: null;
+    }
+
+    /**
+     * Gets a callable which returns the default device certification.
+     *
+     * @throws UnexpectedValueException
+     * @return callable|null
+     */
+    public static function getDefaultClientCertSource()
+    {
+        if (!$clientCertSourceJson = self::loadDefaultClientCertSourceFile()) {
+            return null;
+        }
+        $clientCertSourceCmd = $clientCertSourceJson['cert_provider_command'];
+
+        return function () use ($clientCertSourceCmd) {
+            $cmd = array_map('escapeshellarg', $clientCertSourceCmd);
+            exec(implode(' ', $cmd), $output, $returnVar);
+
+            if (0 === $returnVar) {
+                return implode(PHP_EOL, $output);
+            }
+            throw new RuntimeException(
+                '"cert_provider_command" failed with a nonzero exit code'
+            );
+        };
+    }
+
+    /**
+     * Determines whether or not the default device certificate should be loaded.
+     *
+     * @return bool
+     */
+    public static function shouldLoadClientCertSource()
+    {
+        return filter_var(getenv(self::MTLS_CERT_ENV_VAR), FILTER_VALIDATE_BOOLEAN);
+    }
+
+    /**
+     * @return array{cert_provider_command:string[]}|null
+     */
+    private static function loadDefaultClientCertSourceFile()
+    {
+        $rootEnv = self::isOnWindows() ? 'APPDATA' : 'HOME';
+        $path = sprintf('%s/%s', getenv($rootEnv), self::MTLS_WELL_KNOWN_PATH);
+        if (!file_exists($path)) {
+            return null;
+        }
+        $jsonKey = file_get_contents($path);
+        $clientCertSourceJson = json_decode((string) $jsonKey, true);
+        if (!$clientCertSourceJson) {
+            throw new UnexpectedValueException('Invalid client cert source JSON');
+        }
+        if (!isset($clientCertSourceJson['cert_provider_command'])) {
+            throw new UnexpectedValueException(
+                'cert source requires "cert_provider_command"'
+            );
+        }
+        if (!is_array($clientCertSourceJson['cert_provider_command'])) {
+            throw new UnexpectedValueException(
+                'cert source expects "cert_provider_command" to be an array'
+            );
+        }
+        return $clientCertSourceJson;
+    }
+
+    /**
+     * Get the universe domain from the credential. Defaults to "googleapis.com"
+     * for all credential types which do not support universe domain.
+     *
+     * @return string
+     */
+    public function getUniverseDomain(): string
+    {
+        return self::DEFAULT_UNIVERSE_DOMAIN;
+    }
+}
Index: vendor/google/auth/src/ExecutableHandler/ExecutableHandler.php
===================================================================
--- vendor/google/auth/src/ExecutableHandler/ExecutableHandler.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/ExecutableHandler/ExecutableHandler.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Copyright 2024 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Google\Auth\ExecutableHandler;
+
+use RuntimeException;
+use Symfony\Component\Process\Exception\ProcessTimedOutException;
+use Symfony\Component\Process\Process;
+
+class ExecutableHandler
+{
+    private const DEFAULT_EXECUTABLE_TIMEOUT_MILLIS = 30 * 1000;
+
+    private int $timeoutMs;
+
+    /** @var array<string|\Stringable> */
+    private array $env = [];
+
+    private ?string $output = null;
+
+    /**
+     * @param array<string|\Stringable> $env
+     */
+    public function __construct(
+        array $env = [],
+        int $timeoutMs = self::DEFAULT_EXECUTABLE_TIMEOUT_MILLIS,
+    ) {
+        if (!class_exists(Process::class)) {
+            throw new RuntimeException(sprintf(
+                'The "symfony/process" package is required to use %s.',
+                self::class
+            ));
+        }
+        $this->env = $env;
+        $this->timeoutMs = $timeoutMs;
+    }
+
+    /**
+     * @param string $command
+     * @return int
+     */
+    public function __invoke(string $command): int
+    {
+        $process = Process::fromShellCommandline(
+            $command,
+            null,
+            $this->env,
+            null,
+            ($this->timeoutMs / 1000)
+        );
+
+        try {
+            $process->run();
+        } catch (ProcessTimedOutException $e) {
+            throw new ExecutableResponseError(
+                'The executable failed to finish within the timeout specified.',
+                'TIMEOUT_EXCEEDED'
+            );
+        }
+
+        $this->output = $process->getOutput() . $process->getErrorOutput();
+
+        return $process->getExitCode();
+    }
+
+    public function getOutput(): ?string
+    {
+        return $this->output;
+    }
+}
Index: vendor/google/auth/src/ExecutableHandler/ExecutableResponseError.php
===================================================================
--- vendor/google/auth/src/ExecutableHandler/ExecutableResponseError.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/ExecutableHandler/ExecutableResponseError.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Copyright 2024 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Google\Auth\ExecutableHandler;
+
+use Error;
+
+class ExecutableResponseError extends Error
+{
+    public function __construct(string $message, string $executableErrorCode = 'INVALID_EXECUTABLE_RESPONSE')
+    {
+        parent::__construct(sprintf('Error code %s: %s', $executableErrorCode, $message));
+    }
+}
Index: vendor/google/auth/src/ExternalAccountCredentialSourceInterface.php
===================================================================
--- vendor/google/auth/src/ExternalAccountCredentialSourceInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/ExternalAccountCredentialSourceInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Copyright 2023 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+interface ExternalAccountCredentialSourceInterface
+{
+    public function fetchSubjectToken(?callable $httpHandler = null): string;
+    public function getCacheKey(): ?string;
+}
Index: vendor/google/auth/src/FetchAuthTokenCache.php
===================================================================
--- vendor/google/auth/src/FetchAuthTokenCache.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/FetchAuthTokenCache.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,339 @@
+<?php
+/*
+ * Copyright 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+use Psr\Cache\CacheItemPoolInterface;
+
+/**
+ * A class to implement caching for any object implementing
+ * FetchAuthTokenInterface
+ */
+class FetchAuthTokenCache implements
+    FetchAuthTokenInterface,
+    GetQuotaProjectInterface,
+    GetUniverseDomainInterface,
+    SignBlobInterface,
+    ProjectIdProviderInterface,
+    UpdateMetadataInterface
+{
+    use CacheTrait;
+
+    /**
+     * @var FetchAuthTokenInterface
+     */
+    private $fetcher;
+
+    /**
+     * @var int
+     */
+    private $eagerRefreshThresholdSeconds = 10;
+
+    /**
+     * @param FetchAuthTokenInterface $fetcher A credentials fetcher
+     * @param array<mixed>|null $cacheConfig Configuration for the cache
+     * @param CacheItemPoolInterface $cache
+     */
+    public function __construct(
+        FetchAuthTokenInterface $fetcher,
+        ?array $cacheConfig = null,
+        ?CacheItemPoolInterface $cache = null
+    ) {
+        $this->fetcher = $fetcher;
+        $this->cache = $cache;
+        $this->cacheConfig = array_merge([
+            'lifetime' => 1500,
+            'prefix' => '',
+            'cacheUniverseDomain' => $fetcher instanceof Credentials\GCECredentials,
+        ], (array) $cacheConfig);
+    }
+
+    /**
+     * @return FetchAuthTokenInterface
+     */
+    public function getFetcher()
+    {
+        return $this->fetcher;
+    }
+
+    /**
+     * Implements FetchAuthTokenInterface#fetchAuthToken.
+     *
+     * Checks the cache for a valid auth token and fetches the auth tokens
+     * from the supplied fetcher.
+     *
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @return array<mixed> the response
+     * @throws \Exception
+     */
+    public function fetchAuthToken(?callable $httpHandler = null)
+    {
+        if ($cached = $this->fetchAuthTokenFromCache()) {
+            return $cached;
+        }
+
+        $auth_token = $this->fetcher->fetchAuthToken($httpHandler);
+
+        $this->saveAuthTokenInCache($auth_token);
+
+        return $auth_token;
+    }
+
+    /**
+     * @return string
+     */
+    public function getCacheKey()
+    {
+        return $this->getFullCacheKey($this->fetcher->getCacheKey());
+    }
+
+    /**
+     * @return array<mixed>|null
+     */
+    public function getLastReceivedToken()
+    {
+        return $this->fetcher->getLastReceivedToken();
+    }
+
+    /**
+     * Get the client name from the fetcher.
+     *
+     * @param callable|null $httpHandler An HTTP handler to deliver PSR7 requests.
+     * @return string
+     */
+    public function getClientName(?callable $httpHandler = null)
+    {
+        if (!$this->fetcher instanceof SignBlobInterface) {
+            throw new \RuntimeException(
+                'Credentials fetcher does not implement ' .
+                'Google\Auth\SignBlobInterface'
+            );
+        }
+
+        return $this->fetcher->getClientName($httpHandler);
+    }
+
+    /**
+     * Sign a blob using the fetcher.
+     *
+     * @param string $stringToSign The string to sign.
+     * @param bool $forceOpenSsl Require use of OpenSSL for local signing. Does
+     *        not apply to signing done using external services. **Defaults to**
+     *        `false`.
+     * @return string The resulting signature.
+     * @throws \RuntimeException If the fetcher does not implement
+     *     `Google\Auth\SignBlobInterface`.
+     */
+    public function signBlob($stringToSign, $forceOpenSsl = false)
+    {
+        if (!$this->fetcher instanceof SignBlobInterface) {
+            throw new \RuntimeException(
+                'Credentials fetcher does not implement ' .
+                'Google\Auth\SignBlobInterface'
+            );
+        }
+
+        // Pass the access token from cache for credentials that sign blobs
+        // using the IAM API. This saves a call to fetch an access token when a
+        // cached token exists.
+        if ($this->fetcher instanceof Credentials\GCECredentials
+            || $this->fetcher instanceof Credentials\ImpersonatedServiceAccountCredentials
+        ) {
+            $cached = $this->fetchAuthTokenFromCache();
+            $accessToken = $cached['access_token'] ?? null;
+            return $this->fetcher->signBlob($stringToSign, $forceOpenSsl, $accessToken);
+        }
+
+        return $this->fetcher->signBlob($stringToSign, $forceOpenSsl);
+    }
+
+    /**
+     * Get the quota project used for this API request from the credentials
+     * fetcher.
+     *
+     * @return string|null
+     */
+    public function getQuotaProject()
+    {
+        if ($this->fetcher instanceof GetQuotaProjectInterface) {
+            return $this->fetcher->getQuotaProject();
+        }
+
+        return null;
+    }
+
+    /**
+     * Get the Project ID from the fetcher.
+     *
+     * @param callable|null $httpHandler Callback which delivers psr7 request
+     * @return string|null
+     * @throws \RuntimeException If the fetcher does not implement
+     *     `Google\Auth\ProvidesProjectIdInterface`.
+     */
+    public function getProjectId(?callable $httpHandler = null)
+    {
+        if (!$this->fetcher instanceof ProjectIdProviderInterface) {
+            throw new \RuntimeException(
+                'Credentials fetcher does not implement ' .
+                'Google\Auth\ProvidesProjectIdInterface'
+            );
+        }
+
+        // Pass the access token from cache for credentials that require an
+        // access token to fetch the project ID. This saves a call to fetch an
+        // access token when a cached token exists.
+        if ($this->fetcher instanceof Credentials\ExternalAccountCredentials) {
+            $cached = $this->fetchAuthTokenFromCache();
+            $accessToken = $cached['access_token'] ?? null;
+            return $this->fetcher->getProjectId($httpHandler, $accessToken);
+        }
+
+        return $this->fetcher->getProjectId($httpHandler);
+    }
+
+    /*
+     * Get the Universe Domain from the fetcher.
+     *
+     * @return string
+     */
+    public function getUniverseDomain(): string
+    {
+        if ($this->fetcher instanceof GetUniverseDomainInterface) {
+            if ($this->cacheConfig['cacheUniverseDomain']) {
+                return $this->getCachedUniverseDomain($this->fetcher);
+            }
+            return $this->fetcher->getUniverseDomain();
+        }
+
+        return GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN;
+    }
+
+    /**
+     * Updates metadata with the authorization token.
+     *
+     * @param array<mixed> $metadata metadata hashmap
+     * @param string $authUri optional auth uri
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @return array<mixed> updated metadata hashmap
+     * @throws \RuntimeException If the fetcher does not implement
+     *     `Google\Auth\UpdateMetadataInterface`.
+     */
+    public function updateMetadata(
+        $metadata,
+        $authUri = null,
+        ?callable $httpHandler = null
+    ) {
+        if (!$this->fetcher instanceof UpdateMetadataInterface) {
+            throw new \RuntimeException(
+                'Credentials fetcher does not implement ' .
+                'Google\Auth\UpdateMetadataInterface'
+            );
+        }
+
+        $cached = $this->fetchAuthTokenFromCache($authUri);
+        if ($cached) {
+            // Set the access token in the `Authorization` metadata header so
+            // the downstream call to updateMetadata know they don't need to
+            // fetch another token.
+            if (isset($cached['access_token'])) {
+                $metadata[self::AUTH_METADATA_KEY] = [
+                    'Bearer ' . $cached['access_token']
+                ];
+            } elseif (isset($cached['id_token'])) {
+                $metadata[self::AUTH_METADATA_KEY] = [
+                    'Bearer ' . $cached['id_token']
+                ];
+            }
+        }
+
+        $newMetadata = $this->fetcher->updateMetadata(
+            $metadata,
+            $authUri,
+            $httpHandler
+        );
+
+        if (!$cached && $token = $this->fetcher->getLastReceivedToken()) {
+            $this->saveAuthTokenInCache($token, $authUri);
+        }
+
+        return $newMetadata;
+    }
+
+    /**
+     * @param string|null $authUri
+     * @return array<mixed>|null
+     */
+    private function fetchAuthTokenFromCache($authUri = null)
+    {
+        // Use the cached value if its available.
+        //
+        // TODO: correct caching; update the call to setCachedValue to set the expiry
+        // to the value returned with the auth token.
+        //
+        // TODO: correct caching; enable the cache to be cleared.
+
+        // if $authUri is set, use it as the cache key
+        $cacheKey = $authUri
+            ? $this->getFullCacheKey($authUri)
+            : $this->fetcher->getCacheKey();
+
+        $cached = $this->getCachedValue($cacheKey);
+        if (is_array($cached)) {
+            if (empty($cached['expires_at'])) {
+                // If there is no expiration data, assume token is not expired.
+                // (for JwtAccess and ID tokens)
+                return $cached;
+            }
+            if ((time() + $this->eagerRefreshThresholdSeconds) < $cached['expires_at']) {
+                // access token is not expired
+                return $cached;
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * @param array<mixed> $authToken
+     * @param string|null  $authUri
+     * @return void
+     */
+    private function saveAuthTokenInCache($authToken, $authUri = null)
+    {
+        if (isset($authToken['access_token']) ||
+            isset($authToken['id_token'])) {
+            // if $authUri is set, use it as the cache key
+            $cacheKey = $authUri
+                ? $this->getFullCacheKey($authUri)
+                : $this->fetcher->getCacheKey();
+
+            $this->setCachedValue($cacheKey, $authToken);
+        }
+    }
+
+    private function getCachedUniverseDomain(GetUniverseDomainInterface $fetcher): string
+    {
+        $cacheKey = $this->getFullCacheKey($fetcher->getCacheKey() . 'universe_domain'); // @phpstan-ignore-line
+        if ($universeDomain = $this->getCachedValue($cacheKey)) {
+            return $universeDomain;
+        }
+
+        $universeDomain = $fetcher->getUniverseDomain();
+        $this->setCachedValue($cacheKey, $universeDomain);
+        return $universeDomain;
+    }
+}
Index: vendor/google/auth/src/FetchAuthTokenInterface.php
===================================================================
--- vendor/google/auth/src/FetchAuthTokenInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/FetchAuthTokenInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,54 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+/**
+ * An interface implemented by objects that can fetch auth tokens.
+ */
+interface FetchAuthTokenInterface
+{
+    /**
+     * Fetches the auth tokens based on the current state.
+     *
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @return array<mixed> a hash of auth tokens
+     */
+    public function fetchAuthToken(?callable $httpHandler = null);
+
+    /**
+     * Obtains a key that can used to cache the results of #fetchAuthToken.
+     *
+     * If the value is empty, the auth token is not cached.
+     *
+     * @return string a key that may be used to cache the auth token.
+     */
+    public function getCacheKey();
+
+    /**
+     * Returns an associative array with the token and
+     * expiration time.
+     *
+     * @return null|array<mixed> {
+     *     The last received access token.
+     *
+     *     @type string $access_token The access token string.
+     *     @type int $expires_at The time the token expires as a UNIX timestamp.
+     * }
+     */
+    public function getLastReceivedToken();
+}
Index: vendor/google/auth/src/GCECache.php
===================================================================
--- vendor/google/auth/src/GCECache.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/GCECache.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,82 @@
+<?php
+/*
+ * Copyright 2020 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+use Google\Auth\Credentials\GCECredentials;
+use Psr\Cache\CacheItemPoolInterface;
+
+/**
+ * A class to implement caching for calls to GCECredentials::onGce. This class
+ * is used automatically when you pass a `Psr\Cache\CacheItemPoolInterface`
+ * cache object to `ApplicationDefaultCredentials::getCredentials`.
+ *
+ * ```
+ * $sysvCache = new Google\Auth\SysvCacheItemPool();
+ * $creds = Google\Auth\ApplicationDefaultCredentials::getCredentials(
+ *     $scope,
+ *     null,
+ *     null,
+ *     $sysvCache
+ * );
+ * ```
+ */
+class GCECache
+{
+    const GCE_CACHE_KEY = 'google_auth_on_gce_cache';
+
+    use CacheTrait;
+
+    /**
+     * @param array<mixed> $cacheConfig Configuration for the cache
+     * @param CacheItemPoolInterface $cache
+     */
+    public function __construct(
+        ?array $cacheConfig = null,
+        ?CacheItemPoolInterface $cache = null
+    ) {
+        $this->cache = $cache;
+        $this->cacheConfig = array_merge([
+            'lifetime' => 1500,
+            'prefix' => '',
+        ], (array) $cacheConfig);
+    }
+
+    /**
+     * Caches the result of onGce so the metadata server is not called multiple
+     * times.
+     *
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @return bool True if this a GCEInstance, false otherwise
+     */
+    public function onGce(?callable $httpHandler = null)
+    {
+        if (is_null($this->cache)) {
+            return GCECredentials::onGce($httpHandler);
+        }
+
+        $cacheKey = self::GCE_CACHE_KEY;
+        $onGce = $this->getCachedValue($cacheKey);
+
+        if (is_null($onGce)) {
+            $onGce = GCECredentials::onGce($httpHandler);
+            $this->setCachedValue($cacheKey, $onGce);
+        }
+
+        return $onGce;
+    }
+}
Index: vendor/google/auth/src/GetQuotaProjectInterface.php
===================================================================
--- vendor/google/auth/src/GetQuotaProjectInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/GetQuotaProjectInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,33 @@
+<?php
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+/**
+ * An interface implemented by objects that can get quota projects.
+ */
+interface GetQuotaProjectInterface
+{
+    const X_GOOG_USER_PROJECT_HEADER = 'X-Goog-User-Project';
+
+    /**
+     * Get the quota project used for this API request
+     *
+     * @return string|null
+     */
+    public function getQuotaProject();
+}
Index: vendor/google/auth/src/GetUniverseDomainInterface.php
===================================================================
--- vendor/google/auth/src/GetUniverseDomainInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/GetUniverseDomainInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,35 @@
+<?php
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+/**
+ * An interface implemented by objects that can get universe domain for Google Cloud APIs.
+ */
+interface GetUniverseDomainInterface
+{
+    const DEFAULT_UNIVERSE_DOMAIN = 'googleapis.com';
+
+    /**
+     * Get the universe domain from the credential. This should always return
+     * a string, and default to "googleapis.com" if no universe domain is
+     * configured.
+     *
+     * @return string
+     */
+    public function getUniverseDomain(): string;
+}
Index: vendor/google/auth/src/HttpHandler/Guzzle6HttpHandler.php
===================================================================
--- vendor/google/auth/src/HttpHandler/Guzzle6HttpHandler.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/HttpHandler/Guzzle6HttpHandler.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Google\Auth\HttpHandler;
+
+use GuzzleHttp\ClientInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+class Guzzle6HttpHandler
+{
+    /**
+     * @var ClientInterface
+     */
+    private $client;
+
+    /**
+     * @param ClientInterface $client
+     */
+    public function __construct(ClientInterface $client)
+    {
+        $this->client = $client;
+    }
+
+    /**
+     * Accepts a PSR-7 request and an array of options and returns a PSR-7 response.
+     *
+     * @param RequestInterface $request
+     * @param array<mixed> $options
+     * @return ResponseInterface
+     */
+    public function __invoke(RequestInterface $request, array $options = [])
+    {
+        return $this->client->send($request, $options);
+    }
+
+    /**
+     * Accepts a PSR-7 request and an array of options and returns a PromiseInterface
+     *
+     * @param RequestInterface $request
+     * @param array<mixed> $options
+     *
+     * @return \GuzzleHttp\Promise\PromiseInterface
+     */
+    public function async(RequestInterface $request, array $options = [])
+    {
+        return $this->client->sendAsync($request, $options);
+    }
+}
Index: vendor/google/auth/src/HttpHandler/Guzzle7HttpHandler.php
===================================================================
--- vendor/google/auth/src/HttpHandler/Guzzle7HttpHandler.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/HttpHandler/Guzzle7HttpHandler.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,21 @@
+<?php
+/**
+ * Copyright 2020 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Google\Auth\HttpHandler;
+
+class Guzzle7HttpHandler extends Guzzle6HttpHandler
+{
+}
Index: vendor/google/auth/src/HttpHandler/HttpClientCache.php
===================================================================
--- vendor/google/auth/src/HttpHandler/HttpClientCache.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/HttpHandler/HttpClientCache.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,54 @@
+<?php
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\HttpHandler;
+
+use GuzzleHttp\ClientInterface;
+
+/**
+ * Stores an HTTP Client in order to prevent multiple instantiations.
+ */
+class HttpClientCache
+{
+    /**
+     * @var ClientInterface|null
+     */
+    private static $httpClient;
+
+    /**
+     * Cache an HTTP Client for later calls.
+     *
+     * Passing null will unset the cached client.
+     *
+     * @param ClientInterface|null $client
+     * @return void
+     */
+    public static function setHttpClient(?ClientInterface $client = null)
+    {
+        self::$httpClient = $client;
+    }
+
+    /**
+     * Get the stored HTTP Client, or null.
+     *
+     * @return ClientInterface|null
+     */
+    public static function getHttpClient()
+    {
+        return self::$httpClient;
+    }
+}
Index: vendor/google/auth/src/HttpHandler/HttpHandlerFactory.php
===================================================================
--- vendor/google/auth/src/HttpHandler/HttpHandlerFactory.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/HttpHandler/HttpHandlerFactory.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,64 @@
+<?php
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+namespace Google\Auth\HttpHandler;
+
+use GuzzleHttp\BodySummarizer;
+use GuzzleHttp\Client;
+use GuzzleHttp\ClientInterface;
+use GuzzleHttp\HandlerStack;
+use GuzzleHttp\Middleware;
+
+class HttpHandlerFactory
+{
+    /**
+     * Builds out a default http handler for the installed version of guzzle.
+     *
+     * @param ClientInterface|null $client
+     * @return Guzzle6HttpHandler|Guzzle7HttpHandler
+     * @throws \Exception
+     */
+    public static function build(?ClientInterface $client = null)
+    {
+        if (is_null($client)) {
+            $stack = null;
+            if (class_exists(BodySummarizer::class)) {
+                // double the # of characters before truncation by default
+                $bodySummarizer = new BodySummarizer(240);
+                $stack = HandlerStack::create();
+                $stack->remove('http_errors');
+                $stack->unshift(Middleware::httpErrors($bodySummarizer), 'http_errors');
+            }
+            $client = new Client(['handler' => $stack]);
+        }
+
+        $version = null;
+        if (defined('GuzzleHttp\ClientInterface::MAJOR_VERSION')) {
+            $version = ClientInterface::MAJOR_VERSION;
+        } elseif (defined('GuzzleHttp\ClientInterface::VERSION')) {
+            $version = (int) substr(ClientInterface::VERSION, 0, 1);
+        }
+
+        switch ($version) {
+            case 6:
+                return new Guzzle6HttpHandler($client);
+            case 7:
+                return new Guzzle7HttpHandler($client);
+            default:
+                throw new \Exception('Version not supported');
+        }
+    }
+}
Index: vendor/google/auth/src/Iam.php
===================================================================
--- vendor/google/auth/src/Iam.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Iam.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,155 @@
+<?php
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+use Google\Auth\HttpHandler\HttpClientCache;
+use Google\Auth\HttpHandler\HttpHandlerFactory;
+use GuzzleHttp\Psr7;
+use GuzzleHttp\Psr7\Utils;
+
+/**
+ * Tools for using the IAM API.
+ *
+ * @see https://cloud.google.com/iam/docs IAM Documentation
+ */
+class Iam
+{
+    /**
+     * @deprecated
+     */
+    const IAM_API_ROOT = 'https://iamcredentials.googleapis.com/v1';
+    const SIGN_BLOB_PATH = '%s:signBlob?alt=json';
+    const SERVICE_ACCOUNT_NAME = 'projects/-/serviceAccounts/%s';
+    private const IAM_API_ROOT_TEMPLATE = 'https://iamcredentials.UNIVERSE_DOMAIN/v1';
+    private const GENERATE_ID_TOKEN_PATH = '%s:generateIdToken';
+
+    /**
+     * @var callable
+     */
+    private $httpHandler;
+
+    private string $universeDomain;
+
+    /**
+     * @param callable|null $httpHandler [optional] The HTTP Handler to send requests.
+     */
+    public function __construct(
+        ?callable $httpHandler = null,
+        string $universeDomain = GetUniverseDomainInterface::DEFAULT_UNIVERSE_DOMAIN
+    ) {
+        $this->httpHandler = $httpHandler
+            ?: HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+        $this->universeDomain = $universeDomain;
+    }
+
+    /**
+     * Sign a string using the IAM signBlob API.
+     *
+     * Note that signing using IAM requires your service account to have the
+     * `iam.serviceAccounts.signBlob` permission, part of the "Service Account
+     * Token Creator" IAM role.
+     *
+     * @param string $email The service account email.
+     * @param string $accessToken An access token from the service account.
+     * @param string $stringToSign The string to be signed.
+     * @param array<string> $delegates [optional] A list of service account emails to
+     *        add to the delegate chain. If omitted, the value of `$email` will
+     *        be used.
+     * @return string The signed string, base64-encoded.
+     */
+    public function signBlob($email, $accessToken, $stringToSign, array $delegates = [])
+    {
+        $name = sprintf(self::SERVICE_ACCOUNT_NAME, $email);
+        $apiRoot = str_replace('UNIVERSE_DOMAIN', $this->universeDomain, self::IAM_API_ROOT_TEMPLATE);
+        $uri = $apiRoot . '/' . sprintf(self::SIGN_BLOB_PATH, $name);
+
+        if ($delegates) {
+            foreach ($delegates as &$delegate) {
+                $delegate = sprintf(self::SERVICE_ACCOUNT_NAME, $delegate);
+            }
+        } else {
+            $delegates = [$name];
+        }
+
+        $body = [
+            'delegates' => $delegates,
+            'payload' => base64_encode($stringToSign),
+        ];
+
+        $headers = [
+            'Authorization' => 'Bearer ' . $accessToken
+        ];
+
+        $request = new Psr7\Request(
+            'POST',
+            $uri,
+            $headers,
+            Utils::streamFor(json_encode($body))
+        );
+
+        $res = ($this->httpHandler)($request);
+        $body = json_decode((string) $res->getBody(), true);
+
+        return $body['signedBlob'];
+    }
+
+    /**
+     * Sign a string using the IAM signBlob API.
+     *
+     * Note that signing using IAM requires your service account to have the
+     * `iam.serviceAccounts.signBlob` permission, part of the "Service Account
+     * Token Creator" IAM role.
+     *
+     * @param string $clientEmail The service account email.
+     * @param string $targetAudience The audience for the ID token.
+     * @param string $bearerToken The token to authenticate the IAM request.
+     * @param array<string, string> $headers [optional] Additional headers to send with the request.
+     *
+     * @return string The signed string, base64-encoded.
+     */
+    public function generateIdToken(
+        string $clientEmail,
+        string $targetAudience,
+        string $bearerToken,
+        array $headers = []
+    ): string {
+        $name = sprintf(self::SERVICE_ACCOUNT_NAME, $clientEmail);
+        $apiRoot = str_replace('UNIVERSE_DOMAIN', $this->universeDomain, self::IAM_API_ROOT_TEMPLATE);
+        $uri = $apiRoot . '/' . sprintf(self::GENERATE_ID_TOKEN_PATH, $name);
+
+        $headers['Authorization'] = 'Bearer ' . $bearerToken;
+
+        $body = [
+            'audience' => $targetAudience,
+            'includeEmail' => true,
+            'useEmailAzp' => true,
+        ];
+
+        $request = new Psr7\Request(
+            'POST',
+            $uri,
+            $headers,
+            Utils::streamFor(json_encode($body))
+        );
+
+        $res = ($this->httpHandler)($request);
+        $body = json_decode((string) $res->getBody(), true);
+
+        return $body['token'];
+    }
+}
Index: vendor/google/auth/src/IamSignerTrait.php
===================================================================
--- vendor/google/auth/src/IamSignerTrait.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/IamSignerTrait.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,72 @@
+<?php
+
+/*
+ * Copyright 2022 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+use Exception;
+use Google\Auth\HttpHandler\HttpClientCache;
+use Google\Auth\HttpHandler\HttpHandlerFactory;
+
+trait IamSignerTrait
+{
+    /**
+     * @var Iam|null
+     */
+    private $iam;
+
+    /**
+     * Sign a string using the default service account private key.
+     *
+     * This implementation uses IAM's signBlob API.
+     *
+     * @see https://cloud.google.com/iam/credentials/reference/rest/v1/projects.serviceAccounts/signBlob SignBlob
+     *
+     * @param string $stringToSign The string to sign.
+     * @param bool $forceOpenSsl [optional] Does not apply to this credentials
+     *        type.
+     * @param string $accessToken The access token to use to sign the blob. If
+     *        provided, saves a call to the metadata server for a new access
+     *        token. **Defaults to** `null`.
+     * @return string
+     * @throws Exception
+     */
+    public function signBlob($stringToSign, $forceOpenSsl = false, $accessToken = null)
+    {
+        $httpHandler = HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+
+        // Providing a signer is useful for testing, but it's undocumented
+        // because it's not something a user would generally need to do.
+        $signer = $this->iam;
+        if (!$signer) {
+            $signer = $this instanceof GetUniverseDomainInterface
+                ? new Iam($httpHandler, $this->getUniverseDomain())
+                : new Iam($httpHandler);
+        }
+
+        $email = $this->getClientName($httpHandler);
+
+        if (is_null($accessToken)) {
+            $previousToken = $this->getLastReceivedToken();
+            $accessToken = $previousToken
+                ? $previousToken['access_token']
+                : $this->fetchAuthToken($httpHandler)['access_token'];
+        }
+
+        return $signer->signBlob($email, $accessToken, $stringToSign);
+    }
+}
Index: vendor/google/auth/src/MetricsTrait.php
===================================================================
--- vendor/google/auth/src/MetricsTrait.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/MetricsTrait.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,120 @@
+<?php
+/*
+ * Copyright 2024 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+/**
+ * Trait containing helper methods required for enabling
+ * observability metrics in the library.
+ *
+ * @internal
+ */
+trait MetricsTrait
+{
+    /**
+     * @var string The version of the auth library php.
+     */
+    private static $version;
+
+    /**
+     * @var string The header key for the observability metrics.
+     */
+    protected static $metricMetadataKey = 'x-goog-api-client';
+
+    /**
+     * @param string $credType [Optional] The credential type.
+     *        Empty value will not add any credential type to the header.
+     *        Should be one of `'sa'`, `'jwt'`, `'imp'`, `'mds'`, `'u'`.
+     * @param string $authRequestType [Optional] The auth request type.
+     *        Empty value will not add any auth request type to the header.
+     *        Should be one of `'at'`, `'it'`, `'mds'`.
+     * @return string The header value for the observability metrics.
+     */
+    protected static function getMetricsHeader(
+        $credType = '',
+        $authRequestType = ''
+    ): string {
+        $value = sprintf(
+            'gl-php/%s auth/%s',
+            PHP_VERSION,
+            self::getVersion()
+        );
+
+        if (!empty($authRequestType)) {
+            $value .= ' auth-request-type/' . $authRequestType;
+        }
+
+        if (!empty($credType)) {
+            $value .= ' cred-type/' . $credType;
+        }
+
+        return $value;
+    }
+
+    /**
+     * @param array<mixed> $metadata The metadata to update and return.
+     * @return array<mixed> The updated metadata.
+     */
+    protected function applyServiceApiUsageMetrics($metadata)
+    {
+        if ($credType = $this->getCredType()) {
+            // Add service api usage observability metrics info into metadata
+            // We expect upstream libries to have the metadata key populated already
+            $value = 'cred-type/' . $credType;
+            if (!isset($metadata[self::$metricMetadataKey])) {
+                // This case will happen only when someone invokes the updateMetadata
+                // method on the credentials fetcher themselves.
+                $metadata[self::$metricMetadataKey] = [$value];
+            } elseif (is_array($metadata[self::$metricMetadataKey])) {
+                $metadata[self::$metricMetadataKey][0] .= ' ' . $value;
+            } else {
+                $metadata[self::$metricMetadataKey] .= ' ' . $value;
+            }
+        }
+
+        return $metadata;
+    }
+
+    /**
+     * @param array<mixed> $metadata The metadata to update and return.
+     * @param string $authRequestType The auth request type. Possible values are
+     *        `'at'`, `'it'`, `'mds'`.
+     * @return array<mixed> The updated metadata.
+     */
+    protected function applyTokenEndpointMetrics($metadata, $authRequestType)
+    {
+        $metricsHeader = self::getMetricsHeader($this->getCredType(), $authRequestType);
+        if (!isset($metadata[self::$metricMetadataKey])) {
+            $metadata[self::$metricMetadataKey] = $metricsHeader;
+        }
+        return $metadata;
+    }
+
+    protected static function getVersion(): string
+    {
+        if (is_null(self::$version)) {
+            $versionFilePath = __DIR__ . '/../VERSION';
+            self::$version = trim((string) file_get_contents($versionFilePath));
+        }
+        return self::$version;
+    }
+
+    protected function getCredType(): string
+    {
+        return '';
+    }
+}
Index: vendor/google/auth/src/Middleware/AuthTokenMiddleware.php
===================================================================
--- vendor/google/auth/src/Middleware/AuthTokenMiddleware.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Middleware/AuthTokenMiddleware.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,163 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Middleware;
+
+use Google\Auth\FetchAuthTokenCache;
+use Google\Auth\FetchAuthTokenInterface;
+use Google\Auth\GetQuotaProjectInterface;
+use Google\Auth\UpdateMetadataInterface;
+use GuzzleHttp\Psr7\Utils;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * AuthTokenMiddleware is a Guzzle Middleware that adds an Authorization header
+ * provided by an object implementing FetchAuthTokenInterface.
+ *
+ * The FetchAuthTokenInterface#fetchAuthToken is used to obtain a hash; one of
+ * the values value in that hash is added as the authorization header.
+ *
+ * Requests will be accessed with the authorization header:
+ *
+ * 'authorization' 'Bearer <value of auth_token>'
+ */
+class AuthTokenMiddleware
+{
+    /**
+     * @var callable
+     */
+    private $httpHandler;
+
+    /**
+     * It must be an implementation of FetchAuthTokenInterface.
+     * It may also implement UpdateMetadataInterface allowing direct
+     * retrieval of auth related headers
+     * @var FetchAuthTokenInterface
+     */
+    private $fetcher;
+
+    /**
+     * @var ?callable
+     */
+    private $tokenCallback;
+
+    /**
+     * Creates a new AuthTokenMiddleware.
+     *
+     * @param FetchAuthTokenInterface $fetcher is used to fetch the auth token
+     * @param callable|null $httpHandler (optional) callback which delivers psr7 request
+     * @param callable|null $tokenCallback (optional) function to be called when a new token is fetched.
+     */
+    public function __construct(
+        FetchAuthTokenInterface $fetcher,
+        ?callable $httpHandler = null,
+        ?callable $tokenCallback = null
+    ) {
+        $this->fetcher = $fetcher;
+        $this->httpHandler = $httpHandler;
+        $this->tokenCallback = $tokenCallback;
+    }
+
+    /**
+     * Updates the request with an Authorization header when auth is 'google_auth'.
+     *
+     *   use Google\Auth\Middleware\AuthTokenMiddleware;
+     *   use Google\Auth\OAuth2;
+     *   use GuzzleHttp\Client;
+     *   use GuzzleHttp\HandlerStack;
+     *
+     *   $config = [..<oauth config param>.];
+     *   $oauth2 = new OAuth2($config)
+     *   $middleware = new AuthTokenMiddleware($oauth2);
+     *   $stack = HandlerStack::create();
+     *   $stack->push($middleware);
+     *
+     *   $client = new Client([
+     *       'handler' => $stack,
+     *       'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
+     *       'auth' => 'google_auth' // authorize all requests
+     *   ]);
+     *
+     *   $res = $client->get('myproject/taskqueues/myqueue');
+     *
+     * @param callable $handler
+     * @return \Closure
+     */
+    public function __invoke(callable $handler)
+    {
+        return function (RequestInterface $request, array $options) use ($handler) {
+            // Requests using "auth"="google_auth" will be authorized.
+            if (!isset($options['auth']) || $options['auth'] !== 'google_auth') {
+                return $handler($request, $options);
+            }
+
+            $request = $this->addAuthHeaders($request);
+
+            if ($quotaProject = $this->getQuotaProject()) {
+                $request = $request->withHeader(
+                    GetQuotaProjectInterface::X_GOOG_USER_PROJECT_HEADER,
+                    $quotaProject
+                );
+            }
+
+            return $handler($request, $options);
+        };
+    }
+
+    /**
+     * Adds auth related headers to the request.
+     *
+     * @param RequestInterface $request
+     * @return RequestInterface
+     */
+    private function addAuthHeaders(RequestInterface $request)
+    {
+        if (!$this->fetcher instanceof UpdateMetadataInterface ||
+            ($this->fetcher instanceof FetchAuthTokenCache &&
+             !$this->fetcher->getFetcher() instanceof UpdateMetadataInterface)
+        ) {
+            $token = $this->fetcher->fetchAuthToken();
+            $request = $request->withHeader(
+                'authorization',
+                'Bearer ' . ($token['access_token'] ?? $token['id_token'] ?? '')
+            );
+        } else {
+            $headers = $this->fetcher->updateMetadata($request->getHeaders(), null, $this->httpHandler);
+            $request = Utils::modifyRequest($request, ['set_headers' => $headers]);
+        }
+
+        if ($this->tokenCallback && ($token = $this->fetcher->getLastReceivedToken())) {
+            if (array_key_exists('access_token', $token)) {
+                call_user_func($this->tokenCallback, $this->fetcher->getCacheKey(), $token['access_token']);
+            }
+        }
+
+        return $request;
+    }
+
+    /**
+     * @return string|null
+     */
+    private function getQuotaProject()
+    {
+        if ($this->fetcher instanceof GetQuotaProjectInterface) {
+            return $this->fetcher->getQuotaProject();
+        }
+
+        return null;
+    }
+}
Index: vendor/google/auth/src/Middleware/ProxyAuthTokenMiddleware.php
===================================================================
--- vendor/google/auth/src/Middleware/ProxyAuthTokenMiddleware.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Middleware/ProxyAuthTokenMiddleware.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,155 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Middleware;
+
+use Google\Auth\FetchAuthTokenInterface;
+use Google\Auth\GetQuotaProjectInterface;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * ProxyAuthTokenMiddleware is a Guzzle Middleware that adds an Authorization header
+ * provided by an object implementing FetchAuthTokenInterface.
+ *
+ * The FetchAuthTokenInterface#fetchAuthToken is used to obtain a hash; one of
+ * the values value in that hash is added as the authorization header.
+ *
+ * Requests will be accessed with the authorization header:
+ *
+ * 'proxy-authorization' 'Bearer <value of auth_token>'
+ */
+class ProxyAuthTokenMiddleware
+{
+    /**
+     * @var callable
+     */
+    private $httpHandler;
+
+    /**
+     * @var FetchAuthTokenInterface
+     */
+    private $fetcher;
+
+    /**
+     * @var ?callable
+     */
+    private $tokenCallback;
+
+    /**
+     * Creates a new ProxyAuthTokenMiddleware.
+     *
+     * @param FetchAuthTokenInterface $fetcher is used to fetch the auth token
+     * @param callable|null $httpHandler (optional) callback which delivers psr7 request
+     * @param callable|null $tokenCallback (optional) function to be called when a new token is fetched.
+     */
+    public function __construct(
+        FetchAuthTokenInterface $fetcher,
+        ?callable $httpHandler = null,
+        ?callable $tokenCallback = null
+    ) {
+        $this->fetcher = $fetcher;
+        $this->httpHandler = $httpHandler;
+        $this->tokenCallback = $tokenCallback;
+    }
+
+    /**
+     * Updates the request with an Authorization header when auth is 'google_auth'.
+     *
+     *   use Google\Auth\Middleware\ProxyAuthTokenMiddleware;
+     *   use Google\Auth\OAuth2;
+     *   use GuzzleHttp\Client;
+     *   use GuzzleHttp\HandlerStack;
+     *
+     *   $config = [..<oauth config param>.];
+     *   $oauth2 = new OAuth2($config)
+     *   $middleware = new ProxyAuthTokenMiddleware($oauth2);
+     *   $stack = HandlerStack::create();
+     *   $stack->push($middleware);
+     *
+     *   $client = new Client([
+     *       'handler' => $stack,
+     *       'base_uri' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
+     *       'proxy_auth' => 'google_auth' // authorize all requests
+     *   ]);
+     *
+     *   $res = $client->get('myproject/taskqueues/myqueue');
+     *
+     * @param callable $handler
+     * @return \Closure
+     */
+    public function __invoke(callable $handler)
+    {
+        return function (RequestInterface $request, array $options) use ($handler) {
+            // Requests using "proxy_auth"="google_auth" will be authorized.
+            if (!isset($options['proxy_auth']) || $options['proxy_auth'] !== 'google_auth') {
+                return $handler($request, $options);
+            }
+
+            $request = $request->withHeader('proxy-authorization', 'Bearer ' . $this->fetchToken());
+
+            if ($quotaProject = $this->getQuotaProject()) {
+                $request = $request->withHeader(
+                    GetQuotaProjectInterface::X_GOOG_USER_PROJECT_HEADER,
+                    $quotaProject
+                );
+            }
+
+            return $handler($request, $options);
+        };
+    }
+
+    /**
+     * Call fetcher to fetch the token.
+     *
+     * @return string|null
+     */
+    private function fetchToken()
+    {
+        $auth_tokens = $this->fetcher->fetchAuthToken($this->httpHandler);
+
+        if (array_key_exists('access_token', $auth_tokens)) {
+            // notify the callback if applicable
+            if ($this->tokenCallback) {
+                call_user_func(
+                    $this->tokenCallback,
+                    $this->fetcher->getCacheKey(),
+                    $auth_tokens['access_token']
+                );
+            }
+
+            return $auth_tokens['access_token'];
+        }
+
+        if (array_key_exists('id_token', $auth_tokens)) {
+            return $auth_tokens['id_token'];
+        }
+
+        return null;
+    }
+
+    /**
+     * @return string|null;
+     */
+    private function getQuotaProject()
+    {
+        if ($this->fetcher instanceof GetQuotaProjectInterface) {
+            return $this->fetcher->getQuotaProject();
+        }
+
+        return null;
+    }
+}
Index: vendor/google/auth/src/Middleware/ScopedAccessTokenMiddleware.php
===================================================================
--- vendor/google/auth/src/Middleware/ScopedAccessTokenMiddleware.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Middleware/ScopedAccessTokenMiddleware.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,165 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Middleware;
+
+use Google\Auth\CacheTrait;
+use Psr\Cache\CacheItemPoolInterface;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * ScopedAccessTokenMiddleware is a Guzzle Middleware that adds an Authorization
+ * header provided by a closure.
+ *
+ * The closure returns an access token, taking the scope, either a single
+ * string or an array of strings, as its value.  If provided, a cache will be
+ * used to preserve the access token for a given lifetime.
+ *
+ * Requests will be accessed with the authorization header:
+ *
+ * 'authorization' 'Bearer <value of auth_token>'
+ */
+class ScopedAccessTokenMiddleware
+{
+    use CacheTrait;
+
+    const DEFAULT_CACHE_LIFETIME = 1500;
+
+    /**
+     * @var callable
+     */
+    private $tokenFunc;
+
+    /**
+     * @var array<string>|string
+     */
+    private $scopes;
+
+    /**
+     * Creates a new ScopedAccessTokenMiddleware.
+     *
+     * @param callable $tokenFunc a token generator function
+     * @param array<string>|string $scopes the token authentication scopes
+     * @param array<mixed>|null $cacheConfig configuration for the cache when it's present
+     * @param CacheItemPoolInterface|null $cache an implementation of CacheItemPoolInterface
+     */
+    public function __construct(
+        callable $tokenFunc,
+        $scopes,
+        ?array $cacheConfig = null,
+        ?CacheItemPoolInterface $cache = null
+    ) {
+        $this->tokenFunc = $tokenFunc;
+        if (!(is_string($scopes) || is_array($scopes))) {
+            throw new \InvalidArgumentException(
+                'wants scope should be string or array'
+            );
+        }
+        $this->scopes = $scopes;
+
+        if (!is_null($cache)) {
+            $this->cache = $cache;
+            $this->cacheConfig = array_merge([
+                'lifetime' => self::DEFAULT_CACHE_LIFETIME,
+                'prefix' => '',
+            ], $cacheConfig);
+        }
+    }
+
+    /**
+     * Updates the request with an Authorization header when auth is 'scoped'.
+     *
+     *   E.g this could be used to authenticate using the AppEngine
+     *   AppIdentityService.
+     *
+     *   use google\appengine\api\app_identity\AppIdentityService;
+     *   use Google\Auth\Middleware\ScopedAccessTokenMiddleware;
+     *   use GuzzleHttp\Client;
+     *   use GuzzleHttp\HandlerStack;
+     *
+     *   $scope = 'https://www.googleapis.com/auth/taskqueue'
+     *   $middleware = new ScopedAccessTokenMiddleware(
+     *       'AppIdentityService::getAccessToken',
+     *       $scope,
+     *       [ 'prefix' => 'Google\Auth\ScopedAccessToken::' ],
+     *       $cache = new Memcache()
+     *   );
+     *   $stack = HandlerStack::create();
+     *   $stack->push($middleware);
+     *
+     *   $client = new Client([
+     *       'handler' => $stack,
+     *       'base_url' => 'https://www.googleapis.com/taskqueue/v1beta2/projects/',
+     *       'auth' => 'scoped' // authorize all requests
+     *   ]);
+     *
+     *   $res = $client->get('myproject/taskqueues/myqueue');
+     *
+     * @param callable $handler
+     * @return \Closure
+     */
+    public function __invoke(callable $handler)
+    {
+        return function (RequestInterface $request, array $options) use ($handler) {
+            // Requests using "auth"="scoped" will be authorized.
+            if (!isset($options['auth']) || $options['auth'] !== 'scoped') {
+                return $handler($request, $options);
+            }
+
+            $request = $request->withHeader('authorization', 'Bearer ' . $this->fetchToken());
+
+            return $handler($request, $options);
+        };
+    }
+
+    /**
+     * @return string
+     */
+    private function getCacheKey()
+    {
+        $key = null;
+
+        if (is_string($this->scopes)) {
+            $key .= $this->scopes;
+        } elseif (is_array($this->scopes)) {
+            $key .= implode(':', $this->scopes);
+        }
+
+        return $key;
+    }
+
+    /**
+     * Determine if token is available in the cache, if not call tokenFunc to
+     * fetch it.
+     *
+     * @return string
+     */
+    private function fetchToken()
+    {
+        $cacheKey = $this->getCacheKey();
+        $cached = $this->getCachedValue($cacheKey);
+
+        if (!empty($cached)) {
+            return $cached;
+        }
+
+        $token = call_user_func($this->tokenFunc, $this->scopes);
+        $this->setCachedValue($cacheKey, $token);
+
+        return $token;
+    }
+}
Index: vendor/google/auth/src/Middleware/SimpleMiddleware.php
===================================================================
--- vendor/google/auth/src/Middleware/SimpleMiddleware.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/Middleware/SimpleMiddleware.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,92 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth\Middleware;
+
+use GuzzleHttp\Psr7\Query;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * SimpleMiddleware is a Guzzle Middleware that implements Google's Simple API
+ * access.
+ *
+ * Requests are accessed using the Simple API access developer key.
+ */
+class SimpleMiddleware
+{
+    /**
+     * @var array<mixed>
+     */
+    private $config;
+
+    /**
+     * Create a new Simple plugin.
+     *
+     * The configuration array expects one option
+     * - key: required, otherwise InvalidArgumentException is thrown
+     *
+     * @param array<mixed> $config Configuration array
+     */
+    public function __construct(array $config)
+    {
+        if (!isset($config['key'])) {
+            throw new \InvalidArgumentException('requires a key to have been set');
+        }
+
+        $this->config = array_merge(['key' => null], $config);
+    }
+
+    /**
+     * Updates the request query with the developer key if auth is set to simple.
+     *
+     *   use Google\Auth\Middleware\SimpleMiddleware;
+     *   use GuzzleHttp\Client;
+     *   use GuzzleHttp\HandlerStack;
+     *
+     *   $my_key = 'is not the same as yours';
+     *   $middleware = new SimpleMiddleware(['key' => $my_key]);
+     *   $stack = HandlerStack::create();
+     *   $stack->push($middleware);
+     *
+     *   $client = new Client([
+     *       'handler' => $stack,
+     *       'base_uri' => 'https://www.googleapis.com/discovery/v1/',
+     *       'auth' => 'simple'
+     *   ]);
+     *
+     *   $res = $client->get('drive/v2/rest');
+     *
+     * @param callable $handler
+     * @return \Closure
+     */
+    public function __invoke(callable $handler)
+    {
+        return function (RequestInterface $request, array $options) use ($handler) {
+            // Requests using "auth"="scoped" will be authorized.
+            if (!isset($options['auth']) || $options['auth'] !== 'simple') {
+                return $handler($request, $options);
+            }
+
+            $query = Query::parse($request->getUri()->getQuery());
+            $params = array_merge($query, $this->config);
+            $uri = $request->getUri()->withQuery(Query::build($params));
+            $request = $request->withUri($uri);
+
+            return $handler($request, $options);
+        };
+    }
+}
Index: vendor/google/auth/src/OAuth2.php
===================================================================
--- vendor/google/auth/src/OAuth2.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/OAuth2.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,1828 @@
+<?php
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+use Firebase\JWT\JWT;
+use Firebase\JWT\Key;
+use Google\Auth\HttpHandler\HttpClientCache;
+use Google\Auth\HttpHandler\HttpHandlerFactory;
+use GuzzleHttp\Psr7\Query;
+use GuzzleHttp\Psr7\Request;
+use GuzzleHttp\Psr7\Utils;
+use InvalidArgumentException;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * OAuth2 supports authentication by OAuth2 2-legged flows.
+ *
+ * It primary supports
+ * - service account authorization
+ * - authorization where a user already has an access token
+ */
+class OAuth2 implements FetchAuthTokenInterface
+{
+    const DEFAULT_EXPIRY_SECONDS = 3600; // 1 hour
+    const DEFAULT_SKEW_SECONDS = 60; // 1 minute
+    const JWT_URN = 'urn:ietf:params:oauth:grant-type:jwt-bearer';
+    const STS_URN = 'urn:ietf:params:oauth:grant-type:token-exchange';
+    private const STS_REQUESTED_TOKEN_TYPE = 'urn:ietf:params:oauth:token-type:access_token';
+
+    /**
+     * TODO: determine known methods from the keys of JWT::methods.
+     *
+     * @var array<string>
+     */
+    public static $knownSigningAlgorithms = [
+        'HS256',
+        'HS512',
+        'HS384',
+        'RS256',
+    ];
+
+    /**
+     * The well known grant types.
+     *
+     * @var array<string>
+     */
+    public static $knownGrantTypes = [
+        'authorization_code',
+        'refresh_token',
+        'password',
+        'client_credentials',
+    ];
+
+    /**
+     * - authorizationUri
+     *   The authorization server's HTTP endpoint capable of
+     *   authenticating the end-user and obtaining authorization.
+     *
+     * @var ?UriInterface
+     */
+    private $authorizationUri;
+
+    /**
+     * - tokenCredentialUri
+     *   The authorization server's HTTP endpoint capable of issuing
+     *   tokens and refreshing expired tokens.
+     *
+     * @var UriInterface
+     */
+    private $tokenCredentialUri;
+
+    /**
+     * The redirection URI used in the initial request.
+     *
+     * @var ?string
+     */
+    private $redirectUri;
+
+    /**
+     * A unique identifier issued to the client to identify itself to the
+     * authorization server.
+     *
+     * @var string
+     */
+    private $clientId;
+
+    /**
+     * A shared symmetric secret issued by the authorization server, which is
+     * used to authenticate the client.
+     *
+     * @var string
+     */
+    private $clientSecret;
+
+    /**
+     * The resource owner's username.
+     *
+     * @var ?string
+     */
+    private $username;
+
+    /**
+     * The resource owner's password.
+     *
+     * @var ?string
+     */
+    private $password;
+
+    /**
+     * The scope of the access request, expressed either as an Array or as a
+     * space-delimited string.
+     *
+     * @var ?array<string>
+     */
+    private $scope;
+
+    /**
+     * An arbitrary string designed to allow the client to maintain state.
+     *
+     * @var string
+     */
+    private $state;
+
+    /**
+     * The authorization code issued to this client.
+     *
+     * Only used by the authorization code access grant type.
+     *
+     * @var ?string
+     */
+    private $code;
+
+    /**
+     * The issuer ID when using assertion profile.
+     *
+     * @var ?string
+     */
+    private $issuer;
+
+    /**
+     * The target audience for assertions.
+     *
+     * @var string
+     */
+    private $audience;
+
+    /**
+     * The target sub when issuing assertions.
+     *
+     * @var string
+     */
+    private $sub;
+
+    /**
+     * The number of seconds assertions are valid for.
+     *
+     * @var int
+     */
+    private $expiry;
+
+    /**
+     * The signing key when using assertion profile.
+     *
+     * @var ?string
+     */
+    private $signingKey;
+
+    /**
+     * The signing key id when using assertion profile. Param kid in jwt header
+     *
+     * @var string
+     */
+    private $signingKeyId;
+
+    /**
+     * The signing algorithm when using an assertion profile.
+     *
+     * @var ?string
+     */
+    private $signingAlgorithm;
+
+    /**
+     * The refresh token associated with the access token to be refreshed.
+     *
+     * @var ?string
+     */
+    private $refreshToken;
+
+    /**
+     * The current access token.
+     *
+     * @var string
+     */
+    private $accessToken;
+
+    /**
+     * The current ID token.
+     *
+     * @var string
+     */
+    private $idToken;
+
+    /**
+     * The scopes granted to the current access token
+     *
+     * @var string
+     */
+    private $grantedScope;
+
+    /**
+     * The lifetime in seconds of the current access token.
+     *
+     * @var ?int
+     */
+    private $expiresIn;
+
+    /**
+     * The expiration time of the access token as a number of seconds since the
+     * unix epoch.
+     *
+     * @var ?int
+     */
+    private $expiresAt;
+
+    /**
+     * The issue time of the access token as a number of seconds since the unix
+     * epoch.
+     *
+     * @var ?int
+     */
+    private $issuedAt;
+
+    /**
+     * The current grant type.
+     *
+     * @var ?string
+     */
+    private $grantType;
+
+    /**
+     * When using an extension grant type, this is the set of parameters used by
+     * that extension.
+     *
+     * @var array<mixed>
+     */
+    private $extensionParams;
+
+    /**
+     * When using the toJwt function, these claims will be added to the JWT
+     * payload.
+     *
+     * @var array<mixed>
+     */
+    private $additionalClaims;
+
+    /**
+     * The code verifier for PKCE for OAuth 2.0. When set, the authorization
+     * URI will contain the Code Challenge and Code Challenge Method querystring
+     * parameters, and the token URI will contain the Code Verifier parameter.
+     *
+     * @see https://datatracker.ietf.org/doc/html/rfc7636
+     * @var ?string
+     */
+    private $codeVerifier;
+
+    /**
+     * For STS requests.
+     * A URI that indicates the target service or resource where the client
+     * intends to use the requested security token.
+     */
+    private ?string $resource;
+
+    /**
+     * For STS requests.
+     * A fetcher for the "subject_token", which is a security token that
+     * represents the identity of the party on behalf of whom the request is
+     * being made.
+     */
+    private ?ExternalAccountCredentialSourceInterface $subjectTokenFetcher;
+
+    /**
+     * For STS requests.
+     * An identifier, that indicates the type of the security token in the
+     * subjectToken parameter.
+     */
+    private ?string $subjectTokenType;
+
+    /**
+     * For STS requests.
+     * A security token that represents the identity of the acting party.
+     */
+    private ?string $actorToken;
+
+    /**
+     * For STS requests.
+     * An identifier that indicates the type of the security token in the
+     * actorToken parameter.
+     */
+    private ?string $actorTokenType;
+
+    /**
+     * From STS response.
+     * An identifier for the representation of the issued security token.
+     */
+    private ?string $issuedTokenType = null;
+
+    /**
+     * From STS response.
+     * An identifier for the representation of the issued security token.
+     *
+     * @var array<mixed>
+     */
+    private array $additionalOptions;
+
+    /**
+     * Create a new OAuthCredentials.
+     *
+     * The configuration array accepts various options
+     *
+     * - authorizationUri
+     *   The authorization server's HTTP endpoint capable of
+     *   authenticating the end-user and obtaining authorization.
+     *
+     * - tokenCredentialUri
+     *   The authorization server's HTTP endpoint capable of issuing
+     *   tokens and refreshing expired tokens.
+     *
+     * - clientId
+     *   A unique identifier issued to the client to identify itself to the
+     *   authorization server.
+     *
+     * - clientSecret
+     *   A shared symmetric secret issued by the authorization server,
+     *   which is used to authenticate the client.
+     *
+     * - scope
+     *   The scope of the access request, expressed either as an Array
+     *   or as a space-delimited String.
+     *
+     * - state
+     *   An arbitrary string designed to allow the client to maintain state.
+     *
+     * - redirectUri
+     *   The redirection URI used in the initial request.
+     *
+     * - username
+     *   The resource owner's username.
+     *
+     * - password
+     *   The resource owner's password.
+     *
+     * - issuer
+     *   Issuer ID when using assertion profile
+     *
+     * - audience
+     *   Target audience for assertions
+     *
+     * - expiry
+     *   Number of seconds assertions are valid for
+     *
+     * - signingKey
+     *   Signing key when using assertion profile
+     *
+     * - signingKeyId
+     *   Signing key id when using assertion profile
+     *
+     * - refreshToken
+     *   The refresh token associated with the access token
+     *   to be refreshed.
+     *
+     * - accessToken
+     *   The current access token for this client.
+     *
+     * - idToken
+     *   The current ID token for this client.
+     *
+     * - extensionParams
+     *   When using an extension grant type, this is the set of parameters used
+     *   by that extension.
+     *
+     * - codeVerifier
+     *   The code verifier for PKCE for OAuth 2.0.
+     *
+     * - resource
+     *   The target service or resource where the client ntends to use the
+     *   requested security token.
+     *
+     * - subjectTokenFetcher
+     *    A fetcher for the "subject_token", which is a security token that
+     *    represents the identity of the party on behalf of whom the request is
+     *    being made.
+     *
+     * - subjectTokenType
+     *   An identifier that indicates the type of the security token in the
+     *   subjectToken parameter.
+     *
+     * - actorToken
+     *   A security token that represents the identity of the acting party.
+     *
+     * - actorTokenType
+     *   An identifier for the representation of the issued security token.
+     *
+     * @param array<mixed> $config Configuration array
+     */
+    public function __construct(array $config)
+    {
+        $opts = array_merge([
+            'expiry' => self::DEFAULT_EXPIRY_SECONDS,
+            'extensionParams' => [],
+            'authorizationUri' => null,
+            'redirectUri' => null,
+            'tokenCredentialUri' => null,
+            'state' => null,
+            'username' => null,
+            'password' => null,
+            'clientId' => null,
+            'clientSecret' => null,
+            'issuer' => null,
+            'sub' => null,
+            'audience' => null,
+            'signingKey' => null,
+            'signingKeyId' => null,
+            'signingAlgorithm' => null,
+            'scope' => null,
+            'additionalClaims' => [],
+            'codeVerifier' => null,
+            'resource' => null,
+            'subjectTokenFetcher' => null,
+            'subjectTokenType' => null,
+            'actorToken' => null,
+            'actorTokenType' => null,
+            'additionalOptions' => [],
+        ], $config);
+
+        $this->setAuthorizationUri($opts['authorizationUri']);
+        $this->setRedirectUri($opts['redirectUri']);
+        $this->setTokenCredentialUri($opts['tokenCredentialUri']);
+        $this->setState($opts['state']);
+        $this->setUsername($opts['username']);
+        $this->setPassword($opts['password']);
+        $this->setClientId($opts['clientId']);
+        $this->setClientSecret($opts['clientSecret']);
+        $this->setIssuer($opts['issuer']);
+        $this->setSub($opts['sub']);
+        $this->setExpiry($opts['expiry']);
+        $this->setAudience($opts['audience']);
+        $this->setSigningKey($opts['signingKey']);
+        $this->setSigningKeyId($opts['signingKeyId']);
+        $this->setSigningAlgorithm($opts['signingAlgorithm']);
+        $this->setScope($opts['scope']);
+        $this->setExtensionParams($opts['extensionParams']);
+        $this->setAdditionalClaims($opts['additionalClaims']);
+        $this->setCodeVerifier($opts['codeVerifier']);
+
+        // for STS
+        $this->resource = $opts['resource'];
+        $this->subjectTokenFetcher = $opts['subjectTokenFetcher'];
+        $this->subjectTokenType = $opts['subjectTokenType'];
+        $this->actorToken = $opts['actorToken'];
+        $this->actorTokenType = $opts['actorTokenType'];
+        $this->additionalOptions = $opts['additionalOptions'];
+
+        $this->updateToken($opts);
+    }
+
+    /**
+     * Verifies the idToken if present.
+     *
+     * - if none is present, return null
+     * - if present, but invalid, raises DomainException.
+     * - otherwise returns the payload in the idtoken as a PHP object.
+     *
+     * The behavior of this method varies depending on the version of
+     * `firebase/php-jwt` you are using. In versions 6.0 and above, you cannot
+     * provide multiple $allowed_algs, and instead must provide an array of Key
+     * objects as the $publicKey.
+     *
+     * @param string|Key|Key[] $publicKey The public key to use to authenticate the token
+     * @param string|array<string> $allowed_algs algorithm or array of supported verification algorithms.
+     *        Providing more than one algorithm will throw an exception.
+     * @throws \DomainException if the token is missing an audience.
+     * @throws \DomainException if the audience does not match the one set in
+     *         the OAuth2 class instance.
+     * @throws \UnexpectedValueException If the token is invalid
+     * @throws \InvalidArgumentException If more than one value for allowed_algs is supplied
+     * @throws \Firebase\JWT\SignatureInvalidException If the signature is invalid.
+     * @throws \Firebase\JWT\BeforeValidException If the token is not yet valid.
+     * @throws \Firebase\JWT\ExpiredException If the token has expired.
+     * @return null|object
+     */
+    public function verifyIdToken($publicKey = null, $allowed_algs = [])
+    {
+        $idToken = $this->getIdToken();
+        if (is_null($idToken)) {
+            return null;
+        }
+
+        $resp = $this->jwtDecode($idToken, $publicKey, $allowed_algs);
+        if (!property_exists($resp, 'aud')) {
+            throw new \DomainException('No audience found the id token');
+        }
+        if ($resp->aud != $this->getAudience()) {
+            throw new \DomainException('Wrong audience present in the id token');
+        }
+
+        return $resp;
+    }
+
+    /**
+     * Obtains the encoded jwt from the instance data.
+     *
+     * @param array<mixed> $config array optional configuration parameters
+     * @return string
+     */
+    public function toJwt(array $config = [])
+    {
+        if (is_null($this->getSigningKey())) {
+            throw new \DomainException('No signing key available');
+        }
+        if (is_null($this->getSigningAlgorithm())) {
+            throw new \DomainException('No signing algorithm specified');
+        }
+        $now = time();
+
+        $opts = array_merge([
+            'skew' => self::DEFAULT_SKEW_SECONDS,
+        ], $config);
+
+        $assertion = [
+            'iss' => $this->getIssuer(),
+            'exp' => ($now + $this->getExpiry()),
+            'iat' => ($now - $opts['skew']),
+        ];
+        foreach ($assertion as $k => $v) {
+            if (is_null($v)) {
+                throw new \DomainException($k . ' should not be null');
+            }
+        }
+        if (!(is_null($this->getAudience()))) {
+            $assertion['aud'] = $this->getAudience();
+        }
+
+        if (!(is_null($this->getScope()))) {
+            $assertion['scope'] = $this->getScope();
+        }
+
+        if (empty($assertion['scope']) && empty($assertion['aud'])) {
+            throw new \DomainException('one of scope or aud should not be null');
+        }
+
+        if (!(is_null($this->getSub()))) {
+            $assertion['sub'] = $this->getSub();
+        }
+        $assertion += $this->getAdditionalClaims();
+
+        return JWT::encode(
+            $assertion,
+            $this->getSigningKey(),
+            $this->getSigningAlgorithm(),
+            $this->getSigningKeyId()
+        );
+    }
+
+    /**
+     * Generates a request for token credentials.
+     *
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @param array<mixed> $headers [optional] Additional headers to pass to
+     *        the token endpoint request.
+     * @return RequestInterface the authorization Url.
+     */
+    public function generateCredentialsRequest(?callable $httpHandler = null, $headers = [])
+    {
+        $uri = $this->getTokenCredentialUri();
+        if (is_null($uri)) {
+            throw new \DomainException('No token credential URI was set.');
+        }
+
+        $grantType = $this->getGrantType();
+        $params = ['grant_type' => $grantType];
+        switch ($grantType) {
+            case 'authorization_code':
+                $params['code'] = $this->getCode();
+                $params['redirect_uri'] = $this->getRedirectUri();
+                if ($this->codeVerifier) {
+                    $params['code_verifier'] = $this->codeVerifier;
+                }
+                $this->addClientCredentials($params);
+                break;
+            case 'password':
+                $params['username'] = $this->getUsername();
+                $params['password'] = $this->getPassword();
+                $this->addClientCredentials($params);
+                break;
+            case 'refresh_token':
+                $params['refresh_token'] = $this->getRefreshToken();
+                if (isset($this->getAdditionalClaims()['target_audience'])) {
+                    $params['target_audience'] = $this->getAdditionalClaims()['target_audience'];
+                }
+                $this->addClientCredentials($params);
+                break;
+            case self::JWT_URN:
+                $params['assertion'] = $this->toJwt();
+                break;
+            case self::STS_URN:
+                $token = $this->subjectTokenFetcher->fetchSubjectToken($httpHandler);
+                $params['subject_token'] = $token;
+                $params['subject_token_type'] = $this->subjectTokenType;
+                $params += array_filter([
+                    'resource'             => $this->resource,
+                    'audience'             => $this->audience,
+                    'scope'                => $this->getScope(),
+                    'requested_token_type' => self::STS_REQUESTED_TOKEN_TYPE,
+                    'actor_token'          => $this->actorToken,
+                    'actor_token_type'     => $this->actorTokenType,
+                ]);
+                if ($this->additionalOptions) {
+                    $params['options'] = json_encode($this->additionalOptions);
+                }
+                break;
+            default:
+                if (!is_null($this->getRedirectUri())) {
+                    # Grant type was supposed to be 'authorization_code', as there
+                    # is a redirect URI.
+                    throw new \DomainException('Missing authorization code');
+                }
+                unset($params['grant_type']);
+                if (!is_null($grantType)) {
+                    $params['grant_type'] = $grantType;
+                }
+                $params = array_merge($params, $this->getExtensionParams());
+        }
+
+        $headers = [
+            'Cache-Control' => 'no-store',
+            'Content-Type' => 'application/x-www-form-urlencoded',
+        ] + $headers;
+
+        return new Request(
+            'POST',
+            $uri,
+            $headers,
+            Query::build($params)
+        );
+    }
+
+    /**
+     * Fetches the auth tokens based on the current state.
+     *
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @param array<mixed> $headers [optional] If present, add these headers to the token
+     *        endpoint request.
+     * @return array<mixed> the response
+     */
+    public function fetchAuthToken(?callable $httpHandler = null, $headers = [])
+    {
+        if (is_null($httpHandler)) {
+            $httpHandler = HttpHandlerFactory::build(HttpClientCache::getHttpClient());
+        }
+
+        $response = $httpHandler($this->generateCredentialsRequest($httpHandler, $headers));
+        $credentials = $this->parseTokenResponse($response);
+        $this->updateToken($credentials);
+        if (isset($credentials['scope'])) {
+            $this->setGrantedScope($credentials['scope']);
+        }
+
+        return $credentials;
+    }
+
+    /**
+     * @deprecated
+     *
+     * Obtains a key that can used to cache the results of #fetchAuthToken.
+     *
+     * The key is derived from the scopes.
+     *
+     * @return ?string a key that may be used to cache the auth token.
+     */
+    public function getCacheKey()
+    {
+        if (is_array($this->scope)) {
+            return implode(':', $this->scope);
+        }
+
+        if ($this->audience) {
+            return $this->audience;
+        }
+
+        // If scope has not set, return null to indicate no caching.
+        return null;
+    }
+
+    /**
+     * Gets this instance's SubjectTokenFetcher
+     *
+     * @return null|ExternalAccountCredentialSourceInterface
+     */
+    public function getSubjectTokenFetcher(): ?ExternalAccountCredentialSourceInterface
+    {
+        return $this->subjectTokenFetcher;
+    }
+
+    /**
+     * Parses the fetched tokens.
+     *
+     * @param ResponseInterface $resp the response.
+     * @return array<mixed> the tokens parsed from the response body.
+     * @throws \Exception
+     */
+    public function parseTokenResponse(ResponseInterface $resp)
+    {
+        $body = (string) $resp->getBody();
+        if ($resp->hasHeader('Content-Type') &&
+            $resp->getHeaderLine('Content-Type') == 'application/x-www-form-urlencoded'
+        ) {
+            $res = [];
+            parse_str($body, $res);
+
+            return $res;
+        }
+
+        // Assume it's JSON; if it's not throw an exception
+        if (null === $res = json_decode($body, true)) {
+            throw new \Exception('Invalid JSON response');
+        }
+
+        return $res;
+    }
+
+    /**
+     * Updates an OAuth 2.0 client.
+     *
+     * Example:
+     * ```
+     * $oauth->updateToken([
+     *     'refresh_token' => 'n4E9O119d',
+     *     'access_token' => 'FJQbwq9',
+     *     'expires_in' => 3600
+     * ]);
+     * ```
+     *
+     * @param array<mixed> $config
+     *  The configuration parameters related to the token.
+     *
+     *  - refresh_token
+     *    The refresh token associated with the access token
+     *    to be refreshed.
+     *
+     *  - access_token
+     *    The current access token for this client.
+     *
+     *  - id_token
+     *    The current ID token for this client.
+     *
+     *  - expires_in
+     *    The time in seconds until access token expiration.
+     *
+     *  - expires_at
+     *    The time as an integer number of seconds since the Epoch
+     *
+     *  - issued_at
+     *    The timestamp that the token was issued at.
+     * @return void
+     */
+    public function updateToken(array $config)
+    {
+        $opts = array_merge([
+            'extensionParams' => [],
+            'access_token' => null,
+            'id_token' => null,
+            'expires_in' => null,
+            'expires_at' => null,
+            'issued_at' => null,
+            'scope' => null,
+        ], $config);
+
+        $this->setExpiresAt($opts['expires_at']);
+        $this->setExpiresIn($opts['expires_in']);
+        // By default, the token is issued at `Time.now` when `expiresIn` is set,
+        // but this can be used to supply a more precise time.
+        if (!is_null($opts['issued_at'])) {
+            $this->setIssuedAt($opts['issued_at']);
+        }
+
+        $this->setAccessToken($opts['access_token']);
+        $this->setIdToken($opts['id_token']);
+
+        // The refresh token should only be updated if a value is explicitly
+        // passed in, as some access token responses do not include a refresh
+        // token.
+        if (array_key_exists('refresh_token', $opts)) {
+            $this->setRefreshToken($opts['refresh_token']);
+        }
+
+        // Required for STS response. An identifier for the representation of
+        // the issued security token.
+        if (array_key_exists('issued_token_type', $opts)) {
+            $this->issuedTokenType = $opts['issued_token_type'];
+        }
+    }
+
+    /**
+     * Builds the authorization Uri that the user should be redirected to.
+     *
+     * @param array<mixed> $config configuration options that customize the return url.
+     * @return UriInterface the authorization Url.
+     * @throws InvalidArgumentException
+     */
+    public function buildFullAuthorizationUri(array $config = [])
+    {
+        if (is_null($this->getAuthorizationUri())) {
+            throw new InvalidArgumentException(
+                'requires an authorizationUri to have been set'
+            );
+        }
+
+        $params = array_merge([
+            'response_type' => 'code',
+            'access_type' => 'offline',
+            'client_id' => $this->clientId,
+            'redirect_uri' => $this->redirectUri,
+            'state' => $this->state,
+            'scope' => $this->getScope(),
+        ], $config);
+
+        // Validate the auth_params
+        if (is_null($params['client_id'])) {
+            throw new InvalidArgumentException(
+                'missing the required client identifier'
+            );
+        }
+        if (is_null($params['redirect_uri'])) {
+            throw new InvalidArgumentException('missing the required redirect URI');
+        }
+        if (!empty($params['prompt']) && !empty($params['approval_prompt'])) {
+            throw new InvalidArgumentException(
+                'prompt and approval_prompt are mutually exclusive'
+            );
+        }
+        if ($this->codeVerifier) {
+            $params['code_challenge'] = $this->getCodeChallenge($this->codeVerifier);
+            $params['code_challenge_method'] = $this->getCodeChallengeMethod();
+        }
+
+        // Construct the uri object; return it if it is valid.
+        $result = clone $this->authorizationUri;
+        $existingParams = Query::parse($result->getQuery());
+
+        $result = $result->withQuery(
+            Query::build(array_merge($existingParams, $params))
+        );
+
+        if ($result->getScheme() != 'https') {
+            throw new InvalidArgumentException(
+                'Authorization endpoint must be protected by TLS'
+            );
+        }
+
+        return $result;
+    }
+
+    /**
+     * @return string|null
+     */
+    public function getCodeVerifier(): ?string
+    {
+        return $this->codeVerifier;
+    }
+
+    /**
+     * A cryptographically random string that is used to correlate the
+     * authorization request to the token request.
+     *
+     * The code verifier for PKCE for OAuth 2.0. When set, the authorization
+     * URI will contain the Code Challenge and Code Challenge Method querystring
+     * parameters, and the token URI will contain the Code Verifier parameter.
+     *
+     * @see https://datatracker.ietf.org/doc/html/rfc7636
+     *
+     * @param string|null $codeVerifier
+     */
+    public function setCodeVerifier(?string $codeVerifier): void
+    {
+        $this->codeVerifier = $codeVerifier;
+    }
+
+    /**
+     * Generates a random 128-character string for the "code_verifier" parameter
+     * in PKCE for OAuth 2.0. This is a cryptographically random string that is
+     * determined using random_int, hashed using "hash" and sha256, and base64
+     * encoded.
+     *
+     * When this method is called, the code verifier is set on the object.
+     *
+     * @return string
+     */
+    public function generateCodeVerifier(): string
+    {
+        return $this->codeVerifier = $this->generateRandomString(128);
+    }
+
+    private function getCodeChallenge(string $randomString): string
+    {
+        return rtrim(strtr(base64_encode(hash('sha256', $randomString, true)), '+/', '-_'), '=');
+    }
+
+    private function getCodeChallengeMethod(): string
+    {
+        return 'S256';
+    }
+
+    private function generateRandomString(int $length): string
+    {
+        $validChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~';
+        $validCharsLen = strlen($validChars);
+        $str = '';
+        $i = 0;
+        while ($i++ < $length) {
+            $str .= $validChars[random_int(0, $validCharsLen - 1)];
+        }
+        return $str;
+    }
+
+    /**
+     * Sets the authorization server's HTTP endpoint capable of authenticating
+     * the end-user and obtaining authorization.
+     *
+     * @param string $uri
+     * @return void
+     */
+    public function setAuthorizationUri($uri)
+    {
+        $this->authorizationUri = $this->coerceUri($uri);
+    }
+
+    /**
+     * Gets the authorization server's HTTP endpoint capable of authenticating
+     * the end-user and obtaining authorization.
+     *
+     * @return ?UriInterface
+     */
+    public function getAuthorizationUri()
+    {
+        return $this->authorizationUri;
+    }
+
+    /**
+     * Gets the authorization server's HTTP endpoint capable of issuing tokens
+     * and refreshing expired tokens.
+     *
+     * @return ?UriInterface
+     */
+    public function getTokenCredentialUri()
+    {
+        return $this->tokenCredentialUri;
+    }
+
+    /**
+     * Sets the authorization server's HTTP endpoint capable of issuing tokens
+     * and refreshing expired tokens.
+     *
+     * @param string $uri
+     * @return void
+     */
+    public function setTokenCredentialUri($uri)
+    {
+        $this->tokenCredentialUri = $this->coerceUri($uri);
+    }
+
+    /**
+     * Gets the redirection URI used in the initial request.
+     *
+     * @return ?string
+     */
+    public function getRedirectUri()
+    {
+        return $this->redirectUri;
+    }
+
+    /**
+     * Sets the redirection URI used in the initial request.
+     *
+     * @param ?string $uri
+     * @return void
+     */
+    public function setRedirectUri($uri)
+    {
+        if (is_null($uri)) {
+            $this->redirectUri = null;
+
+            return;
+        }
+        // redirect URI must be absolute
+        if (!$this->isAbsoluteUri($uri)) {
+            // "postmessage" is a reserved URI string in Google-land
+            // @see https://developers.google.com/identity/sign-in/web/server-side-flow
+            if ('postmessage' !== (string) $uri) {
+                throw new InvalidArgumentException(
+                    'Redirect URI must be absolute'
+                );
+            }
+        }
+        $this->redirectUri = (string) $uri;
+    }
+
+    /**
+     * Gets the scope of the access requests as a space-delimited String.
+     *
+     * @return ?string
+     */
+    public function getScope()
+    {
+        if (is_null($this->scope)) {
+            return $this->scope;
+        }
+
+        return implode(' ', $this->scope);
+    }
+
+    /**
+     * Gets the subject token type
+     *
+     * @return ?string
+     */
+    public function getSubjectTokenType(): ?string
+    {
+        return $this->subjectTokenType;
+    }
+
+    /**
+     * Sets the scope of the access request, expressed either as an Array or as
+     * a space-delimited String.
+     *
+     * @param string|array<string>|null $scope
+     * @return void
+     * @throws InvalidArgumentException
+     */
+    public function setScope($scope)
+    {
+        if (is_null($scope)) {
+            $this->scope = null;
+        } elseif (is_string($scope)) {
+            $this->scope = explode(' ', $scope);
+        } elseif (is_array($scope)) {
+            foreach ($scope as $s) {
+                $pos = strpos($s, ' ');
+                if ($pos !== false) {
+                    throw new InvalidArgumentException(
+                        'array scope values should not contain spaces'
+                    );
+                }
+            }
+            $this->scope = $scope;
+        } else {
+            throw new InvalidArgumentException(
+                'scopes should be a string or array of strings'
+            );
+        }
+    }
+
+    /**
+     * Gets the current grant type.
+     *
+     * @return ?string
+     */
+    public function getGrantType()
+    {
+        if (!is_null($this->grantType)) {
+            return $this->grantType;
+        }
+
+        // Returns the inferred grant type, based on the current object instance
+        // state.
+        if (!is_null($this->code)) {
+            return 'authorization_code';
+        }
+
+        if (!is_null($this->refreshToken)) {
+            return 'refresh_token';
+        }
+
+        if (!is_null($this->username) && !is_null($this->password)) {
+            return 'password';
+        }
+
+        if (!is_null($this->issuer) && !is_null($this->signingKey)) {
+            return self::JWT_URN;
+        }
+
+        if (!is_null($this->subjectTokenFetcher) && !is_null($this->subjectTokenType)) {
+            return self::STS_URN;
+        }
+
+        return null;
+    }
+
+    /**
+     * Sets the current grant type.
+     *
+     * @param string $grantType
+     * @return void
+     * @throws InvalidArgumentException
+     */
+    public function setGrantType($grantType)
+    {
+        if (in_array($grantType, self::$knownGrantTypes)) {
+            $this->grantType = $grantType;
+        } else {
+            // validate URI
+            if (!$this->isAbsoluteUri($grantType)) {
+                throw new InvalidArgumentException(
+                    'invalid grant type'
+                );
+            }
+            $this->grantType = (string) $grantType;
+        }
+    }
+
+    /**
+     * Gets an arbitrary string designed to allow the client to maintain state.
+     *
+     * @return string
+     */
+    public function getState()
+    {
+        return $this->state;
+    }
+
+    /**
+     * Sets an arbitrary string designed to allow the client to maintain state.
+     *
+     * @param string $state
+     * @return void
+     */
+    public function setState($state)
+    {
+        $this->state = $state;
+    }
+
+    /**
+     * Gets the authorization code issued to this client.
+     *
+     * @return string
+     */
+    public function getCode()
+    {
+        return $this->code;
+    }
+
+    /**
+     * Sets the authorization code issued to this client.
+     *
+     * @param string $code
+     * @return void
+     */
+    public function setCode($code)
+    {
+        $this->code = $code;
+    }
+
+    /**
+     * Gets the resource owner's username.
+     *
+     * @return string
+     */
+    public function getUsername()
+    {
+        return $this->username;
+    }
+
+    /**
+     * Sets the resource owner's username.
+     *
+     * @param string $username
+     * @return void
+     */
+    public function setUsername($username)
+    {
+        $this->username = $username;
+    }
+
+    /**
+     * Gets the resource owner's password.
+     *
+     * @return string
+     */
+    public function getPassword()
+    {
+        return $this->password;
+    }
+
+    /**
+     * Sets the resource owner's password.
+     *
+     * @param string $password
+     * @return void
+     */
+    public function setPassword($password)
+    {
+        $this->password = $password;
+    }
+
+    /**
+     * Sets a unique identifier issued to the client to identify itself to the
+     * authorization server.
+     *
+     * @return string
+     */
+    public function getClientId()
+    {
+        return $this->clientId;
+    }
+
+    /**
+     * Sets a unique identifier issued to the client to identify itself to the
+     * authorization server.
+     *
+     * @param string $clientId
+     * @return void
+     */
+    public function setClientId($clientId)
+    {
+        $this->clientId = $clientId;
+    }
+
+    /**
+     * Gets a shared symmetric secret issued by the authorization server, which
+     * is used to authenticate the client.
+     *
+     * @return string
+     */
+    public function getClientSecret()
+    {
+        return $this->clientSecret;
+    }
+
+    /**
+     * Sets a shared symmetric secret issued by the authorization server, which
+     * is used to authenticate the client.
+     *
+     * @param string $clientSecret
+     * @return void
+     */
+    public function setClientSecret($clientSecret)
+    {
+        $this->clientSecret = $clientSecret;
+    }
+
+    /**
+     * Gets the Issuer ID when using assertion profile.
+     *
+     * @return ?string
+     */
+    public function getIssuer()
+    {
+        return $this->issuer;
+    }
+
+    /**
+     * Sets the Issuer ID when using assertion profile.
+     *
+     * @param string $issuer
+     * @return void
+     */
+    public function setIssuer($issuer)
+    {
+        $this->issuer = $issuer;
+    }
+
+    /**
+     * Gets the target sub when issuing assertions.
+     *
+     * @return ?string
+     */
+    public function getSub()
+    {
+        return $this->sub;
+    }
+
+    /**
+     * Sets the target sub when issuing assertions.
+     *
+     * @param string $sub
+     * @return void
+     */
+    public function setSub($sub)
+    {
+        $this->sub = $sub;
+    }
+
+    /**
+     * Gets the target audience when issuing assertions.
+     *
+     * @return ?string
+     */
+    public function getAudience()
+    {
+        return $this->audience;
+    }
+
+    /**
+     * Sets the target audience when issuing assertions.
+     *
+     * @param string $audience
+     * @return void
+     */
+    public function setAudience($audience)
+    {
+        $this->audience = $audience;
+    }
+
+    /**
+     * Gets the signing key when using an assertion profile.
+     *
+     * @return ?string
+     */
+    public function getSigningKey()
+    {
+        return $this->signingKey;
+    }
+
+    /**
+     * Sets the signing key when using an assertion profile.
+     *
+     * @param string $signingKey
+     * @return void
+     */
+    public function setSigningKey($signingKey)
+    {
+        $this->signingKey = $signingKey;
+    }
+
+    /**
+     * Gets the signing key id when using an assertion profile.
+     *
+     * @return ?string
+     */
+    public function getSigningKeyId()
+    {
+        return $this->signingKeyId;
+    }
+
+    /**
+     * Sets the signing key id when using an assertion profile.
+     *
+     * @param string $signingKeyId
+     * @return void
+     */
+    public function setSigningKeyId($signingKeyId)
+    {
+        $this->signingKeyId = $signingKeyId;
+    }
+
+    /**
+     * Gets the signing algorithm when using an assertion profile.
+     *
+     * @return ?string
+     */
+    public function getSigningAlgorithm()
+    {
+        return $this->signingAlgorithm;
+    }
+
+    /**
+     * Sets the signing algorithm when using an assertion profile.
+     *
+     * @param ?string $signingAlgorithm
+     * @return void
+     */
+    public function setSigningAlgorithm($signingAlgorithm)
+    {
+        if (is_null($signingAlgorithm)) {
+            $this->signingAlgorithm = null;
+        } elseif (!in_array($signingAlgorithm, self::$knownSigningAlgorithms)) {
+            throw new InvalidArgumentException('unknown signing algorithm');
+        } else {
+            $this->signingAlgorithm = $signingAlgorithm;
+        }
+    }
+
+    /**
+     * Gets the set of parameters used by extension when using an extension
+     * grant type.
+     *
+     * @return array<mixed>
+     */
+    public function getExtensionParams()
+    {
+        return $this->extensionParams;
+    }
+
+    /**
+     * Sets the set of parameters used by extension when using an extension
+     * grant type.
+     *
+     * @param array<mixed> $extensionParams
+     * @return void
+     */
+    public function setExtensionParams($extensionParams)
+    {
+        $this->extensionParams = $extensionParams;
+    }
+
+    /**
+     * Gets the number of seconds assertions are valid for.
+     *
+     * @return int
+     */
+    public function getExpiry()
+    {
+        return $this->expiry;
+    }
+
+    /**
+     * Sets the number of seconds assertions are valid for.
+     *
+     * @param int $expiry
+     * @return void
+     */
+    public function setExpiry($expiry)
+    {
+        $this->expiry = $expiry;
+    }
+
+    /**
+     * Gets the lifetime of the access token in seconds.
+     *
+     * @return int
+     */
+    public function getExpiresIn()
+    {
+        return $this->expiresIn;
+    }
+
+    /**
+     * Sets the lifetime of the access token in seconds.
+     *
+     * @param ?int $expiresIn
+     * @return void
+     */
+    public function setExpiresIn($expiresIn)
+    {
+        if (is_null($expiresIn)) {
+            $this->expiresIn = null;
+            $this->issuedAt = null;
+        } else {
+            $this->issuedAt = time();
+            $this->expiresIn = (int) $expiresIn;
+        }
+    }
+
+    /**
+     * Gets the time the current access token expires at.
+     *
+     * @return ?int
+     */
+    public function getExpiresAt()
+    {
+        if (!is_null($this->expiresAt)) {
+            return $this->expiresAt;
+        }
+
+        if (!is_null($this->issuedAt) && !is_null($this->expiresIn)) {
+            return $this->issuedAt + $this->expiresIn;
+        }
+
+        return null;
+    }
+
+    /**
+     * Returns true if the acccess token has expired.
+     *
+     * @return bool
+     */
+    public function isExpired()
+    {
+        $expiration = $this->getExpiresAt();
+        $now = time();
+
+        return !is_null($expiration) && $now >= $expiration;
+    }
+
+    /**
+     * Sets the time the current access token expires at.
+     *
+     * @param int $expiresAt
+     * @return void
+     */
+    public function setExpiresAt($expiresAt)
+    {
+        $this->expiresAt = $expiresAt;
+    }
+
+    /**
+     * Gets the time the current access token was issued at.
+     *
+     * @return ?int
+     */
+    public function getIssuedAt()
+    {
+        return $this->issuedAt;
+    }
+
+    /**
+     * Sets the time the current access token was issued at.
+     *
+     * @param int $issuedAt
+     * @return void
+     */
+    public function setIssuedAt($issuedAt)
+    {
+        $this->issuedAt = $issuedAt;
+    }
+
+    /**
+     * Gets the current access token.
+     *
+     * @return ?string
+     */
+    public function getAccessToken()
+    {
+        return $this->accessToken;
+    }
+
+    /**
+     * Sets the current access token.
+     *
+     * @param string $accessToken
+     * @return void
+     */
+    public function setAccessToken($accessToken)
+    {
+        $this->accessToken = $accessToken;
+    }
+
+    /**
+     * Gets the current ID token.
+     *
+     * @return ?string
+     */
+    public function getIdToken()
+    {
+        return $this->idToken;
+    }
+
+    /**
+     * Sets the current ID token.
+     *
+     * @param string $idToken
+     * @return void
+     */
+    public function setIdToken($idToken)
+    {
+        $this->idToken = $idToken;
+    }
+
+    /**
+     * Get the granted space-separated scopes (if they exist) for the last
+     * fetched token.
+     *
+     * @return string|null
+     */
+    public function getGrantedScope()
+    {
+        return $this->grantedScope;
+    }
+
+    /**
+     * Sets the current ID token.
+     *
+     * @param string $grantedScope
+     * @return void
+     */
+    public function setGrantedScope($grantedScope)
+    {
+        $this->grantedScope = $grantedScope;
+    }
+
+    /**
+     * Gets the refresh token associated with the current access token.
+     *
+     * @return ?string
+     */
+    public function getRefreshToken()
+    {
+        return $this->refreshToken;
+    }
+
+    /**
+     * Sets the refresh token associated with the current access token.
+     *
+     * @param string $refreshToken
+     * @return void
+     */
+    public function setRefreshToken($refreshToken)
+    {
+        $this->refreshToken = $refreshToken;
+    }
+
+    /**
+     * Sets additional claims to be included in the JWT token
+     *
+     * @param array<mixed> $additionalClaims
+     * @return void
+     */
+    public function setAdditionalClaims(array $additionalClaims)
+    {
+        $this->additionalClaims = $additionalClaims;
+    }
+
+    /**
+     * Gets the additional claims to be included in the JWT token.
+     *
+     * @return array<mixed>
+     */
+    public function getAdditionalClaims()
+    {
+        return $this->additionalClaims;
+    }
+
+    /**
+     * Gets the additional claims to be included in the JWT token.
+     *
+     * @return ?string
+     */
+    public function getIssuedTokenType()
+    {
+        return $this->issuedTokenType;
+    }
+
+    /**
+     * The expiration of the last received token.
+     *
+     * @return array<mixed>|null
+     */
+    public function getLastReceivedToken()
+    {
+        if ($token = $this->getAccessToken()) {
+            // the bare necessity of an auth token
+            $authToken = [
+                'access_token' => $token,
+                'expires_at' => $this->getExpiresAt(),
+            ];
+        } elseif ($idToken = $this->getIdToken()) {
+            $authToken = [
+                'id_token' => $idToken,
+                'expires_at' => $this->getExpiresAt(),
+            ];
+        } else {
+            return null;
+        }
+
+        if ($expiresIn = $this->getExpiresIn()) {
+            $authToken['expires_in'] = $expiresIn;
+        }
+        if ($issuedAt = $this->getIssuedAt()) {
+            $authToken['issued_at'] = $issuedAt;
+        }
+        if ($refreshToken = $this->getRefreshToken()) {
+            $authToken['refresh_token'] = $refreshToken;
+        }
+
+        return $authToken;
+    }
+
+    /**
+     * Get the client ID.
+     *
+     * Alias of {@see Google\Auth\OAuth2::getClientId()}.
+     *
+     * @param callable|null $httpHandler
+     * @return string
+     * @access private
+     */
+    public function getClientName(?callable $httpHandler = null)
+    {
+        return $this->getClientId();
+    }
+
+    /**
+     * @todo handle uri as array
+     *
+     * @param ?string $uri
+     * @return null|UriInterface
+     */
+    private function coerceUri($uri)
+    {
+        if (is_null($uri)) {
+            return null;
+        }
+
+        return Utils::uriFor($uri);
+    }
+
+    /**
+     * @param string $idToken
+     * @param Key|Key[]|string|string[] $publicKey
+     * @param string|string[] $allowedAlgs
+     * @return object
+     */
+    private function jwtDecode($idToken, $publicKey, $allowedAlgs)
+    {
+        $keys = $this->getFirebaseJwtKeys($publicKey, $allowedAlgs);
+
+        // Default exception if none are caught. We are using the same exception
+        // class and message from firebase/php-jwt to preserve backwards
+        // compatibility.
+        $e = new \InvalidArgumentException('Key may not be empty');
+        foreach ($keys as $key) {
+            try {
+                return JWT::decode($idToken, $key);
+            } catch (\Exception $e) {
+                // try next alg
+            }
+        }
+        throw $e;
+    }
+
+    /**
+     * @param Key|Key[]|string|string[] $publicKey
+     * @param string|string[] $allowedAlgs
+     * @return Key[]
+     */
+    private function getFirebaseJwtKeys($publicKey, $allowedAlgs)
+    {
+        // If $publicKey is instance of Key, return it
+        if ($publicKey instanceof Key) {
+            return [$publicKey];
+        }
+
+        // If $allowedAlgs is empty, $publicKey must be Key or Key[].
+        if (empty($allowedAlgs)) {
+            $keys = [];
+            foreach ((array) $publicKey as $kid => $pubKey) {
+                if (!$pubKey instanceof Key) {
+                    throw new \InvalidArgumentException(sprintf(
+                        'When allowed algorithms is empty, the public key must'
+                        . 'be an instance of %s or an array of %s objects',
+                        Key::class,
+                        Key::class
+                    ));
+                }
+                $keys[$kid] = $pubKey;
+            }
+            return $keys;
+        }
+
+        $allowedAlg = null;
+        if (is_string($allowedAlgs)) {
+            $allowedAlg = $allowedAlgs;
+        } elseif (is_array($allowedAlgs)) {
+            if (count($allowedAlgs) > 1) {
+                throw new \InvalidArgumentException(
+                    'To have multiple allowed algorithms, You must provide an'
+                    . ' array of Firebase\JWT\Key objects.'
+                    . ' See https://github.com/firebase/php-jwt for more information.'
+                );
+            }
+            $allowedAlg = array_pop($allowedAlgs);
+        } else {
+            throw new \InvalidArgumentException('allowed algorithms must be a string or array.');
+        }
+
+        if (is_array($publicKey)) {
+            // When publicKey is greater than 1, create keys with the single alg.
+            $keys = [];
+            foreach ($publicKey as $kid => $pubKey) {
+                if ($pubKey instanceof Key) {
+                    $keys[$kid] = $pubKey;
+                } else {
+                    $keys[$kid] = new Key($pubKey, $allowedAlg);
+                }
+            }
+            return $keys;
+        }
+
+        return [new Key($publicKey, $allowedAlg)];
+    }
+
+    /**
+     * Determines if the URI is absolute based on its scheme and host or path
+     * (RFC 3986).
+     *
+     * @param string $uri
+     * @return bool
+     */
+    private function isAbsoluteUri($uri)
+    {
+        $uri = $this->coerceUri($uri);
+
+        return $uri->getScheme() && ($uri->getHost() || $uri->getPath());
+    }
+
+    /**
+     * @param array<mixed> $params
+     * @return array<mixed>
+     */
+    private function addClientCredentials(&$params)
+    {
+        $clientId = $this->getClientId();
+        $clientSecret = $this->getClientSecret();
+
+        if ($clientId && $clientSecret) {
+            $params['client_id'] = $clientId;
+            $params['client_secret'] = $clientSecret;
+        }
+
+        return $params;
+    }
+}
Index: vendor/google/auth/src/ProjectIdProviderInterface.php
===================================================================
--- vendor/google/auth/src/ProjectIdProviderInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/ProjectIdProviderInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,32 @@
+<?php
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+/**
+ * Describes a Credentials object which supports fetching the project ID.
+ */
+interface ProjectIdProviderInterface
+{
+    /**
+     * Get the project ID.
+     *
+     * @param callable|null $httpHandler Callback which delivers psr7 request
+     * @return string|null
+     */
+    public function getProjectId(?callable $httpHandler = null);
+}
Index: vendor/google/auth/src/ServiceAccountSignerTrait.php
===================================================================
--- vendor/google/auth/src/ServiceAccountSignerTrait.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/ServiceAccountSignerTrait.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,56 @@
+<?php
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+use phpseclib3\Crypt\PublicKeyLoader;
+use phpseclib3\Crypt\RSA;
+
+/**
+ * Sign a string using a Service Account private key.
+ */
+trait ServiceAccountSignerTrait
+{
+    /**
+     * Sign a string using the service account private key.
+     *
+     * @param string $stringToSign
+     * @param bool $forceOpenssl Whether to use OpenSSL regardless of
+     *        whether phpseclib is installed. **Defaults to** `false`.
+     * @return string
+     */
+    public function signBlob($stringToSign, $forceOpenssl = false)
+    {
+        $privateKey = $this->auth->getSigningKey();
+
+        $signedString = '';
+        if (class_exists(phpseclib3\Crypt\RSA::class) && !$forceOpenssl) {
+            $key = PublicKeyLoader::load($privateKey);
+            $rsa = $key->withHash('sha256')->withPadding(RSA::SIGNATURE_PKCS1);
+
+            $signedString = $rsa->sign($stringToSign);
+        } elseif (extension_loaded('openssl')) {
+            openssl_sign($stringToSign, $signedString, $privateKey, 'sha256WithRSAEncryption');
+        } else {
+            // @codeCoverageIgnoreStart
+            throw new \RuntimeException('OpenSSL is not installed.');
+        }
+        // @codeCoverageIgnoreEnd
+
+        return base64_encode($signedString);
+    }
+}
Index: vendor/google/auth/src/SignBlobInterface.php
===================================================================
--- vendor/google/auth/src/SignBlobInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/SignBlobInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,44 @@
+<?php
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+/**
+ * Describes a class which supports signing arbitrary strings.
+ */
+interface SignBlobInterface extends FetchAuthTokenInterface
+{
+    /**
+     * Sign a string using the method which is best for a given credentials type.
+     *
+     * @param string $stringToSign The string to sign.
+     * @param bool $forceOpenssl Require use of OpenSSL for local signing. Does
+     *        not apply to signing done using external services. **Defaults to**
+     *        `false`.
+     * @return string The resulting signature. Value should be base64-encoded.
+     */
+    public function signBlob($stringToSign, $forceOpenssl = false);
+
+    /**
+     * Returns the current Client Name.
+     *
+     * @param callable|null $httpHandler callback which delivers psr7 request, if
+     *     one is required to obtain a client name.
+     * @return string
+     */
+    public function getClientName(?callable $httpHandler = null);
+}
Index: vendor/google/auth/src/UpdateMetadataInterface.php
===================================================================
--- vendor/google/auth/src/UpdateMetadataInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/UpdateMetadataInterface.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,41 @@
+<?php
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+/**
+ * Describes a Credentials object which supports updating request metadata
+ * (request headers).
+ */
+interface UpdateMetadataInterface
+{
+    const AUTH_METADATA_KEY = 'authorization';
+
+    /**
+     * Updates metadata with the authorization token.
+     *
+     * @param array<mixed> $metadata metadata hashmap
+     * @param string $authUri optional auth uri
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @return array<mixed> updated metadata hashmap
+     */
+    public function updateMetadata(
+        $metadata,
+        $authUri = null,
+        ?callable $httpHandler = null
+    );
+}
Index: vendor/google/auth/src/UpdateMetadataTrait.php
===================================================================
--- vendor/google/auth/src/UpdateMetadataTrait.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
+++ vendor/google/auth/src/UpdateMetadataTrait.php	(revision e3d4e0a8bc0f13135f27c0b055b5c00f64a28f01)
@@ -0,0 +1,74 @@
+<?php
+/*
+ * Copyright 2023 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Google\Auth;
+
+/**
+ * Provides shared methods for updating request metadata (request headers).
+ *
+ * Should implement {@see UpdateMetadataInterface} and {@see FetchAuthTokenInterface}.
+ *
+ * @internal
+ */
+trait UpdateMetadataTrait
+{
+    use MetricsTrait;
+
+    /**
+     * export a callback function which updates runtime metadata.
+     *
+     * @return callable updateMetadata function
+     * @deprecated
+     */
+    public function getUpdateMetadataFunc()
+    {
+        return [$this, 'updateMetadata'];
+    }
+
+    /**
+     * Updates metadata with the authorization token.
+     *
+     * @param array<mixed> $metadata metadata hashmap
+     * @param string $authUri optional auth uri
+     * @param callable|null $httpHandler callback which delivers psr7 request
+     * @return array<mixed> updated metadata hashmap
+     */
+    public function updateMetadata(
+        $metadata,
+        $authUri = null,
+        ?callable $httpHandler = null
+    ) {
+        $metadata_copy = $metadata;
+
+        // We do need to set the service api usage metrics irrespective even if
+        // the auth token is set because invoking this method with auth tokens
+        // would mean the intention is to just explicitly set the metrics metadata.
+        $metadata_copy = $this->applyServiceApiUsageMetrics($metadata_copy);
+
+        if (isset($metadata_copy[self::AUTH_METADATA_KEY])) {
+            // Auth metadata has already been set
+            return $metadata_copy;
+        }
+        $result = $this->fetchAuthToken($httpHandler);
+        if (isset($result['access_token'])) {
+            $metadata_copy[self::AUTH_METADATA_KEY] = ['Bearer ' . $result['access_token']];
+        } elseif (isset($result['id_token'])) {
+            $metadata_copy[self::AUTH_METADATA_KEY] = ['Bearer ' . $result['id_token']];
+        }
+        return $metadata_copy;
+    }
+}
