Public/Connect-SF.ps1
|
<# .SYNOPSIS Connects to the SuccessFactors API using a ConnectorConfiguration object. .DESCRIPTION Validates configuration, selects auth flow (Assertion or ClientCredentials) and stores the access token. Supports two OAuth 2.0 authentication flows: SAML2 assertion with X.509 private key, or direct client credentials. Automatically calculates token expiry and manages renewal. .PARAMETER ConnectorConfiguration Hashtable containing configuration and secrets. Must include baseurl, clientid, and companyid. For Assertion flow, also requires userid and secrets.privatekey. For ClientCredentials flow, requires secrets.clientsecret. .PARAMETER ForceRenewal Force renewal of the access token during connection. .OUTPUTS None - Stores connection state and token internally. .NOTES The function stores the access token in module scope for use by other functions. Token expiry includes a 60-second buffer to ensure renewal before actual expiration. #> function Connect-SF { [CmdletBinding()] [OutputType([void])] Param ( [Parameter(Mandatory = $true)] $ConnectorConfiguration, [Parameter(Mandatory = $false)] [switch] $ForceRenewal ) Process { # Validate required configuration. $baseUrl = $ConnectorConfiguration.configuration.baseurl if (-not $baseUrl) { throw "baseurl is required." } $clientID = $ConnectorConfiguration.configuration.clientid if (-not $clientID) { throw "clientid is required." } $companyID = $ConnectorConfiguration.configuration.companyid if (-not $companyID) { throw "companyid is required." } $authFlow = $ConnectorConfiguration.configuration.authflow if (-not $authFlow) { $authFlow = 'Assertion' } if ($authFlow -notin @('Assertion', 'ClientCredentials')) { throw "authflow must be 'Assertion' or 'ClientCredentials'." } # Retrieve token using the configured auth flow. if ($authFlow -eq 'Assertion') { # For the Assertion flow, we need the user ID and private key to obtain a SAML assertion first. $userID = $ConnectorConfiguration.configuration.userid if (-not $userID) { throw "userid is required when authflow is 'Assertion'." } # The private key is required for the Assertion flow to obtain the SAML assertion. $privateKey = $ConnectorConfiguration.secrets.privatekey if (-not $privateKey) { throw "secrets.privatekey is required when authflow is 'Assertion'." } # Get SAML assertion and then exchange it for an access token. $sfAssertion = Get-SFAssertion -BaseUrl $baseUrl -UserID $userID -ClientID $clientID -TokenEndpointURL "$baseUrl/oauth/token" -PrivateKey $privateKey $sfToken = Get-SFToken -BaseUrl $baseUrl -ClientID $clientID -CompanyID $companyID -Assertion $sfAssertion -ForceNew:$ForceRenewal } else { # For the ClientCredentials flow, we need the client secret to obtain an access token. $clientSecret = $ConnectorConfiguration.secrets.clientsecret if (-not $clientSecret) { throw "secrets.clientsecret is required when authflow is 'ClientCredentials'." } # Get access token directly using client credentials. $sfToken = Get-SFToken -BaseUrl $baseUrl -ClientID $clientID -CompanyID $companyID -ClientSecret $clientSecret -ForceNew:$ForceRenewal } if (-not $sfToken -or -not $sfToken.access_token) { throw "SuccessFactors token response did not contain 'access_token'." } # Only store configuration after a successful token retrieval. $Script:ConnectorConfiguration = $ConnectorConfiguration $Script:AccessToken = $sfToken.access_token # Calculate token expiry time, subtracting a buffer to ensure we renew before it actually expires. $expiresIn = $sfToken.expires_in ? [int]$sfToken.expires_in : 3600 $Script:AccessTokenExpiry = (Get-Date).AddSeconds($expiresIn - 60) } } |