Skip to content

Commit 4c0f666

Browse files
committed
feat(credential): restrict to OAuth only, remove env vars and service accounts
1 parent acec880 commit 4c0f666

7 files changed

Lines changed: 49 additions & 145 deletions

File tree

apps/docs/content/docs/en/blocks/credential.mdx

Lines changed: 21 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Tab, Tabs } from 'fumadocs-ui/components/tabs'
77
import { Image } from '@/components/ui/image'
88
import { FAQ } from '@/components/ui/faq'
99

10-
The Credential block has two operations: **Select Credential** picks a single stored credential and outputs its ID reference for downstream blocks; **List Credentials** returns all credentials in the workspace (optionally filtered by type) as an array for iteration.
10+
The Credential block has two operations: **Select Credential** picks a single OAuth credential and outputs its ID reference for downstream blocks; **List Credentials** returns all OAuth credentials in the workspace (optionally filtered by provider) as an array for iteration.
1111

1212
<div className="flex justify-center">
1313
<Image
@@ -20,7 +20,7 @@ The Credential block has two operations: **Select Credential** picks a single st
2020
</div>
2121

2222
<Callout>
23-
The Credential block outputs credential **ID references**, not secrets. Downstream blocks receive the ID and resolve it securely during their own execution.
23+
The Credential block outputs credential **ID references**, not secrets. Downstream blocks receive the ID and resolve the actual OAuth token securely during their own execution.
2424
</Callout>
2525

2626
## Configuration Options
@@ -29,34 +29,18 @@ The Credential block has two operations: **Select Credential** picks a single st
2929

3030
| Value | Description |
3131
|---|---|
32-
| **Select Credential** | Pick one credential and output its reference — use this to wire a single credential into downstream blocks |
33-
| **List Credentials** | Return all workspace credentials as an array — use this with a ForEach loop |
32+
| **Select Credential** | Pick one OAuth credential and output its reference — use this to wire a single credential into downstream blocks |
33+
| **List Credentials** | Return all OAuth credentials in the workspace as an array — use this with a ForEach loop |
3434

3535
### Credential (Select operation)
3636

37-
Select a credential from your workspace. The dropdown shows all credential types you have access to, grouped by category:
38-
39-
- **OAuth** — Connected accounts (Google, GitHub, Slack, etc.)
40-
- **Environment Variables** — Workspace or personal environment variable references
41-
- **Service Accounts** — Google service account JSON keys
37+
Select an OAuth credential from your workspace. The dropdown shows all connected OAuth accounts (Google, GitHub, Slack, etc.).
4238

4339
In advanced mode, paste a credential ID directly. You can copy a credential ID from your workspace's Credentials settings page.
4440

45-
### Type Filter (List operation)
46-
47-
Filter the returned credentials by type. Defaults to **All**.
41+
### Provider (List operation)
4842

49-
| Value | Description |
50-
|---|---|
51-
| **All** | Return all credential types |
52-
| **OAuth** | Connected OAuth accounts only |
53-
| **Env Variables (Workspace)** | Workspace environment variables only |
54-
| **Env Variables (Personal)** | Personal environment variables only |
55-
| **Service Accounts** | Google service account keys only |
56-
57-
### Provider (List operation, OAuth only)
58-
59-
Further filter OAuth credentials by provider. Select one or more providers from the dropdown — only providers you have credentials for will appear. Leave empty to return all OAuth providers.
43+
Filter the returned OAuth credentials by provider. Select one or more providers from the dropdown — only providers you have credentials for will appear. Leave empty to return all OAuth credentials.
6044

6145
| Example | Returns |
6246
|---|---|
@@ -72,13 +56,12 @@ Further filter OAuth credentials by provider. Select one or more providers from
7256
|---|---|---|
7357
| `credentialId` | `string` | The credential ID — pipe this into other blocks' credential fields |
7458
| `displayName` | `string` | Human-readable name (e.g. "waleed@company.com") |
75-
| `type` | `string` | `oauth` \| `env_workspace` \| `env_personal` \| `service_account` |
76-
| `providerId` | `string` | OAuth provider (e.g. `google`, `github`), empty for non-OAuth types |
59+
| `providerId` | `string` | OAuth provider ID (e.g. `google-email`, `slack`) |
7760
</Tab>
7861
<Tab>
7962
| Output | Type | Description |
8063
|---|---|---|
81-
| `credentials` | `json` | Array of credential objects (see shape below) |
64+
| `credentials` | `json` | Array of OAuth credential objects (see shape below) |
8265
| `count` | `number` | Number of credentials returned |
8366

8467
Each object in the `credentials` array:
@@ -87,8 +70,7 @@ Further filter OAuth credentials by provider. Select one or more providers from
8770
|---|---|---|
8871
| `credentialId` | `string` | The credential ID |
8972
| `displayName` | `string` | Human-readable name |
90-
| `type` | `string` | Credential type |
91-
| `providerId` | `string` | OAuth provider ID, empty for non-OAuth |
73+
| `providerId` | `string` | OAuth provider ID |
9274
</Tab>
9375
</Tabs>
9476

@@ -99,20 +81,14 @@ Further filter OAuth credentials by provider. Select one or more providers from
9981
Credential (Select, Google) → Gmail (Send) & Google Drive (Upload) & Google Calendar (Create)
10082
```
10183

102-
**Environment switching** — Swap credentials without touching downstream blocks
103-
```
104-
Condition (env === 'prod') → Credential (Prod API Key) or Credential (Dev API Key)
105-
→ API Block (credentialId = <credential.credentialId>)
106-
```
107-
10884
**Multi-account workflows** — Route to different credentials based on logic
10985
```
11086
Agent (Determine account) → Condition → Credential A or Credential B → Slack (Post)
11187
```
11288

11389
**Iterate over all Gmail accounts**
11490
```
115-
Credential (List, OAuth, Provider: Gmail) → ForEach Loop → Gmail (Send) using <loop.currentItem.credentialId>
91+
Credential (List, Provider: Gmail) → ForEach Loop → Gmail (Send) using <loop.currentItem.credentialId>
11692
```
11793

11894
<div className="flex justify-center">
@@ -129,24 +105,17 @@ Credential (List, OAuth, Provider: Gmail) → ForEach Loop → Gmail (Send) usin
129105

130106
### Select Credential
131107

132-
1. Drop a **Credential** block and select your credential from the picker
108+
1. Drop a **Credential** block and select your OAuth credential from the picker
133109
2. In the downstream block, switch to **advanced mode** on its credential field
134110
3. Enter `<credentialBlockName.credentialId>` as the value
135111

136-
<Tabs items={['Gmail', 'API Block', 'Slack']}>
112+
<Tabs items={['Gmail', 'Slack']}>
137113
<Tab>
138114
In the Gmail block's credential field (advanced mode):
139115
```
140116
<myCredential.credentialId>
141117
```
142118
</Tab>
143-
<Tab>
144-
In an API block's Authorization header:
145-
```
146-
Bearer <myCredential.credentialId>
147-
```
148-
Note: for API blocks, this passes the credential ID — use this pattern only when the downstream API route resolves credentials internally.
149-
</Tab>
150119
<Tab>
151120
In the Slack block's credential field (advanced mode):
152121
```
@@ -158,25 +127,24 @@ Credential (List, OAuth, Provider: Gmail) → ForEach Loop → Gmail (Send) usin
158127
### List Credentials
159128

160129
1. Drop a **Credential** block, set Operation to **List Credentials**
161-
2. Optionally set a **Type Filter** (e.g. OAuth only)
162-
3. Optionally select one or more **Providers** to narrow results (only your connected providers appear)
163-
4. Wire `<credentialBlockName.credentials>` into a **ForEach Loop** as the items source
164-
5. Inside the loop, reference `<loop.currentItem.credentialId>` in downstream blocks' credential fields
130+
2. Optionally select one or more **Providers** to narrow results (only your connected providers appear)
131+
3. Wire `<credentialBlockName.credentials>` into a **ForEach Loop** as the items source
132+
4. Inside the loop, reference `<loop.currentItem.credentialId>` in downstream blocks' credential fields
165133

166134
## Best Practices
167135

168136
- **Define once, reference many times**: When five blocks use the same Google account, use one Credential block and wire all five to `<credential.credentialId>` instead of selecting the account five times
169137
- **Outputs are safe to log**: The `credentialId` output is a UUID reference, not a secret. It is safe to inspect in execution logs
170-
- **Use for environment switching**: Pair with a Condition block to route to a production or staging credential based on a workflow variable
138+
- **Use for environment switching**: Pair with a Condition block to route to a production or staging OAuth credential based on a workflow variable
171139
- **Advanced mode is required**: Downstream blocks must be in advanced mode on their credential field to accept a dynamic reference
172-
- **Use List + ForEach for fan-out**: When you need to run the same action across all accounts of a type, List Credentials feeds naturally into a ForEach loop
140+
- **Use List + ForEach for fan-out**: When you need to run the same action across all accounts of a provider, List Credentials feeds naturally into a ForEach loop
173141
- **Narrow by provider**: Use the Provider multiselect to filter to specific services — only providers you have credentials for are shown
174142

175143
<FAQ items={[
176-
{ question: "Does the Credential block expose my secret or token?", answer: "No. The block outputs a credential ID (a UUID), not the actual secret or token. Downstream blocks receive the ID and resolve it securely in their own execution context. Secrets never appear in workflow state, logs, or the canvas." },
177-
{ question: "What credential types does it support?", answer: "All credential types: OAuth connected accounts, workspace environment variables, personal environment variables, and Google service accounts." },
144+
{ question: "Does the Credential block expose my secret or token?", answer: "No. The block outputs a credential ID (a UUID), not the actual OAuth token. Downstream blocks receive the ID and resolve the token securely in their own execution context. Secrets never appear in workflow state, logs, or the canvas." },
145+
{ question: "What credential types does it support?", answer: "OAuth connected accounts only (Google, GitHub, Slack, etc.). Environment variables and service accounts cannot be resolved by ID in downstream blocks, so they are not supported." },
178146
{ question: "How is Select different from just copying a credential ID into advanced mode?", answer: "Functionally identical — both pass the same credential ID to the downstream block. The Credential block adds value when you need to use one credential in many blocks (change it once), or when you want to select between credentials dynamically using a Condition block." },
179-
{ question: "Can I list all credentials in my workspace?", answer: "Yes. Set the Operation to 'List Credentials'. You can optionally filter by type (OAuth, environment variables, service accounts). Wire the credentials output into a ForEach loop to process each credential individually." },
147+
{ question: "Can I list all OAuth credentials in my workspace?", answer: "Yes. Set the Operation to 'List Credentials'. Optionally filter by provider using the Provider multiselect. Wire the credentials output into a ForEach loop to process each credential individually." },
180148
{ question: "Can I use a Credential block output in a Function block?", answer: "Yes. Reference <credential.credentialId> in your Function block's code. Note that the function will receive the raw UUID string — if you need the resolved token, the downstream block must handle the resolution (as integration blocks do). The Function block does not automatically resolve credential IDs." },
181149
{ question: "What happens if the credential is deleted?", answer: "The Select operation will throw an error at execution time: 'Credential not found'. The List operation will simply omit the deleted credential from the results. Update the Credential block to select a valid credential before re-running." },
182150
]} />

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/credential-selector/credential-selector.tsx

Lines changed: 4 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,7 @@ import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/c
2222
import type { SubBlockConfig } from '@/blocks/types'
2323
import { CREDENTIAL_SET } from '@/executor/constants'
2424
import { useCredentialSets } from '@/hooks/queries/credential-sets'
25-
import {
26-
useWorkspaceCredential,
27-
useWorkspaceCredentials,
28-
type WorkspaceCredential,
29-
} from '@/hooks/queries/credentials'
25+
import { useWorkspaceCredential, useWorkspaceCredentials } from '@/hooks/queries/credentials'
3026
import { useOAuthCredentials } from '@/hooks/queries/oauth/oauth-credentials'
3127
import { useOrganizations } from '@/hooks/queries/organization'
3228
import { useSubscriptionData } from '@/hooks/queries/subscription'
@@ -35,13 +31,6 @@ import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
3531

3632
const isBillingEnabled = isTruthy(getEnv('NEXT_PUBLIC_BILLING_ENABLED'))
3733

38-
const TYPE_SECTION_LABELS: Record<string, string> = {
39-
oauth: 'OAuth',
40-
env_workspace: 'Environment Variables',
41-
env_personal: 'Personal Variables',
42-
service_account: 'Service Accounts',
43-
} as const
44-
4534
interface CredentialSelectorProps {
4635
blockId: string
4736
subBlock: SubBlockConfig
@@ -255,22 +244,9 @@ export function CredentialSelector({
255244

256245
const { comboboxOptions, comboboxGroups } = useMemo(() => {
257246
if (isAllCredentials) {
258-
const grouped = allWorkspaceCredentials.reduce<Record<string, WorkspaceCredential[]>>(
259-
(acc, cred) => {
260-
const section = TYPE_SECTION_LABELS[cred.type] ?? cred.type
261-
acc[section] = acc[section] ?? []
262-
acc[section].push(cred)
263-
return acc
264-
},
265-
{}
266-
)
267-
268-
const groups = Object.entries(grouped).map(([section, creds]) => ({
269-
section,
270-
items: creds.map((cred) => ({ label: cred.displayName, value: cred.id })),
271-
}))
272-
273-
return { comboboxOptions: [], comboboxGroups: groups.length > 0 ? groups : undefined }
247+
const oauthCredentials = allWorkspaceCredentials.filter((c) => c.type === 'oauth')
248+
const options = oauthCredentials.map((cred) => ({ label: cred.displayName, value: cred.id }))
249+
return { comboboxOptions: options, comboboxGroups: undefined }
274250
}
275251

276252
const pollingProviderId = getPollingProviderFromOAuth(effectiveProviderId)

apps/sim/blocks/blocks/credential.ts

Lines changed: 10 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@ interface CredentialBlockOutput {
1010
output: {
1111
credentialId: string
1212
displayName: string
13-
type: string
1413
providerId: string
1514
credentials: Array<{
1615
credentialId: string
1716
displayName: string
18-
type: string
1917
providerId: string
2018
}>
2119
count: number
@@ -25,14 +23,13 @@ interface CredentialBlockOutput {
2523
export const CredentialBlock: BlockConfig<CredentialBlockOutput> = {
2624
type: 'credential',
2725
name: 'Credential',
28-
description: 'Select or list stored credentials',
26+
description: 'Select or list OAuth credentials',
2927
longDescription:
30-
'Select a stored credential once and pipe its ID into any downstream block that requires authentication, or list all credentials in the workspace for iteration. No secrets are ever exposed — only credential IDs and metadata.',
28+
'Select an OAuth credential once and pipe its ID into any downstream block that requires authentication, or list all OAuth credentials in the workspace for iteration. No secrets are ever exposed — only credential IDs and metadata.',
3129
bestPractices: `
32-
- Use "Select Credential" to define a credential once and reference <CredentialBlock.credentialId> in multiple downstream blocks instead of repeating credential IDs.
33-
- Use "List Credentials" with a ForEach loop to iterate over all credentials of a given type (e.g. all OAuth accounts).
34-
- Use the Type Filter in "List Credentials" to narrow results to a specific credential type.
35-
- Use the Provider filter to further narrow OAuth results to specific services (e.g. Gmail, Slack).
30+
- Use "Select Credential" to define an OAuth credential once and reference <CredentialBlock.credentialId> in multiple downstream blocks instead of repeating credential IDs.
31+
- Use "List Credentials" with a ForEach loop to iterate over all OAuth accounts (e.g. all Gmail accounts).
32+
- Use the Provider filter to narrow results to specific services (e.g. Gmail, Slack).
3633
- The outputs are credential ID references, not secret values — they are safe to log and inspect.
3734
- To switch credentials across environments, replace the single Credential block rather than updating every downstream block.
3835
`,
@@ -51,26 +48,13 @@ export const CredentialBlock: BlockConfig<CredentialBlockOutput> = {
5148
],
5249
value: () => 'select',
5350
},
54-
{
55-
id: 'typeFilter',
56-
title: 'Type Filter',
57-
type: 'dropdown',
58-
options: [
59-
{ label: 'All', id: 'all' },
60-
{ label: 'OAuth', id: 'oauth' },
61-
{ label: 'Env Variables (Workspace)', id: 'env_workspace' },
62-
{ label: 'Env Variables (Personal)', id: 'env_personal' },
63-
{ label: 'Service Accounts', id: 'service_account' },
64-
],
65-
value: () => 'all',
66-
condition: { field: 'operation', value: 'list' },
67-
},
6851
{
6952
id: 'providerFilter',
7053
title: 'Provider',
7154
type: 'dropdown',
7255
multiSelect: true,
7356
options: [],
57+
condition: { field: 'operation', value: 'list' },
7458
fetchOptions: async () => {
7559
const workspaceId = useWorkflowRegistry.getState().hydration.workspaceId
7660
if (!workspaceId) return []
@@ -99,11 +83,6 @@ export const CredentialBlock: BlockConfig<CredentialBlockOutput> = {
9983
const label = serviceConfig?.name ?? optionId
10084
return { label, id: optionId }
10185
},
102-
condition: {
103-
field: 'operation',
104-
value: 'list',
105-
and: { field: 'typeFilter', value: 'oauth' },
106-
},
10786
},
10887
{
10988
id: 'credential',
@@ -133,17 +112,12 @@ export const CredentialBlock: BlockConfig<CredentialBlockOutput> = {
133112
operation: { type: 'string', description: "'select' or 'list'" },
134113
credentialId: {
135114
type: 'string',
136-
description: 'The credential ID to resolve (select operation)',
137-
},
138-
typeFilter: {
139-
type: 'string',
140-
description:
141-
"Type filter for list operation: 'all' | 'oauth' | 'env_workspace' | 'env_personal' | 'service_account'",
115+
description: 'The OAuth credential ID to resolve (select operation)',
142116
},
143117
providerFilter: {
144118
type: 'json',
145119
description:
146-
'Array of OAuth provider IDs to filter by (e.g. ["google-email", "slack"]). Only applies when typeFilter is oauth.',
120+
'Array of OAuth provider IDs to filter by (e.g. ["google-email", "slack"]). Leave empty to return all OAuth credentials.',
147121
},
148122
},
149123
outputs: {
@@ -157,20 +131,15 @@ export const CredentialBlock: BlockConfig<CredentialBlockOutput> = {
157131
description: 'Human-readable name of the credential',
158132
condition: { field: 'operation', value: 'select' },
159133
},
160-
type: {
161-
type: 'string',
162-
description: 'Credential type: oauth | env_workspace | env_personal | service_account',
163-
condition: { field: 'operation', value: 'select' },
164-
},
165134
providerId: {
166135
type: 'string',
167-
description: 'OAuth provider ID (e.g. google, github), empty for non-OAuth credentials',
136+
description: 'OAuth provider ID (e.g. google-email, slack)',
168137
condition: { field: 'operation', value: 'select' },
169138
},
170139
credentials: {
171140
type: 'json',
172141
description:
173-
'Array of credential objects, each with credentialId, displayName, type, and providerId',
142+
'Array of OAuth credential objects, each with credentialId, displayName, and providerId',
174143
condition: { field: 'operation', value: 'list' },
175144
},
176145
count: {

0 commit comments

Comments
 (0)