Skip to content

Commit 21e32d7

Browse files
authored
feat(credentials): second auth modes for ServiceNow, Snowflake, Infisical, and Google Ads (#9928)
* feat(google-ads): accept a Google service account JSON key 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. * feat(infisical): log machine identities in with Universal Auth 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. * feat(servicenow): connect with an OAuth client's client credentials 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. * feat(snowflake): connect with an RSA key pair 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. * refactor(servicenow): keep the Basic header builder private to its utils serviceNowAuthorization is now the only caller, so the export was unused. * fix(snowflake): name an underscore account the same from either of its 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. * refactor(credentials): share the token response reader with the Infisical 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. * refactor(servicenow): tighten the saved-credential params and auth types 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. * fix(snowflake): list the key-pair connection in the credential provider catalog * refactor(servicenow): mark the username with requiredForAuthMethods so the catalog scopes it to the password sign-in * fix(snowflake): verify key pairs through the egress guard and leave an 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. * fix(snowflake): mask the key-pair private key when unfocused and type the key-pair header test The key-pair private key textarea hides its value off focus, matching the Google JSON key field, and the new getSnowflakeHeaders case passes the oauthCredential its params type requires. * fix(snowflake): accept underscore account hosts in the connect form and state the key-size ceiling * fix(credentials): expire a coordinated token an internal operation's provider refuses
1 parent e5af324 commit 21e32d7

57 files changed

Lines changed: 2000 additions & 239 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎apps/docs/content/docs/integrations/google-service-account.mdx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ Leave **Impersonated Account** blank to authenticate as the service account itse
173173

174174
Domain-wide delegation requires a Google Workspace super administrator. It authorizes impersonation within that Workspace domain, subject to the authorized scopes and the impersonated user’s access. Consumer Gmail accounts and users outside that domain cannot be impersonated. Access also depends on the license required by the target service. See [Google’s service-account authorization guide](https://developers.google.com/identity/protocols/oauth2/service-account).
175175

176+
**Google Ads** never uses domain-wide delegation: add the service account's email as a user in the Google Ads account (**Admin > Access and security**); it signs in as itself. Enable the Google Ads API in the project that owns the service account; that project's Google Ads API access level applies. See [Google Ads](/integrations/google_ads).
177+
176178
A credential can serve multiple supported Google services when their APIs and scopes are configured. To rotate its key, create a replacement JSON key, update the credential in Sim, verify access, then delete the old key in Google Cloud.
177179

178180
## Keyless Google Cloud access [#keyless-google-cloud-access]

‎apps/docs/content/docs/integrations/google_ads.mdx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Use [Google Ads](https://ads.google.com) in Sim to list accessible accounts and
1414

1515
Connect your Google account and select a reporting operation. Google requires the `adwords` OAuth scope even for read-only reports; Sim's Google Ads operations do not create or modify ads, budgets, or billing.
1616

17+
To run without a person's Google sign-in, select a [Google service account](/integrations/google-service-account) JSON key instead. In Google Ads, open **Admin > Access and security** and add the service account's email as a user of each account it reads, or of the manager account above them; Google allows up to 20 accounts per email, and service accounts can't use Email only access. The service account signs in as itself, so leave domain-wide delegation off. API access then belongs to the Google Cloud project that owns the service account. Keyless (Workload Identity Federation) Google credentials can't be used with Google Ads. See [Google's service account guide](https://developers.google.com/google-ads/api/docs/oauth/service-accounts).
18+
1719
Google Ads API access belongs to the Google Cloud project that owns the OAuth client. Self-hosted deployments must enable the Google Ads API and configure the project's access level in the [Google Ads API overview](https://console.cloud.google.com/google/ads-apis/overview). Test access works only with Google Ads test accounts; production accounts require an appropriate production access level. [Developer tokens were retired on September 9, 2026](https://developers.google.com/google-ads/api/docs/api-policy/developer-token) and are no longer needed.
1820

1921
Use the client account's Customer ID for reports. If your Google user accesses that account through a manager, set Manager Customer ID in the additional fields. List Customers returns accounts directly accessible to the signed-in user, which may include the manager rather than its client accounts. Test accounts do not serve ads and cannot demonstrate real impressions, clicks, or spend.

‎apps/docs/content/docs/integrations/infisical.mdx‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@ import { ReferenceDetails } from "@/components/ui/reference-details"
1010

1111

1212
{/* MANUAL-CONTENT-START:intro */}
13-
Use [Infisical](https://infisical.com/) to list, read, create, update, or delete secrets in a project environment. Connect a saved Infisical credential (a machine identity access token), then set the project ID, environment slug, and any secret path required by the selected operation.
13+
Use [Infisical](https://infisical.com/) to list, read, create, update, or delete secrets in a project environment. Connect a saved Infisical credential (a machine identity's Universal Auth client ID and secret, or its access token), then set the project ID, environment slug, and any secret path required by the selected operation.
1414

15-
Sim stores the access token as pasted and does not renew it, so the credential stops working when the token's Access Token TTL runs out. On the identity's Universal Auth or Token Auth configuration, set a long Access Token TTL and Access Token Max TTL, and leave Access Token Period unset: a periodic token expires at the end of each period unless it is renewed. Replace the credential with a new token before the old one expires. See Infisical's [Universal Auth](https://infisical.com/docs/documentation/platform/identities/universal-auth) and [Token Auth](https://infisical.com/docs/documentation/platform/identities/token-auth) guides.
15+
The recommended setup is **Universal Auth (client ID and secret)**: in Infisical, add Universal Auth to the machine identity and create a Client Secret; in Sim, add the Infisical credential, choose that authentication, and enter the Client ID, Client Secret, and instance URL (`https://us.infisical.com` for US Cloud, `https://eu.infisical.com` for EU Cloud, or your self-hosted URL). Sim logs in with them whenever its access token expires, so the credential keeps working without a renewed token. Each login spends one use of the Client Secret, so leave its usage limit at `0` (unlimited) and leave Access Token Max Number of Uses at `0`; if the identity restricts trusted IPs, allow Sim's outbound addresses. See Infisical's [Universal Auth guide](https://infisical.com/docs/documentation/platform/identities/universal-auth).
16+
17+
You can instead paste a machine identity **access token**. Sim stores it as pasted and does not renew it, so the credential stops working when the token's Access Token TTL runs out. On the identity's Universal Auth or Token Auth configuration, set a long Access Token TTL and Access Token Max TTL, and leave Access Token Period unset: a periodic token expires at the end of each period unless it is renewed. Replace the credential with a new token before the old one expires. See Infisical's [Token Auth](https://infisical.com/docs/documentation/platform/identities/token-auth) guide.
1618
{/* MANUAL-CONTENT-END */}
1719

1820
## Use the block [#usage-instructions]

‎apps/docs/content/docs/integrations/servicenow.mdx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import { ReferenceDetails } from "@/components/ui/reference-details"
1313
Use [ServiceNow](https://www.servicenow.com/) in Sim to create or update incidents and change requests, order catalog items, and process approvals. Read configuration items, knowledge articles, users, and groups, and transfer attachments. Generic record and aggregate operations accept a table name, such as incident, task, change_request, or sys_user, and the fields required by the operation. List Attachments and Upload Attachment also require a table name.
1414

1515
Connect ServiceNow once as a ServiceNow credential: enter the instance URL plus the username and password of a dedicated integration user that has the roles your workflows need and does not use multi-factor authentication. Enter the instance's https URL, such as `acme.service-now.com` or a custom instance URL; the instance must be reachable from the internet. Workflows built with the earlier ServiceNow block keep the instance URL, username, and password they entered in the block.
16+
17+
To connect without a password, set **Authentication** to **OAuth client credentials** and enter the instance URL with the client ID and secret of an inbound OAuth client. A ServiceNow admin first creates the system property `glide.oauth.inbound.client.credential.grant_type.enabled` (true/false) in the global scope and sets it to `true`, then creates the OAuth client (on Zurich and later, in **Machine Identity Console > Inbound integrations > New integration > OAuth - Client credentials grant**) with an **OAuth Application User** that has the roles your workflows need. Sim requests a token from the instance's `/oauth_token.do` whenever the current one expires, and every request acts as the OAuth Application User. See ServiceNow's [client credentials](https://www.servicenow.com/docs/r/xanadu/platform-security/authentication/client-credentials.html) documentation.
1618
{/* MANUAL-CONTENT-END */}
1719

1820
## Use the block [#usage-instructions]

‎apps/docs/content/docs/integrations/snowflake-service-account.mdx‎

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Snowflake connections
3-
description: Connect Snowflake to Sim with a keyless service user that trusts Sim through OpenID Connect, or with a programmatic access token
3+
description: Connect Snowflake to Sim with a keyless service user that trusts Sim through OpenID Connect, a key pair, or a programmatic access token
44
---
55

66
import { Callout } from '@/components/ui/callout'
@@ -11,6 +11,7 @@ A Snowflake connection holds your account host and how Sim signs in to it:
1111
| Option | What Sim stores | When to use it |
1212
| --- | --- | --- |
1313
| **Service user (keyless, via Sim OIDC)** | Nothing secret: the account host only | Recommended where available. No token to rotate, expire, or leak. |
14+
| **Key pair (RSA private key)** | The user's private key | Any account, including organization connections and deployments without keyless support. Nothing expires, and the key works only for the user holding its public key. |
1415
| **Programmatic access token** | A programmatic access token (PAT) | Any account, and deployments without keyless support. The token belongs to one user; use `ROLE_RESTRICTION` to limit it to a role with the access your workflows need. |
1516

1617
Sim stores the connection as one credential. Once it is added, every Snowflake block picks it from a dropdown — and the block's database, schema, table, warehouse, role, file-format, and procedure fields become pickers that list what the token can actually see.
@@ -123,6 +124,27 @@ If an authentication policy applies to the user, `'PROGRAMMATIC_ACCESS_TOKEN'` m
123124

124125
The host and the token are encrypted before being stored, and the token is never returned to the browser — the block sends a credential id and Sim resolves it server-side. Keyless tokens are signed on Sim's servers at run time and never stored.
125126

127+
## Use a key pair [#key-pair]
128+
129+
Snowflake [key-pair authentication](https://docs.snowflake.com/en/user-guide/key-pair-auth) lets a user sign in with an RSA key instead of a password or token. Sim stores the private key encrypted and, on every run, signs a JWT with it that Snowflake accepts for up to an hour, sent with the `KEYPAIR_JWT` token type of the [SQL API](https://docs.snowflake.com/en/developer-guide/sql-api/authenticating).
130+
131+
<Steps>
132+
<Step>
133+
Generate an unencrypted 2048-bit key: `openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt`, then its public key: `openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub`
134+
</Step>
135+
<Step>
136+
Assign the public key to the user (without the PEM delimiter lines): `ALTER USER SIM_WORKFLOWS SET RSA_PUBLIC_KEY = 'MIIBIjANBgkqh...';`. Grant the user a role and set it as its default role.
137+
</Step>
138+
<Step>
139+
In Sim, add a Snowflake connection, choose **Key pair (RSA private key)**, and enter the **account host**, the **user**, and the contents of `rsa_key.p8`
140+
</Step>
141+
<Step>
142+
Save. Sim signs a JWT and runs the same verification statement as for a token, so a wrong user, key, or host is reported before anything is saved.
143+
</Step>
144+
</Steps>
145+
146+
The JWT names the account from the host (its first label, such as `MYORG-MYACCOUNT` or the locator `XY12345` without region) and the user in uppercase. An account name with underscores works from either of its hostnames: `myorg-my_account` and `myorg-my-account` both sign in as `MYORG-MY_ACCOUNT`. To rotate, assign the new public key as `RSA_PUBLIC_KEY_2`, select **Reconnect** in Sim with the new private key, then unset the old public key.
147+
126148
## Use the credential in workflows [#using-the-credential-in-workflows]
127149

128150
Select the credential on any Snowflake block. You never enter the host again: every tool derives its endpoint from the host stored on the credential.
@@ -154,10 +176,12 @@ A token's expiry is fixed at creation. To rotate, generate a new token on the sa
154176
| Keyless: "Snowflake did not accept Sim's token" | No user in this account was created with exactly the issuer and subject from the dialog, the user is not `TYPE = SERVICE`, or a network or authentication policy blocks it. Run `SHOW USER WORKLOAD IDENTITY AUTHENTICATION METHODS FOR USER SIM_WORKFLOWS` to compare. |
155177
| Keyless: error 099706 when creating the user | Another user in the account already has this issuer and subject. Find it with `SHOW USER WORKLOAD IDENTITY AUTHENTICATION METHODS` and remove it, or reconnect with a new subject. |
156178
| Keyless: runs fail for up to an hour after a signing-key rotation | Snowflake had not yet seen the new key. Publish a new key at least 60 minutes before signing with it (see [Self-hosted deployments](#self-hosted-deployments)). |
157-
| Keyless option missing | The deployment has no workload-identity signing key, or the connection belongs to an organization rather than a workspace. Use a programmatic access token. |
179+
| Keyless option missing | The deployment has no workload-identity signing key, or the connection belongs to an organization rather than a workspace. Use a key pair or a programmatic access token. |
180+
| Key pair: "Snowflake did not accept a token signed with this key" | The user's `RSA_PUBLIC_KEY` (or `RSA_PUBLIC_KEY_2`) is not this key's public key, the user name is wrong, or a network or authentication policy blocks it. Compare `DESC USER SIM_WORKFLOWS` (`RSA_PUBLIC_KEY_FP`) with the key's fingerprint. |
181+
| Key pair: the private key is refused | Sim needs an unencrypted PEM RSA private key of 2048 to 4096 bits. Convert an encrypted key with `openssl pkcs8 -in rsa_key.p8 -nocrypt -out rsa_key_unencrypted.p8`. |
158182
| Lost token secret | Snowflake shows it only at creation. Generate a replacement and reconnect the credential in Sim. |
159183
| Authentication fails | Check expiry or revocation, the user's network policy and Sim's egress, permitted authentication methods, role restriction, and SQL API access. |
160-
| Wrong host | Use the account's Snowflake hostname. Sim reports a host error separately when the verification endpoint returns `404`. |
184+
| Wrong host | Use the account's Snowflake hostname (`.snowflakecomputing.com`, or `.snowflakecomputing.cn` for accounts in China). Sim reports a host error separately when the verification endpoint returns `404`. |
161185
| Empty picker | Check privileges under the token's effective role. The block's execution role is not applied to metadata pickers; use advanced mode to enter a name when appropriate. |
162186
| A second account is needed | Add another credential. Each token and stored host target one Snowflake account. |
163187
| Token limit reached | Snowflake allows 15 unexpired PATs per user, including disabled tokens. Remove an unused token before creating another. |

0 commit comments

Comments
 (0)