401 unauthorized in powershell API call

Description
I’m trying to simply get a channel ID. I found the powershell module PSZoom, which works, but will not return the info I need AFAIK. I took some code from the individual functions in the modules to build the code below. It runs, but returns a 401 unauthorized error

Error
401 unauthorized when trying to get channel lists for my user

Which App?
Custom app, JWT

How To Reproduce (If applicable)
Run script below

Additional context
All code is from the PSZoom module

Note that APIkey and APIsecret are saved to variables, removed prior to posting. Bolded text near the end contains my user id obtained from get-zoomuser

Import-Module pszoom

function New-Jwt
{
param (
[Parameter(Mandatory = $True)]
[ValidateSet(‘HS256’, ‘HS384’, ‘HS512’)]
[string]$Algorithm,
$Type = $null,
[Parameter(Mandatory = $True)]
[string]$Issuer,
[int]$ValidforSeconds = $null,
[Parameter(Mandatory = $True)]
[string]$SecretKey
)

Write-Verbose 'Generating JWT'
$Exp = [int][double]::parse((Get-Date -Date $((Get-Date).addseconds($ValidforSeconds).ToUniversalTime()) -UFormat %s)) # Grab Unix Epoch Timestamp and add desired expiration

$Header = @{
	alg = $Algorithm
	typ = $Type
}

$Payload = @{
	iss = $Issuer
	exp = $Exp
}

$Headerjson = $Header | ConvertTo-Json -Compress
$Payloadjson = $Payload | ConvertTo-Json -Compress

$Headerjsonbase64 = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($Headerjson)).Split('=')[0].Replace('+', '-').Replace('/', '_')
$Payloadjsonbase64 = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($Payloadjson)).Split('=')[0].Replace('+', '-').Replace('/', '_')

$ToBeSigned = $Headerjsonbase64 + "." + $Payloadjsonbase64

$SigningAlgorithm = switch ($Algorithm)
{
	"HS256" { New-Object System.Security.Cryptography.HMACSHA256 }
	"HS384" { New-Object System.Security.Cryptography.HMACSHA384 }
	"HS512" { New-Object System.Security.Cryptography.HMACSHA512 }
}

$SigningAlgorithm.Key = [System.Text.Encoding]::UTF8.GetBytes($SecretKey)
$Signature = [Convert]::ToBase64String($SigningAlgorithm.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($ToBeSigned))).Split('=')[0].Replace('+', '-').Replace('/', '_')

$Token = "$Headerjsonbase64.$Payloadjsonbase64.$Signature"

Write-Output $Token

}

function Get-ZoomApiCredentials
{
[CmdletBinding()]
Param (
[string]$ZoomApiKey,
[string]$ZoomApiSecret
)

try
{
	Write-Verbose -Message 'Retrieving Zoom API Credentials.'
	
	if (-not $Global:ZoomApiKey)
	{
		if (-not [string]::IsNullOrWhiteSpace($ZoomApiKey))
		{
			$Global:ZoomApiKey = $ZoomApiKey
		}
		else
		{
			$Global:ZoomApiKey = if ($PSPrivateMetadata.JobId)
			{
				Get-AutomationVariable -Name ZoomApiKey
			}
			else
			{
				Read-Host 'Enter Zoom Api key (push ctrl + c to exit)'
			}
		}
	}
	
	if (-not $Global:ZoomApiSecret)
	{
		if (-not [string]::IsNullOrWhiteSpace($ZoomApiSecret))
		{
			$Global:ZoomApiSecret = $ZoomApiSecret
		}
		else
		{
			$Global:ZoomApiSecret = if ($PSPrivateMetadata.JobId)
			{
				Get-AutomationVariable -Name ZoomApiSecret
			}
			else
			{
				Read-Host 'Enter Zoom Api Secret (push ctrl + c to exit)'
			}
		}
	}
	
	@{
		'ApiKey'    = $Global:ZoomApiKey
		'ApiSecret' = $Global:ZoomApiSecret
	}
	
	Write-Verbose 'Retrieved API Credentials.'
}
catch
{
	Write-Error "Problem getting Zoom Api Authorization variables:`n$_"
}

}

function New-ZoomHeaders
{
param (
[string]$ApiKey,
[string]$ApiSecret
)
$Credentials = Get-ZoomApiCredentials -ZoomApiKey $ApiKey -ZoomApiSecret $ApiSecret
$Token = New-Jwt -Algorithm ‘HS256’ -type ‘JWT’ -Issuer $Credentials.ApiKey -SecretKey $Credentials.ApiSecret -ValidforSeconds 30

Write 'Generating Headers'
$Headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$Headers.Add('content-type', 'application/json')
$Headers.Add('authorization', 'bearer ' + $Token)

Write-Output $Headers

}

$Headers = New-ZoomHeaders -ApiKey $ApiKey -ApiSecret $ApiSecret
$Request = [System.UriBuilder]“https://api.zoom.us/v2/chat/users/MY USER ID/channels”

write $Headers

$response = Invoke-RestMethod -Uri $request.Uri -Headers $Headers -Method POST

$response

Hi @Pew05 ,

Welcome to the Dev Forum! I am unfamiliar with the powershell module PSZoom as it it not a Zoom created product, but can you please clarify what information you’re looking to return via channel ID that it does not show?

Thanks,
Gianni

Hi, I made the module and can help. Are you trying to use this API call: https://marketplace.zoom.us/docs/api-reference/zoom-api/chat-channels/getchannels ?

I think maybe you’re using POST when you should be using GET for the method parameter. This should work (I don’t use chat and can’t test really):

import-module pszoom
$userID = 'put_user_id_here'
$Request = [System.UriBuilder]"https://api.zoom.us/v2/chat/users/$userID/channels"
Invoke-ZoomRestMethod -Uri $request.Uri -ApiKey $your_api_key -ApiSecret $your_api_secret -Method GET

Let me know how it turns out.

Hello, thank you for your reply. That is how I started, but I can’t get it to connect. When I run what you provided above with my api key, secret and userID, I get this:

ERROR: Invoke-ZoomRestMethod : The remote server returned an error: (401) Unauthorized. This API only supports oAuth2 for authorization.
get-channelid2.ps1 (23, 1): ERROR: At Line: 23 char: 1
ERROR: + Invoke-ZoomRestMethod -Uri $request.Uri -ApiKey $apikey -ApiSecret $a …
ERROR: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ERROR: + CategoryInfo : AuthenticationError: (https://api.zoo…XGcU_A/channels:) [Write-Error], This API only s… authorization.
ERROR: + FullyQualifiedErrorId : 401,Invoke-ZoomRestMethod

This API only supports oAuth2 for authorization

There’s your issue. PSZoom uses JWT. I’m not sure how to implement oauth2 in PowerShell.

Hey @maci01,

Thanks for sharing your insight here! @Pew05 I don’t have any experience with OAuth2 and Powershell either. Let me know if this 3rd party guide helps:

Thanks,
Max

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.