functions/core/Update-MgaAccessToken.ps1

function Update-MgaAccessToken {
    <#
    .SYNOPSIS
        Updates an existing access token
 
    .DESCRIPTION
        Updates an existing access token for contacting the specified application endpoint as long
        as the token is still valid. Otherwise, a new access is called through New-MgaAccessToken.
 
    .PARAMETER Token
        The token object to renew.
 
    .PARAMETER Register
        Registers the renewed token, so all subsequent calls to Exchange Online reuse it by default.
 
    .PARAMETER PassThru
        Outputs the token to the console, even when the register switch is set
 
    .EXAMPLE
        PS C:\> New-MgaAccessToken -MailboxName 'max.musterman@contoso.com'
 
        Registers an application to run under 'max.mustermann@contoso.com'.
        Requires an interactive session with a user handling the web UI.
 
    .EXAMPLE
        PS C:\> New-MgaAccessToken -MailboxName 'max.musterman@contoso.com' -Credential $cred
 
        Generates a token to a session as max.mustermann@contoso.com under the credentials specified in $cred.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "")]
    [CmdletBinding(DefaultParameterSetName="Default")]
    param (
        [MSGraph.Core.AzureAccessToken]
        $Token,

        [Parameter(ParameterSetName='Register')]
        [switch]
        $Register,

        [Parameter(ParameterSetName='Register')]
        [switch]
        $PassThru
    )

    if (-not $Token) {
        $Token = $script:msgraph_Token
        $Register = $true
    }
    if (-not $Token) { Stop-PSFFunction -Message "Not connected! Use New-MgaAccessToken to create a Token and either register it or specifs it." -EnableException $true -Category AuthenticationError -Cmdlet $PSCmdlet }

    if (-not $Token.IsValid) {
        Write-PSFMessage -Level Warning -Message "Token lifetime already expired and can't be newed. New authentication is required. Calling New-MgaAccessToken..." -Tag "Authorization"
        $paramsNewToken = @{
            ClientId = $Token.AccessTokenInfo.ApplicationID.Guid
            RedirectUrl = $Token.AppRedirectUrl
        }
        if ($Token.Credential) { $paramsNewToken.Add("Credential", $Token.Credential ) }
        if ($Register -or ($script:msgraph_Token.AccessTokenInfo.Payload -eq $Token.AccessTokenInfo.Payload) ) { $paramsNewToken.Add("Register", $true) }
        $resultObject = New-MgaAccessToken -PassThru @paramsNewToken
        if ($PassThru) { return $resultObject } else { return }
    }

    $resourceUri = "https://graph.microsoft.com"
    $endpointUri = "https://login.windows.net/common/oauth2"
    $endpointUriToken = "$($endpointUri)/token "

    $baselineTimestamp = [datetime]"1970-01-01Z00:00:00"
    $httpClient = New-HttpClient

    $queryHash = [ordered]@{
        grant_type    = "refresh_token"
        resource      = [System.Web.HttpUtility]::UrlEncode($resourceUri)
        client_id     = $Token.ClientId
        refresh_token = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Token.RefreshToken))
    }
    $authorizationPostRequest = Convert-UriQueryFromHash $queryHash -NoQuestionmark


    $content = New-Object System.Net.Http.StringContent($authorizationPostRequest, [System.Text.Encoding]::UTF8, "application/x-www-form-urlencoded")
    $clientResult = $httpClient.PostAsync([Uri]$endpointUriToken, $content)
    if ($clientResult.Result.StatusCode -eq [System.Net.HttpStatusCode]"OK") {
        Write-PSFMessage -Level Verbose -Message "AccessToken renewal successful. $($clientResult.Result.StatusCode.value__) ($($clientResult.Result.StatusCode)) $($clientResult.Result.ReasonPhrase)" -Tag "Authorization"
    }
    else {
        Stop-PSFFunction -Message "Failed to renew AccessToken! $($clientResult.Result.StatusCode.value__) ($($clientResult.Result.StatusCode)) $($clientResult.Result.ReasonPhrase)" -Tag "Authorization" -EnableException $true
    }
    $jsonResponse = ConvertFrom-Json -InputObject $clientResult.Result.Content.ReadAsStringAsync().Result

    # Build output object
    $resultObject = New-Object MSGraph.Core.AzureAccessToken -Property @{
        TokenType      = $jsonResponse.token_type
        Scope          = $jsonResponse.scope -split " "
        ValidUntilUtc  = $baselineTimestamp.AddSeconds($jsonResponse.expires_on).ToUniversalTime()
        ValidFromUtc   = $baselineTimestamp.AddSeconds($jsonResponse.not_before).ToUniversalTime()
        ValidUntil     = New-Object DateTime($baselineTimestamp.AddSeconds($jsonResponse.expires_on).Ticks)
        ValidFrom      = New-Object DateTime($baselineTimestamp.AddSeconds($jsonResponse.not_before).Ticks)
        AccessToken    = $null
        RefreshToken   = $null
        IDToken        = $null
        Credential     = $Credential
        ClientId       = $ClientId
        Resource       = $resourceUri
        AppRedirectUrl = $Token.AppRedirectUrl
    }
    # Insert token data into output object. done as secure string to prevent text output of tokens
    if ($jsonResponse.psobject.Properties.name -contains "refresh_token") { $resultObject.RefreshToken = ($jsonResponse.refresh_token | ConvertTo-SecureString -AsPlainText -Force) }
    if ($jsonResponse.psobject.Properties.name -contains "id_token") { $resultObject.IDToken = ($jsonResponse.id_token | ConvertTo-SecureString -AsPlainText -Force) }
    if ($jsonResponse.psobject.Properties.name -contains "access_token") {
        $resultObject.AccessToken = ($jsonResponse.access_token | ConvertTo-SecureString -AsPlainText -Force)
        $resultObject.AccessTokenInfo = ConvertFrom-JWTtoken -Token $jsonResponse.access_token
    }
    if ((Get-Date).IsDaylightSavingTime()) {
        $resultObject.ValidUntil = $resultObject.ValidUntil.AddHours(1)
        $resultObject.ValidFrom = $resultObject.ValidFrom.AddHours(1)
    }

    if ($resultObject.IsValid) {
        if ($Register) {
            $script:msgraph_Token = $resultObject
            if ($PassThru) { $resultObject }
        }
        else {
            $resultObject
        }
    }
    else {
        Stop-PSFFunction -Message "Token failure. Acquired token is not valid" -EnableException -Tag "Authorization"
    }
}