### Install Core and Per-API Packages Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Install the necessary Google API client libraries using the .NET CLI. ```bash dotnet add package Google.Apis.Auth dotnet add package Google.Apis dotnet add package Google.Apis.Drive.v3 dotnet add package Google.Apis.Calendar.v3 dotnet add package Google.Apis.Sheets.v4 dotnet add package Google.Apis.YouTube.v3 dotnet add package Google.Apis.Storage.v1 ``` -------------------------------- ### Download Media in Chunks with MediaDownloader Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Use MediaDownloader to download large files in configurable chunks, supporting range requests and progress callbacks. Set the ChunkSize to control download chunk size, and handle download status updates via the ProgressChanged event. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Download; using Google.Apis.Services; GoogleCredential credential = (await GoogleCredential.GetApplicationDefaultAsync()) .CreateScoped(DriveService.ScopeConstants.DriveReadonly); var driveService = new DriveService(new BaseClientService.Initializer { HttpClientInitializer = credential, ApplicationName = "DownloadDemo" }); string fileId = "1aBcDeFgHiJkLmNoPqRsTuVwXyZ"; using var outputStream = new FileStream("/local/downloaded.pdf", FileMode.Create); var downloader = new MediaDownloader(driveService); downloader.ChunkSize = MediaDownloader.MaximumChunkSize; // 10 MB per chunk // Track progress downloader.ProgressChanged += progress => { if (progress.Status == DownloadStatus.Downloading) Console.WriteLine($ ``` -------------------------------- ### ASP.NET Core Integration — `AddGoogleOpenIdConnect` Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Integrates Google Sign-In into ASP.NET Core applications using OpenID Connect, enabling authentication and authorization with Google accounts. Includes the `[GoogleScopedAuthorize]` attribute for incremental scope authorization. ```APIDOC ## ASP.NET Core Integration — `AddGoogleOpenIdConnect` The `Google.Apis.Auth.AspNetCore3` package provides an OpenID Connect handler and a `[GoogleScopedAuthorize]` attribute that enables incremental OAuth2 scope authorization in ASP.NET Core web applications. ```csharp // Program.cs / Startup.cs using Google.Apis.Auth.AspNetCore3; using Google.Apis.Drive.v3; var builder = WebApplication.CreateBuilder(args); builder.Services .AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie() .AddGoogleOpenIdConnect(options => { options.ClientId = builder.Configuration["Authentication:Google:ClientId"]; options.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"]; }); builder.Services.AddControllersWithViews(); var app = builder.Build(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run(); // ------- Controller ------- // [GoogleScopedAuthorize] triggers an incremental consent challenge if // the user hasn't yet granted the required scope. [GoogleScopedAuthorize(DriveService.ScopeConstants.DriveReadonly)] public async Task ListDriveFiles( [FromServices] IGoogleAuthProvider authProvider) { GoogleCredential credential = await authProvider.GetCredentialAsync(); var driveService = new DriveService(new BaseClientService.Initializer { HttpClientInitializer = credential }); var files = await driveService.Files.List().ExecuteAsync(); return View(files.Files); } ``` ``` -------------------------------- ### ASP.NET Core Integration with `AddGoogleOpenIdConnect` Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Integrates Google Sign-In into an ASP.NET Core application using OpenID Connect. The `[GoogleScopedAuthorize]` attribute enables incremental scope authorization for accessing Google APIs. ```csharp // Program.cs / Startup.cs using Google.Apis.Auth.AspNetCore3; using Google.Apis.Drive.v3; var builder = WebApplication.CreateBuilder(args); builder.Services .AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = GoogleOpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie() .AddGoogleOpenIdConnect(options => { options.ClientId = builder.Configuration["Authentication:Google:ClientId"]; options.ClientSecret = builder.Configuration["Authentication:Google:ClientSecret"]; }); builder.Services.AddControllersWithViews(); var app = builder.Build(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run(); // ------- Controller ------- ``` ```csharp // [GoogleScopedAuthorize] triggers an incremental consent challenge if // the user hasn't yet granted the required scope. [GoogleScopedAuthorize(DriveService.ScopeConstants.DriveReadonly)] public async Task ListDriveFiles( [FromServices] IGoogleAuthProvider authProvider) { GoogleCredential credential = await authProvider.GetCredentialAsync(); var driveService = new DriveService(new BaseClientService.Initializer { HttpClientInitializer = credential }); var files = await driveService.Files.List().ExecuteAsync(); return View(files.Files); } ``` -------------------------------- ### Authorize Google API Access with User Consent Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Performs the three-legged OAuth2 flow for desktop applications. Opens a browser for user consent and stores the resulting UserCredential for reuse. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.Calendar.v3; using Google.Apis.Services; using Google.Apis.Util.Store.DataStore; // Load OAuth2 client secrets (downloaded from Google Cloud Console) ClientSecrets secrets; using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read)) { secrets = await GoogleClientSecrets.FromStreamAsync(stream); } // Authorize; token is cached in %APPDATA%/Google.Apis.Auth/ UserCredential credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( secrets.Secrets, new[] { CalendarService.ScopeConstants.CalendarReadonly }, user: "user", CancellationToken.None, new FileDataStore("CalendarTokenStore")); var calendarService = new CalendarService(new BaseClientService.Initializer { HttpClientInitializer = credential, ApplicationName = "CalendarApp" }); // List upcoming calendar events var eventsRequest = calendarService.Events.List("primary"); eventsRequest.TimeMinDateTimeOffset = DateTimeOffset.UtcNow; eventsRequest.SingleEvents = true; eventsRequest.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime; var events = await eventsRequest.ExecuteAsync(); foreach (var ev in events.Items ?? new List()) { Console.WriteLine($"{ev.Summary} — {ev.Start?.DateTime ?? ev.Start?.Date}"); } ``` -------------------------------- ### Load Service Account Credentials with CredentialFactory Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Load service account credentials from a JSON key file using CredentialFactory and use them to interact with the Google Sheets API. Ensure the path to the service account JSON file is correct. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.Sheets.v4; using Google.Apis.Services; // Load from a service account JSON key file var serviceAccountCred = CredentialFactory.FromFile( "/path/to/service-account.json"); GoogleCredential credential = serviceAccountCred .ToGoogleCredential() .CreateScoped(SheetsService.ScopeConstants.Spreadsheets); var sheetsService = new SheetsService(new BaseClientService.Initializer { HttpClientInitializer = credential, ApplicationName = "SheetsDemo" }); // Read values from a spreadsheet string spreadsheetId = "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms"; string range = "Sheet1!A1:D5"; var response = await sheetsService.Spreadsheets.Values .Get(spreadsheetId, range) .ExecuteAsync(); foreach (var row in response.Values ?? new List>()) { Console.WriteLine(string.Join(", ", row)); } ``` -------------------------------- ### GoogleWebAuthorizationBroker.AuthorizeAsync Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Performs the three-legged OAuth2 flow for desktop applications, opening a browser for user consent and storing the resulting UserCredential for reuse. ```APIDOC ## `GoogleWebAuthorizationBroker.AuthorizeAsync` — Interactive OAuth2 User Authorization Performs the three-legged OAuth2 flow for desktop applications: opens a browser for user consent, captures the authorization code via a local redirect, and stores the resulting `UserCredential` (including the refresh token) in a `FileDataStore` for reuse on subsequent runs. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.Calendar.v3; using Google.Apis.Services; using Google.Apis.Util.Store; // Load OAuth2 client secrets (downloaded from Google Cloud Console) ClientSecrets secrets; using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read)) { secrets = await GoogleClientSecrets.FromStreamAsync(stream); } // Authorize; token is cached in %APPDATA%/Google.Apis.Auth/ UserCredential credential = await GoogleWebAuthorizationBroker.AuthorizeAsync( secrets.Secrets, new[] { CalendarService.ScopeConstants.CalendarReadonly }, user: "user", CancellationToken.None, new FileDataStore("CalendarTokenStore")); var calendarService = new CalendarService(new BaseClientService.Initializer { HttpClientInitializer = credential, ApplicationName = "CalendarApp" }); // List upcoming calendar events var eventsRequest = calendarService.Events.List("primary"); eventsRequest.TimeMinDateTimeOffset = DateTimeOffset.UtcNow; eventsRequest.SingleEvents = true; eventsRequest.OrderBy = EventsResource.ListRequest.OrderByEnum.StartTime; var events = await eventsRequest.ExecuteAsync(); foreach (var ev in events.Items ?? new List()) { Console.WriteLine($"{ev.Summary} — {ev.Start?.DateTime ?? ev.Start?.Date}"); } ``` ``` -------------------------------- ### Upload Files in Chunks with Resumable Upload Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Uploads a file using Google's resumable upload protocol, automatically splitting it into chunks, tracking progress, and resuming from the last acknowledged byte on transient failure. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Drive.v3.Data; using Google.Apis.Services; using Google.Apis.Upload; GoogleCredential credential = (await GoogleCredential.GetApplicationDefaultAsync()) .CreateScoped(DriveService.ScopeConstants.DriveFile); var driveService = new DriveService(new BaseClientService.Initializer { HttpClientInitializer = credential, ApplicationName = "UploadDemo" }); var fileMetadata = new Google.Apis.Drive.v3.Data.File { Name = "large-report.csv", MimeType = "text/csv" }; using var fileStream = new FileStream("/local/large-report.csv", FileMode.Open); var uploadRequest = driveService.Files.Create(fileMetadata, fileStream, "text/csv"); uploadRequest.Fields = "id, name, size"; // Subscribe to progress events uploadRequest.ProgressChanged += progress => { Console.WriteLine($"Status: {progress.Status}, Bytes sent: {progress.BytesSent}"); }; uploadRequest.ResponseReceived += file => { Console.WriteLine($"Uploaded: {file.Name} (ID: {file.Id}, Size: {file.Size} bytes)"); }; // Optionally tune chunk size (must be a multiple of 256 KB) uploadRequest.ChunkSize = ResumableUpload.MinimumChunkSize * 4; // 1 MB var uploadResult = await uploadRequest.UploadAsync(); if (uploadResult.Status == UploadStatus.Failed) { Console.WriteLine($"Upload failed: {uploadResult.Exception.Message}"); } ``` -------------------------------- ### Use Application Default Credentials (ADC) with Drive API Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Retrieve ambient credentials using ADC and use them to interact with the Google Drive API. Ensure the GOOGLE_APPLICATION_CREDENTIALS environment variable is set or that you are logged in via gcloud. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Services; // ADC resolves credentials automatically from environment GoogleCredential credential = await GoogleCredential.GetApplicationDefaultAsync(); // Add required OAuth scopes credential = credential.CreateScoped(DriveService.ScopeConstants.DriveReadonly); var driveService = new DriveService(new BaseClientService.Initializer { HttpClientInitializer = credential, ApplicationName = "MyApp/1.0" }); // List files in Google Drive var listRequest = driveService.Files.List(); listRequest.PageSize = 10; listRequest.Fields = "nextPageToken, files(id, name, mimeType)"; var result = await listRequest.ExecuteAsync(); foreach (var file in result.Files ?? Enumerable.Empty()) { Console.WriteLine($"{file.Name} ({file.Id})"); } ``` -------------------------------- ### Per-Request Credential and Retry Handlers with `ClientServiceRequest` Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Customizes individual API requests by overriding credentials, adding retry logic, or attaching HTTP interceptors. This allows for fine-grained control over request behavior without modifying the service instance. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Http; using Google.Apis.Requests; using Google.Apis.Services; var driveService = new DriveService(new BaseClientService.Initializer { HttpClientInitializer = await GoogleCredential.GetApplicationDefaultAsync(), ApplicationName = "PerRequestDemo" }); var listRequest = driveService.Files.List(); listRequest.PageSize = 5; listRequest.Fields = "files(id, name)"; // Override the credential for this request only (e.g., act as a specific user) GoogleCredential perRequestCredential = (await GoogleCredential.GetApplicationDefaultAsync()) .CreateScoped(DriveService.ScopeConstants.Drive) .CreateWithUser("delegated-user@example.com"); // domain-wide delegation listRequest.Credential = perRequestCredential; // Attach a per-request unsuccessful response handler listRequest.AddUnsuccessfulResponseHandler(new BackOffHandler(new ExponentialBackOff())); // Attach a per-request exception handler listRequest.AddExceptionHandler(new BackOffHandler(new ExponentialBackOff())); try { var result = await listRequest.ExecuteAsync(CancellationToken.None); foreach (var f in result.Files) Console.WriteLine($"{f.Name} ({f.Id})"); } catch (Google.GoogleApiException ex) { Console.WriteLine($"API Error {ex.HttpStatusCode}: {ex.Error?.Message}"); } ``` -------------------------------- ### Batch Multiple API Calls with BatchRequest Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Combine up to 1,000 API requests into a single HTTP call using BatchRequest to reduce network round-trips and quota usage. Each queued request can have its own typed callback for handling responses or errors. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.Gmail.v1; using Google.Apis.Gmail.v1.Data; using Google.Apis.Requests; using Google.Apis.Services; GoogleCredential credential = (await GoogleCredential.GetApplicationDefaultAsync()) .CreateScoped(GmailService.ScopeConstants.GmailReadonly); var gmailService = new GmailService(new BaseClientService.Initializer { HttpClientInitializer = credential, ApplicationName = "BatchDemo" }); var batchRequest = new BatchRequest(gmailService); // Queue individual requests with per-response callbacks string userId = "me"; var messageIds = new[] { "msg1abc", "msg2def", "msg3ghi" }; foreach (var id in messageIds) { batchRequest.Queue( gmailService.Users.Messages.Get(userId, id), (message, error, index, response) => { if (error != null) Console.WriteLine($"[{index}] Error: {error.Message}"); else Console.WriteLine($"[{index}] Subject: {message.Snippet}"); }); } // Execute all queued requests in one HTTP call await batchRequest.ExecuteAsync(); ``` -------------------------------- ### ResumableUpload Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Uploads a file using Google's resumable upload protocol, automatically splitting it into chunks and resuming from the last acknowledged byte on transient failure. ```APIDOC ## `ResumableUpload` — Chunked / Resumable Media Upload Uploads a file using Google's resumable upload protocol, automatically splitting it into chunks (default 10 MB), tracking progress events, and resuming from the last acknowledged byte on transient failure. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Drive.v3.Data; using Google.Apis.Services; using Google.Apis.Upload; GoogleCredential credential = (await GoogleCredential.GetApplicationDefaultAsync()) .CreateScoped(DriveService.ScopeConstants.DriveFile); var driveService = new DriveService(new BaseClientService.Initializer { HttpClientInitializer = credential, ApplicationName = "UploadDemo" }); var fileMetadata = new Google.Apis.Drive.v3.Data.File { Name = "large-report.csv", MimeType = "text/csv" }; using var fileStream = new FileStream("/local/large-report.csv", FileMode.Open); var uploadRequest = driveService.Files.Create(fileMetadata, fileStream, "text/csv"); uploadRequest.Fields = "id, name, size"; // Subscribe to progress events uploadRequest.ProgressChanged += progress => { Console.WriteLine($"Status: {progress.Status}, Bytes sent: {progress.BytesSent}"); }; uploadRequest.ResponseReceived += file => { Console.WriteLine($"Uploaded: {file.Name} (ID: {file.Id}, Size: {file.Size} bytes)"); }; // Optionally tune chunk size (must be a multiple of 256 KB) uploadRequest.ChunkSize = ResumableUpload.MinimumChunkSize * 4; // 1 MB var uploadResult = await uploadRequest.UploadAsync(); if (uploadResult.Status == UploadStatus.Failed) { Console.WriteLine($"Upload failed: {uploadResult.Exception.Message}"); } ``` ``` -------------------------------- ### Iterate Through API List Responses with PageStreamer Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Use the generic PageStreamer to automatically paginate through all pages of a Google API list response, yielding individual items. This helper works across any Google API that uses page tokens for pagination. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.YouTube.v3; using Google.Apis.YouTube.v3.Data; using Google.Apis.Requests; using Google.Apis.Services; GoogleCredential credential = (await GoogleCredential.GetApplicationDefaultAsync()) .CreateScoped(YouTubeService.ScopeConstants.YoutubeReadonly); var youtubeService = new YouTubeService(new BaseClientService.Initializer { HttpClientInitializer = credential, ApplicationName = "PaginationDemo" }); // Declare the page streamer once (reusable across requests) var pageStreamer = new PageStreamer( (request, token) => request.PageToken = token, response => response.NextPageToken, response => response.Items); var searchRequest = youtubeService.Search.List("snippet"); searchRequest.Q = "Google .NET"; searchRequest.MaxResults = 50; searchRequest.Type = "video"; int count = 0; // FetchAllAsync automatically follows all pages await foreach (var result in pageStreamer.FetchAllAsync(searchRequest, CancellationToken.None)) { Console.WriteLine($"{++count}: {result.Snippet.Title}"); } Console.WriteLine($"Total results fetched: {count}"); ``` -------------------------------- ### Impersonate a Service Account for Delegated Access Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Enables a source credential to impersonate a different service account, generating short-lived tokens scoped to the impersonated identity. Requires the `roles/iam.serviceAccountTokenCreator` IAM role. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.Storage.v1; using Google.Apis.Services; // The source credential must have Token Creator rights on the target GoogleCredential sourceCredential = await GoogleCredential.GetApplicationDefaultAsync(); var impersonated = ImpersonatedCredential.Create( sourceCredential, new ImpersonatedCredential.Initializer("target-sa@project.iam.gserviceaccount.com") { Scopes = new[] { StorageService.ScopeConstants.CloudPlatformReadOnly }, Lifetime = TimeSpan.FromMinutes(30) }); var storageService = new StorageService(new BaseClientService.Initializer { HttpClientInitializer = impersonated, ApplicationName = "ImpersonationDemo" }); var buckets = await storageService.Buckets.List("my-gcp-project").ExecuteAsync(); foreach (var bucket in buckets.Items ?? new List()) { Console.WriteLine(bucket.Name); } ``` -------------------------------- ### ClientServiceRequest — Per-Request Credential and Retry Handlers Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Allows overriding default service credentials, attaching custom retry logic, or adding HTTP interceptors for individual API requests without affecting the service instance. ```APIDOC ## `ClientServiceRequest` — Per-Request Credential and Retry Handlers Every API request object inherits from `ClientServiceRequest`, letting you override the default service-level credential, attach custom retry logic, or add HTTP interceptors for a single call without affecting the service instance. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Http; using Google.Apis.Requests; using Google.Apis.Services; var driveService = new DriveService(new BaseClientService.Initializer { HttpClientInitializer = await GoogleCredential.GetApplicationDefaultAsync(), ApplicationName = "PerRequestDemo" }); var listRequest = driveService.Files.List(); listRequest.PageSize = 5; listRequest.Fields = "files(id, name)"; // Override the credential for this request only (e.g., act as a specific user) GoogleCredential perRequestCredential = (await GoogleCredential.GetApplicationDefaultAsync()) .CreateScoped(DriveService.ScopeConstants.Drive) .CreateWithUser("delegated-user@example.com"); // domain-wide delegation listRequest.Credential = perRequestCredential; // Attach a per-request unsuccessful response handler listRequest.AddUnsuccessfulResponseHandler(new BackOffHandler(new ExponentialBackOff())); // Attach a per-request exception handler listRequest.AddExceptionHandler(new BackOffHandler(new ExponentialBackOff())); try { var result = await listRequest.ExecuteAsync(CancellationToken.None); foreach (var f in result.Files) Console.WriteLine($"{f.Name} ({f.Id})"); } catch (Google.GoogleApiException ex) { Console.WriteLine($"API Error {ex.HttpStatusCode}: {ex.Error?.Message}"); } ``` ``` -------------------------------- ### Validate Google ID Tokens with `GoogleJsonWebSignature.ValidateAsync` Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Validates a Google-signed JWT (ID token) to verify user identity. Ensure the audience matches your application's client ID and consider setting an expiration time clock tolerance for minor clock skews. ```csharp using Google.Apis.Auth; // id_token received from a client-side Google Sign-In flow string idToken = "eyJhbGciOiJSUzI1NiIsImtpZCI6..."; try { var validationSettings = new GoogleJsonWebSignature.ValidationSettings { // Restrict to your application's OAuth2 client ID Audience = new[] { "123456789-abc.apps.googleusercontent.com" }, // ExpirationTimeClockTolerance allows a small clock skew (default 0) ExpirationTimeClockTolerance = TimeSpan.FromMinutes(1) }; GoogleJsonWebSignature.Payload payload = await GoogleJsonWebSignature.ValidateAsync(idToken, validationSettings); Console.WriteLine($"User: {payload.Name}"); Console.WriteLine($"Email: {payload.Email}"); Console.WriteLine($"Email verified: {payload.EmailVerified}"); Console.WriteLine($"Subject (user ID): {payload.Subject}"); Console.WriteLine($"Issuer: {payload.Issuer}"); Console.WriteLine($"Expires: {DateTimeOffset.FromUnixTimeSeconds(payload.ExpirationTimeSeconds ?? 0)}"); } catch (InvalidJwtException ex) { Console.WriteLine($"Invalid token: {ex.Message}"); } ``` -------------------------------- ### ImpersonatedCredential Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Enables a source credential to impersonate a different service account, generating short-lived tokens scoped to the impersonated identity. ```APIDOC ## `ImpersonatedCredential` — Service Account Impersonation Enables a source credential (service account or user) to impersonate a different service account, generating short-lived tokens scoped to the impersonated identity. Requires the `roles/iam.serviceAccountTokenCreator` IAM role. ```csharp using Google.Apis.Auth.OAuth2; using Google.Apis.Storage.v1; using Google.Apis.Services; // The source credential must have Token Creator rights on the target GoogleCredential sourceCredential = await GoogleCredential.GetApplicationDefaultAsync(); var impersonated = ImpersonatedCredential.Create( sourceCredential, new ImpersonatedCredential.Initializer("target-sa@project.iam.gserviceaccount.com") { Scopes = new[] { StorageService.ScopeConstants.CloudPlatformReadOnly }, Lifetime = TimeSpan.FromMinutes(30) }); var storageService = new StorageService(new BaseClientService.Initializer { HttpClientInitializer = impersonated, ApplicationName = "ImpersonationDemo" }); var buckets = await storageService.Buckets.List("my-gcp-project").ExecuteAsync(); foreach (var bucket in buckets.Items ?? new List()) { Console.WriteLine(bucket.Name); } ``` ``` -------------------------------- ### GoogleJsonWebSignature.ValidateAsync Source: https://context7.com/googleapis/google-api-dotnet-client/llms.txt Validates a Google-signed JWT (ID token) to verify user identity and retrieve profile information. It checks the signature, audience, and expiry of the token. ```APIDOC ## `GoogleJsonWebSignature.ValidateAsync` — Verify Google ID Tokens Validates a Google-signed JWT (ID token), typically obtained after a user signs in with Google. Returns the payload with the user's profile information if the signature, audience, and expiry are all valid. ```csharp using Google.Apis.Auth; // id_token received from a client-side Google Sign-In flow string idToken = "eyJhbGciOiJSUzI1NiIsImtpZCI6..."; try { var validationSettings = new GoogleJsonWebSignature.ValidationSettings { // Restrict to your application's OAuth2 client ID Audience = new[] { "123456789-abc.apps.googleusercontent.com" }, // ExpirationTimeClockTolerance allows a small clock skew (default 0) ExpirationTimeClockTolerance = TimeSpan.FromMinutes(1) }; GoogleJsonWebSignature.Payload payload = await GoogleJsonWebSignature.ValidateAsync(idToken, validationSettings); Console.WriteLine($"User: {payload.Name}"); Console.WriteLine($"Email: {payload.Email}"); Console.WriteLine($"Email verified: {payload.EmailVerified}"); Console.WriteLine($"Subject (user ID): {payload.Subject}"); Console.WriteLine($"Issuer: {payload.Issuer}"); Console.WriteLine($"Expires: {DateTimeOffset.FromUnixTimeSeconds(payload.ExpirationTimeSeconds ?? 0)}"); } catch (InvalidJwtException ex) { Console.WriteLine($"Invalid token: {ex.Message}"); } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.