Skip to main content

Create application access token & authorization header

ToThis authenticationarticle againstexplains thehow to authenticate to Microsoft Graph APIusing thereapplication permissions. Use this method for unattended automation where no signed-in user is involved.

When to use application authentication

Use app-only authentication when:

    the script runs unattended the process runs in Azure Automation, Functions, pipelines, or services no user interaction is possible the automation should act as the application itself

    Preferred options in enterprise environments:

      Managed Identity for Azure-hosted workloads Certificate-based authentication Client secret only when the first two are twonot generalpossible concepts. Application
      permissions

      Note allowThe anOAuth application2.0 inclient credentials flow does not return a refresh token. To get a new token, request a new access token again.

      Prerequisites

        Microsoft Entra ID toapp actregistration as it's own entity, rather than on behalf of a specific user. Delegated permissions allow an application in Microsoft Entra ID to perform actions on behalf of a particular user.

        This guide focuses on authentication as an application to create unattended automations. To create or renew a token in the user context there are other instructions.

        Use case

        This authentication is required if you want to retrieve, update, or create resources using the Microsoft APIs (Azure Management API,

        Microsoft Graph API). This is for application-basedapplication permissions suchadmin asconsent regulargranted tenant ID client ID client credential (certificate or triggeredsecret) automations.

        Graph

        Example: APIclient authentication

        secret

        To authenticate with application permission you have to use an Microsoft Entra ID App Registration. There you can specify an Client Secret as it is described here: Get app details and gr... | LNC Docs (lucanoahcaprez.ch)

        The authentication method used for Microsoft Graph API is the industry-standard OAuth 2.0. This concept uses access tokens for authenticating against API endpoints. These access tokens are then sent to the resource server in the HTTP header. Therefore we have to create the header correctly to use the resources of the Microsoft Graph API.

        image.png

        Build header via PowerShell script

        The following scripts creates the header that contains the header property and the corresponding Bearer token. This function needs the arguments Tenant ID, Client (Application) ID and the Client Secret. This function has to be called the first time with these three parameters. Then you can use the refresh token of the first authentication request to consist the session.

        Attention: This function returns a complete header. If you want to specify more information in the request header you have to use the function lower on this page. 

        flow
        # Function for getting Microsoft Entra ID Access Header
        Function Build-MicrosoftEntraIDApplicationAccessHeader(){
            param(
                [Parameter(Mandatory=$true)]
                [string] $tenantid,
                [string] $clientid,
                [string] $clientSecret,
                [string] $refreshtoken
            )
        
            $authenticationurlTenantId     = "https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token"
        
            if($refreshtoken -and<tenant-id>"
        $tenantId){
                $tokenBodySource = @{
                    grant_typeClientId     = "refresh_token"<app-client-id>"
        scope$ClientSecret = "https://graph.microsoft.com/.default"
                    refresh_token  =<client-secret>"
        
        $refreshtoken
                }
            }
            elseif($tenantId -and $clientid -and $clientSecret){
                $tokenBodySourceTokenBody = @{
            grant_type    = "client_credentials"
            scope         = "https://graph.microsoft.com/.default"
            client_id     = $clientidClientId
            client_secret = "$clientSecret"ClientSecret
        }
        
        }
            else{
                Write-Error "Authorization not successful. Not enough information provided."
            }
        
            while ([string]::IsNullOrEmpty($AuthResponse.access_token)) {
                $AuthResponseTokenResponse = try {
                    Invoke-RestMethod `
            -Method POST `
            -Uri $authenticationurl -Body $tokenBodySource
                }
                catch {
                    $ErrorAuthResponse = $_.ErrorDetails.Message | ConvertFrom-Json
                    if ($ErrorAuthResponse.error -ne "authorization_pending") {
                        Write-Error "Authorization not successful. Error while posting body source: $($ErrorAuthResponse.error)"
                        throw
                    }
                }
            }
        
            if($AuthResponse.token_type -and $AuthResponse.access_token){
                $global:MicrosoftEntraIDAccessToken = "$($AuthResponse.token_type) $($AuthResponse.access_token)"
                $global:MicrosoftEntraIDHeader = @{
                    "Authorization" = "$global:MicrosoftEntraIDAccessToken"
                }
                Write-Output "Authorization successful! Token saved in variable."
            }
            else{
                Write-Error "Authorization not successful. Not enough information provided."
            }
        }
        
        # Authorization Header with ClientId & ClientSecret
        $tenantId="<tenantid>"
        $ClientId="<appregistrationclientapp>"
        $ClientSecret="<appregistrationclientsecret>"
        Build-MicrosoftEntraIDApplicationAccessHeader -tenantid $tenantid -clientid $clientid -clientSecret $clientSecret
        
        # Authorization Header with refresh_token
        $tenantId="<tenantid>"
        $refreshtoken="<yourrefreshtoken>"
        Build-MicrosoftEntraIDApplicationAccessHeader -tenantid $tenantid -refreshtoken $refreshtoken

        Get Bearer Token via PowerShell script

        This function allows you to use more than one header property. It only returns the access token which then has to be built into a header by itself. But the other functionalities and parameters work like the function above. 

        # Function for getting Microsoft Entra ID Access Token
        function Get-MicrosoftEntraIDApplicationAccessToken {
            param(
                [Parameter(Mandatory=$true)]
                [string] $tenantid,
                [string] $clientid,
                [string] $clientSecret,
                [string] $refreshtoken
            )
        
            $authenticationurl = "https://login.microsoftonline.com/$tenantid/TenantId/oauth2/v2.0/token" if($refreshtoken`
            -andBody $tenantId){TokenBody `
            -ContentType "application/x-www-form-urlencoded"
        
        $tokenBodySourceHeader = @{
            grant_typeAuthorization = "refresh_token"Bearer scope$($TokenResponse.access_token)"
            "Content-Type" = "https://graph.microsoft.com/.default"
                    refresh_token  = $refreshtokenapplication/json"
        }
        }
        elseif($tenantId

        Example: Managed Identity in Azure

        Connect-MgGraph -andIdentity
        $clientidGet-MgContext
        -and
        $clientSecret){

        Best $tokenBodySourcepractices

        =
        @{use grant_typeleast =privilege "client_credentials"prefer scopeManaged =Identity "https://graph.microsoft.com/.default"over client_idsecrets =prefer $clientidcertificates client_secretover =client "$clientSecret"secrets }when }Managed else{Identity Write-Error "Authorizationis not successful.possible Notstore enough information provided." } while ([string]::IsNullOrEmpty($AuthResponse.access_token)) { $AuthResponse = try { Invoke-RestMethod -Method POST -Uri $authenticationurl -Body $tokenBodySource } catch { $ErrorAuthResponse = $_.ErrorDetails.Message | ConvertFrom-Json if ($ErrorAuthResponse.error -ne "authorization_pending") { Write-Error "Authorization not successful. Error while posting body source: $($ErrorAuthResponse.error)" } } } if($AuthResponse.token_type -and $AuthResponse.access_token){ $global:MicrosoftEntraIDAccessToken = "$($AuthResponse.token_type) $($AuthResponse.access_token)" Write-Output "Authorization successful! Token savedsecrets in variable."Key }Vault else{review Write-ErrorGraph "Authorizationapp notpermissions successful.regularly Not enough

        Common informationmistakes

        provided."
        }expecting }a #refresh Authorizationtoken within ClientIdclient &credentials ClientSecretflow $tenantId="<tenantid>"using $ClientId="<appregistrationclientapp>"app-only $ClientSecret="<appregistrationclientsecret>"auth Get-MicrosoftEntraIDApplicationAccessTokenwhen -tenantida $tenantiduser -clientidcontext $clientidis -clientSecretactually $clientSecretrequired #hardcoding Authorizationsecrets within refresh_tokenscripts $tenantId="<tenantid>"forgetting $refreshtoken="<yourrefreshtoken>"admin Get-MicrosoftEntraIDApplicationAccessTokenconsent -tenantidfor $tenantidGraph -refreshtokenapplication $refreshtokenpermissions

        Summary


        For unattended Microsoft Graph automation, use application permissions and prefer Managed Identity whenever possible.