Public/Authentication/New-SCASession.ps1

function New-SCASession {
    <#
    .SYNOPSIS
        Authenticates to CyberArk's Identity Security Platform and starts a psSCA session.
    .DESCRIPTION
        Exchanges a service user's credentials for a bearer access token via the ISPSS platform
        token endpoint (POST https://<identity-tenant-id>.id.cyberark.cloud/oauth2/platformtoken)
        and stores the resulting session in memory for use by every other psSCA cmdlet.

        The service user must be configured as an OAuth confidential client in Identity
        Administration and must be a member of the role(s) required by whichever CyberArk services
        you intend to call (for example, SCA Admin for cloud console access, CEMAPIAdmin for
        workspace delegation). See docs/AUTHENTICATION.md for the full role matrix.

        The access token is kept only in memory as a SecureString for the lifetime of the
        PowerShell session; it is never written to disk, and Verbose/Debug output redacts it.
    .PARAMETER Name
        A friendly name for this session, used to target it later with -Session on other cmdlets.
        Defaults to 'Default'.
    .PARAMETER IdentityTenantId
        The Identity tenant subdomain used to reach the platform token endpoint, e.g. 'aaf1234'
        for 'aaf1234.id.cyberark.cloud'.
    .PARAMETER TenantSubdomain
        The tenant subdomain used to reach the SCA, UAP, UAR, CDS, CEM, and Risk Management
        service APIs. Defaults to the value of -IdentityTenantId, which is correct for the common
        case where all services share one tenant subdomain.
    .PARAMETER Credential
        A PSCredential whose UserName is the service user's login name and whose Password is the
        service user's password (used as client_id / client_secret in the token request).
    .PARAMETER Default
        Marks this session as the default used by other cmdlets when -Session is not specified.
        The first session created in a PowerShell session is always the default regardless of
        this switch.
    .EXAMPLE
        $cred = Get-Credential
        New-SCASession -IdentityTenantId 'aaf1234' -Credential $cred

        Starts the default psSCA session against tenant aaf1234.
    .EXAMPLE
        New-SCASession -Name Production -IdentityTenantId 'aaf1234' -Credential $cred -Default

        Starts a named session and marks it as the default for subsequent cmdlets.
    .INPUTS
        None.
    .OUTPUTS
        psSCA.Session
    .NOTES
        Only the client-credentials (service user) flow is implemented. Interactive Idira Identity
        browser-based login is not exposed as a non-interactive API and is out of scope.
    .LINK
        https://api-docs.cyberark.com/create-api-token/docs/create-api-token
    #>

    [Diagnostics.CodeAnalysis.SuppressMessage(
        'PSAvoidUsingConvertToSecureStringWithPlainText', '',
        Justification = 'Converts a token just received over TLS into a SecureString for in-memory storage; this is the secure direction, not a hardcoded secret.')]
    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')]
    [OutputType('psSCA.Session')]
    param(
        [Parameter()]
        [string]$Name = 'Default',

        [Parameter(Mandatory)]
        [string]$IdentityTenantId,

        [Parameter()]
        [string]$TenantSubdomain,

        [Parameter(Mandatory)]
        [pscredential]$Credential,

        [switch]$Default
    )

    if (-not $TenantSubdomain) {
        $TenantSubdomain = $IdentityTenantId
    }

    $tokenUri = "https://$IdentityTenantId.id.cyberark.cloud/oauth2/platformtoken"
    $plainSecret = $Credential.GetNetworkCredential().Password
    $bodyPairs = @(
        'grant_type=client_credentials'
        "client_id=$([System.Uri]::EscapeDataString($Credential.UserName))"
        "client_secret=$([System.Uri]::EscapeDataString($plainSecret))"
    )

    if (-not $PSCmdlet.ShouldProcess($IdentityTenantId, 'Request platform access token')) {
        return
    }

    Write-Verbose "psSCA: requesting platform token from $tokenUri"

    try {
        $response = Invoke-WebRequest -Uri $tokenUri -Method Post -Body ($bodyPairs -join '&') `
            -ContentType 'application/x-www-form-urlencoded' -UseBasicParsing -TimeoutSec $script:PSSCADefaultTimeoutSec -ErrorAction Stop
    }
    catch {
        $errorRecord = Resolve-SCAError -ErrorRecord $_ -Service 'Identity' -Operation 'New-SCASession' -Uri $tokenUri
        $PSCmdlet.ThrowTerminatingError($errorRecord)
    }
    finally {
        $plainSecret = $null
    }

    $token = $response.Content | ConvertFrom-Json

    $session = [pscustomobject]@{
        PSTypeName       = 'psSCA.Session'
        Name             = $Name
        IdentityTenantId = $IdentityTenantId
        TenantSubdomain  = $TenantSubdomain
        TokenType        = $token.token_type
        AccessToken      = (ConvertTo-SecureString -String $token.access_token -AsPlainText -Force)
        ExpiresAt        = [DateTime]::UtcNow.AddSeconds([int]$token.expires_in)
        CreatedAt        = [DateTime]::UtcNow
        ModuleVersion    = $script:PSSCAModuleVersion
    }

    $script:SCASessions[$Name] = $session
    if ($Default -or $script:SCASessions.Count -eq 1) {
        $script:SCACurrentSessionName = $Name
    }

    Write-Verbose "psSCA: session '$Name' established, expires $($session.ExpiresAt.ToString('u'))"
    return $session
}