Public/Google/Get-GoogleApiAccessToken.ps1
|
function Get-GoogleApiAccessToken { <# .SYNOPSIS Retrieves an access token from Google API using a service account. .DESCRIPTION This function generates a JWT (JSON Web Token) and exchanges it for an access token from Google API. The access token can then be used for authenticated requests to Google services. The token is issued to the service account ITSELF (no user impersonation / domain-wide delegation). Authorization for Admin SDK calls comes from the Google Workspace admin role assigned to the service account (created by Initialize-IDBridgeGoogleServiceAccount); Sheets access comes from sharing the sheet with the service account's email. .PARAMETER ServiceAccountKeyPath PAth to a JSON file containing the service account credentials, including the private key and client email. This is the Google credential file downloaded from the Google Cloud Console. .PARAMETER ServiceAccountKeyJson The service account credential JSON as a string instead of a file path — e.g. read from the IDBridge secret vault (Get-IDBridgeSecret -Name 'GoogleAuth-ServiceAccount' -AsPlainText). .PARAMETER Scope The scope of access requested from Google API (e.g., 'https://www.googleapis.com/auth/drive'). .EXAMPLE $credentialsJson = Get-Content 'C:\path\to\credentials.json' -Raw $accessToken = Get-GoogleApiAccessToken -ServiceAccountKeyPath $credentialsJson -Scope 'https://www.googleapis.com/auth/drive.readonly' Use the $accessToken for authenticated API requests. .NOTES Ensure that the service account has the necessary permissions for the requested scope. Created by: Sam Cattanach Modified: 02/18/2025 09:30:19 AM #> [CmdletBinding(DefaultParameterSetName = 'Path')] param ( [Parameter(Mandatory, ParameterSetName = 'Path')] [string]$ServiceAccountKeyPath, [Parameter(Mandatory, ParameterSetName = 'Json')] [string]$ServiceAccountKeyJson, [Parameter(Mandatory)] [string]$Scope ) # Convert JSON credentials into a PowerShell object if ($PSCmdlet.ParameterSetName -eq 'Path') { $ServiceAccountKeyJson = Get-Content $ServiceAccountKeyPath -Raw } $jsonContent = ConvertFrom-Json -InputObject $ServiceAccountKeyJson $ServiceAccountEmail = $jsonContent.client_email $PrivateKey = $jsonContent.private_key -replace '-----BEGIN PRIVATE KEY-----\n' -replace '\n-----END PRIVATE KEY-----\n' -replace '\n' # Create JWT Header (Base64-encoded JSON) $header = @{ alg = "RS256" typ = "JWT" } $headerBase64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(($header | ConvertTo-Json -Compress))) # Generate JWT Payload (Claim Set) $timestamp = [Math]::Round((Get-Date -UFormat %s)) # Current time in seconds $claimSet = @{ iss = $ServiceAccountEmail scope = $Scope aud = "https://oauth2.googleapis.com/token" exp = $timestamp + 3600 # Token expiration (1 hour) iat = $timestamp # Issued at time } $claimSetBase64 = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes(($claimSet | ConvertTo-Json -Compress))) # Generate JWT Signature $signatureInput = "$headerBase64.$claimSetBase64" $signatureBytes = [System.Text.Encoding]::UTF8.GetBytes($signatureInput) $privateKeyBytes = [System.Convert]::FromBase64String($PrivateKey) # Create RSA provider and import the private key $rsaProvider = [System.Security.Cryptography.RSA]::Create() $bytesRead = $null $rsaProvider.ImportPkcs8PrivateKey($privateKeyBytes, [ref]$bytesRead) # Sign the JWT using SHA-256 and PKCS1 padding $signature = $rsaProvider.SignData($signatureBytes, [System.Security.Cryptography.HashAlgorithmName]::SHA256, [System.Security.Cryptography.RSASignaturePadding]::Pkcs1) $signatureBase64 = [System.Convert]::ToBase64String($signature) # Construct the final JWT $jwt = "$headerBase64.$claimSetBase64.$signatureBase64" # Create request body for token exchange $body = @{ grant_type = "urn:ietf:params:oauth:grant-type:jwt-bearer" assertion = $jwt } # Request access token from Google OAuth2 API try { $response = Invoke-RestMethod -Uri "https://oauth2.googleapis.com/token" -Method POST -Body $body -ContentType "application/x-www-form-urlencoded" $accessToken = $response.access_token $headers = @{ 'Authorization' = "Bearer $accessToken" 'Accept' = 'application/json' } Write-Log -Message "Successfully retrieved Google Access Token" -Level Trace return $headers } catch { Write-Log -Message "Failed to Retrieve Google Access Token" -Level Error Throw $_ } } |