In the process of updating my library of standard scripts and functions, I’ve taken the opportunity to change a lot of them to use Graph API rather than legacy EWS or PowerShell Modules. Using Graph helps to make them much more efficient and flexible and a lot of the functionality that I need is there anyway.
One challenge I came across with Graph was when running with delegated permissions and avoiding authenticating constantly for unattended scripts. When running as an app we can pipe in our App Registration details and away we go but when you bring delegated permissions and MFA into the loop, that becomes a challenge.
I’ve put together the below function (located here on GitHub) to allow me to use a refresh token and renew my access token to keep access alive. When using access tokens, they will by default last for an hour, needing to be renewed after that. Refresh tokens (which last 14 days) can then be used to renew this access token and get a new refresh token in the process.
The function itself takes in the following values:
-Token: The existing refresh token
-tenantID: The ID of your tenant (tenant.onmicrosoft.com)
-ClientID: Client ID of your App Reg
-Secret: The secret of your app reg
-Scope: A comma delimited list of your access scope
It will then pass back a new token object complete with renewed access and refresh tokens. I generally store these tokens in Azure Key Vault and update them at refresh time. This means my apps can refresh tokens when they need to and save them securely, only accessing at run time.
function RefreshAccessToken{
<#
.SYNOPSIS
Refreshes an access token based on refresh token
.RETURNS
Returns a refreshed access token
.PARAMETER Token
-Token is the existing refresh token
.PARAMETER tenantID
-This is the tenant ID eg. domain.onmicrosoft.com
.PARAMETER ClientID
-This is the app reg client ID
.PARAMETER Secret
-This is the client secret
.PARAMETER Scope
-A comma delimited list of access scope, default is: "Group.ReadWrite.All,User.ReadWrite.All"
#>
Param(
[parameter(Mandatory = $true)]
[String]
$Token,
[parameter(Mandatory = $true)]
[String]
$tenantID,
[parameter(Mandatory = $true)]
[String]
$ClientID,
[parameter(Mandatory = $false)]
[String]
$Scope = "Group.ReadWrite.All,User.ReadWrite.All",
[parameter(Mandatory = $true)]
[String]
$Secret
)
$ScopeFixup = $Scope.replace(',','%20')
$apiUri = "https://login.microsoftonline.com/$tenantID/oauth2/v2.0/token"
$body = "client_id=$ClientID&scope=$ScopeFixup&refresh_token=$Token&redirect_uri=http%3A%2F%2Flocalhost%2F&grant_type=refresh_token&client_secret=$Secret"
write-verbose $body -Verbose
$Refreshedtoken = (Invoke-RestMethod -Uri $apiUri -Method Post -ContentType 'application/x-www-form-urlencoded' -body $body )
return $Refreshedtoken
}