Skip to content

Cut 5088 updating power shell module to handle o auth/service account tokens#742

Open
shashisinghjc wants to merge 5 commits into
masterfrom
CUT-5088-Updating-PowerShell-Module-to-handle-OAuth/ServiceAccount-tokens
Open

Cut 5088 updating power shell module to handle o auth/service account tokens#742
shashisinghjc wants to merge 5 commits into
masterfrom
CUT-5088-Updating-PowerShell-Module-to-handle-OAuth/ServiceAccount-tokens

Conversation

@shashisinghjc
Copy link
Copy Markdown
Contributor

@shashisinghjc shashisinghjc commented May 20, 2026

Issues

  • CUT-5088 - Updating PowerShell Module to handle OAuth/Service Account tokens

What does this solve?

This adds a new authentication method i.e. ClientSecret(OIDC). Earlier only API key was allowed.

Is there anything particularly tricky?

NA

How should this be tested?

Use Connect-JCOnline - Default is the API key authentication
Use Set-JCSettings -authPreferenceMethod ClientSecret (This will switch to ClientSecret) and opt for the client ID and Client Secret

Screenshots


Note

High Risk
Touches core authentication for all API traffic and stores client secrets and tokens in environment variables; client-secret mode also disables some SDK-dependent features until bearer support exists.

Overview
Adds OAuth client-credentials as an optional auth path alongside the existing API key, controlled by authPreference.Method in Config.json (apiKey default, or clientSecret via Set-JCSettingsFile).

New plumbing issues and refreshes bearer tokens (New-JCBearerToken, Get-JCAccessToken with expiry skew), and Get-JCAuthHeaders switches between x-api-key and Authorization: Bearer. Connect-JCOnline, Set-JCOrganization, Invoke-JCApi, and Get-JCResults now branch on auth method and use shared headers. Get-JCAuthStatus reports masked client ID and token expiry in client-secret mode.

JumpCloud.SDK policy template argument completion is skipped when clientSecret is active (SDK still requires -ApiKey). Pester tests cover token, headers, and bearer issuance.

Reviewed by Cursor Bugbot for commit 2683b3c. Bugbot is set up for automated code reviews on this repo. Configure here.

@lucasmendes-jc lucasmendes-jc self-requested a review May 21, 2026 14:31
Copy link
Copy Markdown
Contributor

@jworkmanjc jworkmanjc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay I did add one change to support getting some data with ClientID/ClientSecret. I suspect we'll need to add more to clear this work up.

One question I had was if it was really required to get a new token on each request. I'm running Get-JCUser -username "someUser" -debug to test the new flow and watching the flow from Connect-JCOnline -> New-JCBearerToken. We should be making use of the Token "Expires_in" value which I believe is in seconds so we don't have to do another request to auth every time we hit "Connect-JCOnline" Not sure if it's best to just set it as en Environment Variable or set it in the config. But we shouldn't be generating a new token each time I do a request for data. I think we can do something like this:

First ClientID/Secret request, Get-CurrentDate, get authToken, look at expires_in value and record (Current-Date + add expires_in(in seconds) as some env variable. Next time we do a request check if Current date -gt that Env variable and perform auth again if necessary.

What do you think about that @shashisinghjc? We'd have to do the same thing for OIDC auth right?

@shashisinghjc
Copy link
Copy Markdown
Contributor Author

hi @jworkmanjc , here's the flow. New-Bearer token is only called when the token is missing or expired.

Every API request flow:

Invoke-JCApi → calls Get-JCAuthHeaders
Get-JCAuthHeaders → calls Get-JCAccessToken
Get-JCAccessToken checks token validity:
Token is valid → Returns cached $env:JCAccessToken (no API call)
Token expired/missing → Calls New-JCBearerToken to fetch new token

New token is Stored in $env:JCAccessToken and $global:JCAccessToken.
Expiration: Tracked in $env:JCAccessTokenExpiresAt

lucasmendes-jc
lucasmendes-jc previously approved these changes May 25, 2026
@shashisinghjc shashisinghjc marked this pull request as ready for review May 26, 2026 14:08
@shashisinghjc shashisinghjc requested a review from a team as a code owner May 26, 2026 14:08
@shashisinghjc shashisinghjc requested a review from edgar-lins May 26, 2026 14:08
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 2683b3c. Configure here.

$Param_JumpCloudOrgId.Add('Mandatory', $true)
} else {
$Param_JumpCloudOrgId.Add('Default', $env:JCOrgId)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JumpCloudOrgId now incorrectly mandatory for apiKey mode

High Severity

In the old code, JumpCloudOrgId was never mandatory — it only received a default when $env:JCOrgId was already set. Now, when $env:JCOrgId is empty (e.g., first connection in a session), the parameter is made Mandatory, forcing users to supply an OrgId upfront. This breaks the existing workflow where users call Connect-JCOnline -JumpCloudApiKey "xxx" and the module auto-discovers the org via Set-JCOrganization. This applies to both apiKey and clientSecret branches.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 2683b3c. Configure here.

if ($oauthErrorDetail) {
$msg += " Response body: $oauthErrorDetail"
}
throw $msg
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nested catch shadows $_ corrupting error message

Low Severity

In New-JCBearerToken, the inner catch block (for stream-reading failures) overwrites $_ in the shared scope. After the inner try/catch completes, lines that reference $_.ErrorDetails and $_.Exception.Message to build the error message may reference the stream-reading error instead of the original REST/OAuth error. PowerShell's try/catch doesn't create a new scope, so the inner catch clobbers the outer $_.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 2683b3c. Configure here.

begin {
$hdrs = @{
'Content-Type' = 'application/json'
'Accept' = 'application/json'
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fallback x-org-id in Get-JCResults is dead code

Medium Severity

Get-JCAuthHeaders always includes the x-org-id key in its returned hashtable (even when $env:JCOrgId is empty). The ContainsKey('x-org-id') check is therefore always true, making the fallback to add x-org-id from $JCOrgID dead code. The old code conditionally added x-org-id only when $JCOrgID was truthy; now x-org-id is always present (potentially with an empty string value), which could cause API errors if $env:JCOrgId isn't set yet.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 2683b3c. Configure here.

Base automatically changed from v3.2.0_pwshModule to master May 27, 2026 17:46
@edgar-lins edgar-lins dismissed lucasmendes-jc’s stale review May 27, 2026 17:46

The base branch was changed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants