Private/Refresh-JwtToken.ps1
|
<# .SYNOPSIS Refresh an expired JWT session token. .DESCRIPTION Exchanges the social-login session's refresh token for a fresh JWT access token via the Dune auth `/access-token` endpoint. On success the in-memory `$DuneSession` access token and expiry date are updated and the session is re-cached. Only `SocialLogin` sessions carry a refresh token. If the session is missing, is not a social login, or the refresh token is rejected/expired, the session is cleared and the user is asked to reauthenticate with Connect-Dune. .EXAMPLE PS> Refresh-JwtToken Refreshes the current social-login session's access token in place. #> function Refresh-JwtToken { [CmdletBinding()] param() if (-not $DuneSession) { throw "You are not authenticated. Please run Connect-Dune." } if ($DuneSession.Type -ne 'SocialLogin' -or -not $DuneSession.RefreshToken) { throw "Session expired and cannot be refreshed. Please run Connect-Dune to reauthenticate." } $RefreshToken = ConvertFrom-DuneSecureString -SecureString $DuneSession.RefreshToken $AuthUrl = "{0}{1}" -f $DuneSession.DuneApiUrl, "/access-token" $Headers = @{ "Accept" = "application/json" "Content-Type" = "application/json" "X-Tenant" = $DuneSession.Tenant } $WebRequest = @{ Uri = $AuthUrl Method = 'POST' Headers = $Headers Body = (@{ refreshToken = $RefreshToken } | ConvertTo-Json) UseBasicParsing = $true } if (([System.Uri]$DuneSession.DuneApiUrl).Host -eq 'localhost') { $WebRequest.SkipCertificateCheck = $true } Write-Debug "$($MyInvocation.MyCommand)|process|Refreshing access token ..." try { $Response = Invoke-WebRequest @WebRequest } catch { # Refresh token rejected/expired -> the session is no longer usable. if ($script:DuneSession) { Remove-Variable -Name DuneSession -Scope Script -Force } Remove-CachedDuneSession throw "Failed to refresh JWT token: $($_.Exception.Message). Please run Connect-Dune to reauthenticate." } # The auth service is configured with UseTokenCookie, so GetAccessToken returns an empty # body ({}) and delivers the new JWT in an 'ss-tok' Set-Cookie header. Fall back to the # response body for servers that return the token inline instead. $NewToken = $null try { $NewToken = ($Response.Content | ConvertFrom-Json).accessToken } catch { } if (-not $NewToken) { $SetCookie = $Response.Headers['Set-Cookie'] if ($SetCookie -is [array]) { $SetCookie = $SetCookie -join '; ' } if ($SetCookie -match 'ss-tok=([^;]+)') { $NewToken = $Matches[1] } } if (-not $NewToken) { throw "Token refresh did not return an access token." } $ParsedToken = Parse-JwtToken -Token $NewToken # Use local time: the expiry is compared against Get-Date (local) in Assert-DuneSession. $TokenExpiryDate = [System.DateTimeOffset]::FromUnixTimeSeconds($ParsedToken.exp).LocalDateTime $Script:DuneSession.Token = ($NewToken | ConvertTo-SecureString -AsPlainText -Force) $Script:DuneSession.ExpiryDate = $TokenExpiryDate Write-Verbose "JWT token refreshed successfully" Save-DuneSession } |