Private/Get-ECMA2GraphToken.ps1
|
function Get-ECMA2GraphToken { <# .SYNOPSIS Returns a valid Microsoft Graph access token for the current ECMA2 Graph connection. .DESCRIPTION Internal function. Returns the cached access token established by Connect-ECMA2Graph, transparently refreshing it first if it is at or near expiry. .EXAMPLE Get-ECMA2GraphToken #> [CmdletBinding()] param() if (-not $script:ECMA2GraphContext) { throw "Not connected to Microsoft Graph. Run Connect-ECMA2Graph first." } $context = $script:ECMA2GraphContext if ((Get-Date) -lt $context.ExpiresOn.AddMinutes(-1)) { return $context.AccessToken } Write-Verbose "Access token expired or expiring soon, refreshing ($($context.AuthMode))" $tokenEndpoint = "https://login.microsoftonline.com/$($context.TenantId)/oauth2/v2.0/token" try { switch ($context.AuthMode) { 'DeviceCode' { if (-not $context.RefreshToken) { throw "No refresh token available. Run Connect-ECMA2Graph again to re-authenticate." } $response = Invoke-RestMethod -Method Post -Uri $tokenEndpoint -Body @{ grant_type = 'refresh_token' client_id = $context.ClientId refresh_token = $context.RefreshToken scope = ($context.Scopes -join ' ') } -ContentType 'application/x-www-form-urlencoded' # Some refresh responses omit refresh_token (the identity platform may # reuse the existing one) - only overwrite it when a new value is # actually returned, otherwise the cached refresh token would be wiped # out and the next refresh would fail. if ($response.refresh_token) { $context.RefreshToken = $response.refresh_token } } 'ClientSecret' { $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($context.ClientSecret) $plainSecret = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr) [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) $response = Invoke-RestMethod -Method Post -Uri $tokenEndpoint -Body @{ grant_type = 'client_credentials' client_id = $context.ClientId client_secret = $plainSecret scope = 'https://graph.microsoft.com/.default' } -ContentType 'application/x-www-form-urlencoded' } 'Certificate' { $assertion = New-ECMA2GraphClientAssertion -ClientId $context.ClientId -TenantId $context.TenantId -Certificate $context.Certificate $response = Invoke-RestMethod -Method Post -Uri $tokenEndpoint -Body @{ grant_type = 'client_credentials' client_id = $context.ClientId client_assertion_type = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer' client_assertion = $assertion scope = 'https://graph.microsoft.com/.default' } -ContentType 'application/x-www-form-urlencoded' } 'AccessToken' { throw "The current connection uses a bring-your-own access token and cannot be refreshed automatically. Run Connect-ECMA2Graph -AccessToken with a fresh token." } default { throw "Unknown ECMA2 Graph authentication mode '$($context.AuthMode)'. Run Connect-ECMA2Graph again." } } $context.AccessToken = $response.access_token $context.ExpiresOn = (Get-Date).AddSeconds($response.expires_in) return $context.AccessToken } catch { throw "Failed to refresh Microsoft Graph access token: $_" } } |