Modules/businessdev.ALbuild.Marketplace/Public/New-BcMarketplaceAuthContext.ps1

function New-BcMarketplaceAuthContext {
    <#
    .SYNOPSIS
        Acquires an OAuth2 access token for the Microsoft Marketplace / Partner Center APIs.
 
    .DESCRIPTION
        Performs an OAuth2 client-credentials flow against Azure AD and returns an auth context
        usable with the other Marketplace cmdlets. The Partner Center ingestion API and the Graph
        product-ingestion API use different scopes; pass the appropriate -Scope.
 
    .PARAMETER TenantId
        Azure AD tenant id (or verified domain).
 
    .PARAMETER ClientId
        Azure AD application (client) id.
 
    .PARAMETER ClientSecret
        Client secret (SecureString or plain string).
 
    .PARAMETER Scope
        OAuth2 scope. Default 'https://api.partner.microsoft.com/.default'. Use
        'https://graph.microsoft.com/.default' for product-ingestion (Get-BcMarketplaceProduct).
 
    .EXAMPLE
        $ctx = New-BcMarketplaceAuthContext -TenantId $t -ClientId $c -ClientSecret $s
 
    .OUTPUTS
        PSCustomObject with AccessToken, TokenType, ExpiresOn, TenantId, ClientId, Scope.
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',
        Justification = 'Acquires an OAuth token; it does not change system state.')]
    [CmdletBinding()]
    [OutputType([PSCustomObject])]
    param(
        [Parameter(Mandatory)] [string] $TenantId,
        [Parameter(Mandatory)] [string] $ClientId,
        [Parameter(Mandatory)] [object] $ClientSecret,
        [string] $Scope = 'https://api.partner.microsoft.com/.default'
    )

    Assert-ALbuildLicensed -Feature 'Marketplace'

    $plainSecret = if ($ClientSecret -is [System.Security.SecureString]) {
        [System.Net.NetworkCredential]::new('', $ClientSecret).Password
    } else { [string]$ClientSecret }

    $body = @{
        client_id     = $ClientId
        client_secret = $plainSecret
        scope         = $Scope
        grant_type    = 'client_credentials'
    }

    $tokenUrl = "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token"
    $response = Invoke-RestMethod -Uri $tokenUrl -Method Post -Body $body -ContentType 'application/x-www-form-urlencoded' -ErrorAction Stop

    return [PSCustomObject]@{
        AccessToken = $response.access_token
        TokenType   = $response.token_type
        ExpiresOn   = (Get-Date).AddSeconds([int]$response.expires_in)
        TenantId    = $TenantId
        ClientId    = $ClientId
        Scope       = $Scope
    }
}