GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat(credentials): second auth modes for ServiceNow, Snowflake, Infisical, and Google Ads by waleedlatif1 · Pull Request #9928 · simstudioai/sim

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Nov 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a second (or third) sign-in mode to integrations that already support saved credentials. Each one is a new authMethod or stored blob type, and every existing stored shape resolves exactly as before.

  • ServiceNow: OAuth client credentials. Sim mints a token at {instance}/oauth_token.do through the configured-endpoint egress guard and shares one coordinated token per client. Tools and attachment upload send it as a Bearer token. Saved username/password logins are unchanged (Basic).
  • Snowflake: key-pair JWT as a third mode, beside programmatic access tokens and keyless workload identity. Sim stores an unencrypted RSA key (2048 to 4096 bits) and signs an RS256 JWT for each run: iss is ACCOUNT.USER.SHA256:<fp>, sub is ACCOUNT.USER, both uppercased, valid 59 minutes, sent with X-Snowflake-Authorization-Token-Type: KEYPAIR_JWT. The account comes from the host's first label. An account whose name has underscores signs as that name from either of its hostnames (myorg-my_account or myorg-my-account): organization names hold only letters and numbers and account names never hold a hyphen, so every hyphen after the first is a replaced underscore. It needs no workload identity, so organization credentials and deployments without a signing key can use it. The credential provider catalog (v2, Copilot, CLI) lists a Snowflake "Connection configuration" field that documents the key pair in every scope; the keyless hint is appended only where keyless is available. Host hints now name .snowflakecomputing.cn, which was already accepted.
  • Infisical: Universal Auth client ID and secret, logged in at {instance}/api/v1/auth/universal-auth/login through the new postToConfiguredTokenEndpoint guard. This replaces pasted access tokens that expire. One coordinated token per identity, served for at most a day. An expiresIn of 0 (an access token TTL of 0) is also served for a day. Revoked tokens and tokens past their use limit are answered with 401 by Infisical, so the existing 401 invalidation logs in again on the next call.
  • Google Ads: accepts the google-service-account JSON key (adwords scope; the service account is added as a user in Ads). Keyless Google credentials are still refused for Ads.
  • Shared, additive pieces:
    • exchangeClientCredentialsGrant takes an egress: 'configuredEndpoint' option. The request type is a discriminated union, so fetchOptions can't be combined with it.
    • readAccessTokenResponse holds the refusal classification, capped JSON read, token and lifetime checks, and lifetime cap. The grant and the Infisical login both use it.
    • OAuthConfig.optionalCredentialParams lets a tool policy name a mapped param that a credential mode lacks; it is cleared instead of failing.
    • Token descriptor fields take requiredForAuthMethods (token or client_credentials), the same vocabulary client-credential descriptors and the v2 catalog already use. ServiceNow's username is ['token']: it shows only in the pasted-token mode, is never required or stored in client-credentials mode, and the catalog says so.
    • authStyle gains bearer and snowflake-key-pair; both are authoritative, so caller or model values are stripped.

Vendor references: ServiceNow client credentials and grant workflow; Snowflake SQL API authentication and account identifiers; Infisical Universal Auth login, attach (TTL ranges) and Universal Auth; Google Ads service accounts and developer token sunset.

Not included: Infisical OIDC keyless. Infisical matches subjects as glob patterns, so Sim cannot pin a credential's subject, and this needs a security decision and a live proof first.

Product update (if relevant)

  • ServiceNow and Infisical can connect without storing a person's password or a token that expires.
  • Snowflake can connect with a key pair wherever keyless workload identity isn't available.
  • Google Ads reporting can run as a service account.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation
  • Other: ___________

Testing

  • Unit tests were written test-first for each grant and minter. They cover request shape through the egress guard, lifetime caps (including Infisical's expiresIn 0), refused and invalid responses, unsafe instance URLs, missing secrets (no request sent), and abort. The configured-endpoint guard's own cases (egress refused, unresolvable or transiently failing host, abort) are tested in client-credentials-grant.test.ts.
  • Snowflake JWT claims and fingerprint, locator accounts, underscore accounts from both hostnames, and key-shape refusals are tested.
  • Catalog contract tests check that the Snowflake key-pair field is listed for workspaces that can sign, workspaces that cannot, and organization scope, and that ServiceNow's username carries requiredForAuthMethods: ['token'].
  • Executor tests check that a ServiceNow login sends Basic as before, a minted token is sent as Bearer, and a caller-supplied username is never paired with the saved password.
  • Revert proofs: removing the user uppercasing, the optional-param clearing, or the zero-lifetime handling turns the matching tests red. The hyphen-host test was red before the account-name fix, and the catalog tests were red before the catalog changes.
  • Targeted Vitest passes. Generated-artifact and boundary checks pass: tool-metadata, deployment-config, openapi, cli-api, mcp-operations, egress-boundary, api-validation:strict.
  • Reviewers, please focus on:
    • Rolling deploys: old workers fail closed on the new blob types and authStyle values.
    • Keyless subject sweep: it treats a key-pair blob as keyed, so it never blocks keyless creation.
    • ServiceNow inline mode: authStyle cannot be set by an inline caller.

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

Screenshots/Videos

Connect dialogs: ServiceNow and Infisical gain an auth method picker; Snowflake gains a "Key pair (RSA private key)" option.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

greptile-apps[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@vercel

vercel Bot commented Nov 12, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
docs Ready Ready Preview Nov 12, 2026 12:43pm UTC

Request Review

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vercel
vercel Bot deployed to Preview November 12, 2026 11:53
View deployment
@greptile-apps

greptile-apps Bot commented Nov 12, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no new actionable issues were established.

Summary

Adds saved sign-in options for ServiceNow, Snowflake, Infisical, and Google Ads.

  • Snowflake connections can sign in with an RSA key pair.
  • ServiceNow tools can use saved OAuth client credentials.
  • Infisical credentials can log in with Universal Auth.
  • Google Ads can use a Google service-account key.
  • Saved credentials share guarded token requests and auth-mode fields.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Saved credential] --> B{Sign-in mode}
  B --> C[ServiceNow or Infisical coordinated token]
  B --> D[Snowflake token signed with saved key]
  B --> E[Google JSON-key token]
  C --> F[Authorized tool call]
  D --> F
  E --> F
Loading

Reviews (2) · Last reviewed commit: "fix(snowflake): verify key pairs through..." · Reviewed by Greptile

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

greptile-apps[bot]
greptile-apps Bot reviewed Nov 12, 2026
View reviewed changes
Comment thread ...rkspaceId]/integrations/components/connect-service-account-modal/snowflake-account-modal.tsx Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread apps/sim/lib/credentials/token-service-accounts/grants/infisical.test.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

cubic-dev-ai[bot]
cubic-dev-ai Bot reviewed Nov 12, 2026
View reviewed changes

@cubic-dev-ai cubic-dev-ai Bot left a comment •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

All reported issues were addressed across 56 files

Turn on auto-fix | Re-trigger cubic

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread apps/sim/lib/credentials/token-service-accounts/validators/snowflake.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread apps/sim/lib/credentials/snowflake-service-account.server.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread ...rkspaceId]/integrations/components/connect-service-account-modal/snowflake-account-modal.tsx Resolved

Uh oh!

There was an error while loading. Please reload this page.

waleedlatif1 added 11 commits November 12, 2026 04:06
@waleedlatif1
feat(google-ads): accept a Google service account JSON key
12d5f23
Google Ads now offers the google-service-account credential: a service
account added as a user of the Ads account signs in as itself with the
adwords scope (developer tokens were retired). Keyless Google credentials
stay refused because Google documents no Workload Identity path for Ads.
@waleedlatif1
feat(infisical): log machine identities in with Universal Auth
b6a5d78
Infisical credentials gain a Universal Auth mode: the machine identity's
client ID and secret are stored instead of a pasted access token, and Sim
logs in at the credential's instance through the configured-endpoint egress
guard whenever its token expires. One coordinated token serves every
credential for an identity, so logins don't multiply per worker. Pasted
access-token credentials are unchanged.

Adds postToConfiguredTokenEndpoint, the guarded token request for hosts
taken from a validated credential field.
@waleedlatif1
feat(servicenow): connect with an OAuth client's client credentials
3019d84
ServiceNow credentials gain an OAuth client credentials mode beside the
username and password login. The client ID and secret are stored, and Sim
mints a token at the instance's /oauth_token.do through the
configured-endpoint egress guard, shared across workers. The minted token
resolves with authStyle 'bearer', which the ServiceNow tools and the
attachment upload operation send as a bearer token. Saved logins store and
resolve exactly as before.

Shared changes, each additive: exchangeClientCredentialsGrant takes an
egress option for configured hosts; a tool policy can name mapped params a
credential mode lacks (optionalCredentialParams), which are cleared rather
than failing; a token descriptor field can belong to the pasted-token mode
only; a token check's account id may be absent for a sign-in mode.
@waleedlatif1
feat(snowflake): connect with an RSA key pair
7e7ec5f
Snowflake connections gain a key-pair mode beside keyless workload
identity and programmatic access tokens. Sim stores the user's unencrypted
RSA private key and signs a JWT for every run (iss ACCOUNT.USER.SHA256:<fp>,
sub ACCOUNT.USER, uppercased, 59-minute lifetime) that tools and selectors
send with the KEYPAIR_JWT token type. The account comes from the host the
way Snowflake's drivers derive it. Key pairs need no workload identity, so
organization connections and deployments without a signing key can use
them; the connect dialog now always offers them. Token and keyless
credentials store and resolve exactly as before.

Host hints now name .snowflakecomputing.cn, which the validator, tools,
and selectors already accept.
@waleedlatif1
refactor(servicenow): keep the Basic header builder private to its utils
13a3ab6
serviceNowAuthorization is now the only caller, so the export was unused.
@waleedlatif1
fix(snowflake): name an underscore account the same from either of it…
12d59ed
…s hostnames

Snowflake also serves an account whose name has underscores at a hostname
with hyphens in their place. Organization names hold only letters and
numbers and account names never hold a hyphen, so every hyphen after the
first in an org-account host label is a replaced underscore and is
restored before the key-pair JWT names the account. The derivation moves
next to normalizeSnowflakeHost and its suffix list. The connection secret
type is renamed for the three modes, and the modal shares one saved-
connection submit hook.
@waleedlatif1
refactor(credentials): share the token response reader with the Infis…
b788acc
…ical login

readAccessTokenResponse holds the refusal classification, capped JSON read,
token and lifetime checks, and lifetime cap that exchangeClientCredentialsGrant
and the Infisical Universal Auth login both need. An Infisical expiresIn of 0
(an access token TTL of 0) is served for the daily cap instead of failing as an
outage. egress and fetchOptions become a discriminated union, and the
configured-endpoint guard's own cases are tested where it lives.
@waleedlatif1
refactor(servicenow): tighten the saved-credential params and auth types
6405015
The hidden credential params become a constant like Zendesk's, the upload
schema accepts only the bearer authStyle, and serviceNowAuthorization takes an
optional username so the upload client no longer fakes one. A pasted-token-only
descriptor field stays hidden until that mode is chosen and is never required
in client-credentials mode.
@waleedlatif1
fix(snowflake): list the key-pair connection in the credential provid…
8925e0c
…er catalog
@waleedlatif1
refactor(servicenow): mark the username with requiredForAuthMethods s…
edc3571
…o the catalog scopes it to the password sign-in
@waleedlatif1
fix(snowflake): verify key pairs through the egress guard and leave a…
e3e7242
…n organization reconnect's mode unchosen

Key-pair validation now sends its signed JWT through the same guarded egress
path as keyless, so an account host that resolves to a private address is
refused as host_not_allowed. An organization credential's stored mode is not
reported, so its reconnect starts with no mode chosen instead of defaulting to a
programmatic access token. The Infisical and ServiceNow grant tests use the
shared jsonResponse helper.
@waleedlatif1
waleedlatif1 force-pushed the feat/credential-second-modes branch from c0c4650 to e3e7242 Compare November 12, 2026 12:38
@waleedlatif1

waleedlatif1 commented Nov 12, 2026

Copy link
Copy Markdown
Collaborator Author

@greptile

greptile-apps[bot] reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@waleedlatif1

waleedlatif1 commented Nov 12, 2026

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

cubic-dev-ai[bot] reacted with eyes emoji
All reactions
  • 👀 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@cubic-dev-ai

cubic-dev-ai Bot commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vercel
vercel Bot deployed to Preview November 12, 2026 12:43
View deployment
cubic-dev-ai[bot]
cubic-dev-ai Bot reviewed Nov 12, 2026
View reviewed changes

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

2 issues found across 57 files

Confidence score: 3/5

  • In oauth.ts, the shared provider alias lets keyless Google credentials be selected for Google Ads even though the token resolver rejects them. Exclude keyless credentials from that selection.
  • In snowflake-account-modal.tsx, the private key stays visible after the field loses focus, exposing it to shoulder-surfing or screen captures. Mask it when unfocused, matching the existing private-key input pattern.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/sim/app/workspace/[workspaceId]/integrations/components/connect-service-account-modal/snowflake-account-modal.tsx">

<violation number="1" location="apps/sim/app/workspace/[workspaceId]/integrations/components/connect-service-account-modal/snowflake-account-modal.tsx:345">
P2: This private-key field leaves the full RSA key visible after focus leaves, exposing a credential to shoulder-surfing or screen captures. Mask the value when unfocused, matching the existing private-key input pattern.</violation>
</file>

<file name="apps/sim/lib/oauth/oauth.ts">

<violation number="1" location="apps/sim/lib/oauth/oauth.ts:503">
P2: This shared provider alias also makes existing keyless Google credentials eligible for Google Ads credential selection, but the token resolver explicitly rejects `google-ads` for keyless credentials. Filter keyless credentials out for this service (or add service-aware eligibility) so users cannot select a credential that every Ads run will reject.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Turn on auto-fix | Re-trigger cubic

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread ...rkspaceId]/integrations/components/connect-service-account-modal/snowflake-account-modal.tsx
value={privateKey}
onChange={(event) => edit(setPrivateKey)(event.target.value)}
placeholder='-----BEGIN PRIVATE KEY-----'
className='min-h-[120px] font-mono'

@cubic-dev-ai cubic-dev-ai Bot Nov 12, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

P2: This private-key field leaves the full RSA key visible after focus leaves, exposing a credential to shoulder-surfing or screen captures. Mask the value when unfocused, matching the existing private-key input pattern.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/app/workspace/[workspaceId]/integrations/components/connect-service-account-modal/snowflake-account-modal.tsx, line 345:

<comment>This private-key field leaves the full RSA key visible after focus leaves, exposing a credential to shoulder-surfing or screen captures. Mask the value when unfocused, matching the existing private-key input pattern.</comment>

<file context>
@@ -292,6 +319,42 @@ function SnowflakeAccountForm({
+                  value={privateKey}
+                  onChange={(event) => edit(setPrivateKey)(event.target.value)}
+                  placeholder='-----BEGIN PRIVATE KEY-----'
+                  className='min-h-[120px] font-mono'
+                  spellCheck={false}
+                  autoComplete='off'
</file context>
Suggested change
className='min-h-[120px] font-mono'
className={`min-h-[120px] font-mono ${privateKey ? '[&:not(:focus)]:[-webkit-text-security:disc]' : ''}`}
Fix with cubic

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread apps/sim/lib/oauth/oauth.ts
* Google credentials stay refused here: Ads is not in `GOOGLE_KEYLESS_SERVICES`, since
* Google documents no Workload Identity Federation path for it.
*/
serviceAccountProviderId: 'google-service-account',

@cubic-dev-ai cubic-dev-ai Bot Nov 12, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

P2: This shared provider alias also makes existing keyless Google credentials eligible for Google Ads credential selection, but the token resolver explicitly rejects google-ads for keyless credentials. Filter keyless credentials out for this service (or add service-aware eligibility) so users cannot select a credential that every Ads run will reject.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/lib/oauth/oauth.ts, line 503:

<comment>This shared provider alias also makes existing keyless Google credentials eligible for Google Ads credential selection, but the token resolver explicitly rejects `google-ads` for keyless credentials. Filter keyless credentials out for this service (or add service-aware eligibility) so users cannot select a credential that every Ads run will reject.</comment>

<file context>
@@ -494,6 +494,13 @@ export const OAUTH_PROVIDERS: Record<string, OAuthProviderConfig> = {
+         * Google credentials stay refused here: Ads is not in `GOOGLE_KEYLESS_SERVICES`, since
+         * Google documents no Workload Identity Federation path for it.
+         */
+        serviceAccountProviderId: 'google-service-account',
       },
       'google-bigquery': {
</file context>
Fix with cubic

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

This branch was successfully deployed

1 active deployment
Preview — e3e72421 Deployed Nov 12, 2026 by vercel[bot]
View deployment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@greptile-apps greptile-apps[bot] greptile-apps[bot] left review comments
@cubic-dev-ai cubic-dev-ai[bot] cubic-dev-ai[bot] left review comments

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

1 participant

@waleedlatif1
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.