@tadnt2003/n8n-nodes-infisical 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # n8n-nodes-infisical
1
+ # @tadnt2003/n8n-nodes-infisical
2
2
 
3
3
  An n8n community node for integrating [Infisical](https://infisical.com/) — the open-source secrets management platform — into your n8n workflows.
4
4
 
@@ -20,7 +20,7 @@ An n8n community node for integrating [Infisical](https://infisical.com/) — th
20
20
 
21
21
  Follow the [community nodes installation guide](https://docs.n8n.io/integrations/community-nodes/installation/) in the n8n documentation.
22
22
 
23
- Package name: `n8n-nodes-infisical`
23
+ Package name: `@tadnt2003/n8n-nodes-infisical`
24
24
 
25
25
  ---
26
26
 
@@ -41,12 +41,13 @@ Universal Auth uses a Machine Identity's Client ID and Client Secret to obtain a
41
41
 
42
42
  **Credential fields:**
43
43
 
44
- | Field | Description |
45
- | --- | --- |
46
- | API URL | Base URL of your Infisical API (default: `https://app.infisical.com/api`) |
47
- | Authentication Type | Select **Universal Auth (Machine Identity)** |
48
- | Client ID | The Machine Identity's Client ID |
49
- | Client Secret | The Machine Identity's Client Secret |
44
+ | Field | Required | Description |
45
+ | --- | --- | --- |
46
+ | API URL | Yes | Base URL of your Infisical API (default: `https://app.infisical.com/api`) |
47
+ | Authentication Type | Yes | Select **Universal Auth (Machine Identity)** |
48
+ | Client ID | Yes | The Machine Identity's Client ID |
49
+ | Client Secret | Yes | The Machine Identity's Client Secret |
50
+ | Organization Slug | No | Scope the access token to a specific organization. Leave blank to use the organization the machine identity belongs to. To restrict access to a specific project, assign the identity to that project in Organization Settings → Machine Identities → your identity → Project Access. |
50
51
 
51
52
  ### Service Token (Legacy)
52
53
 
@@ -59,11 +60,11 @@ Service Tokens are deprecated by Infisical and may be removed in future versions
59
60
 
60
61
  **Credential fields:**
61
62
 
62
- | Field | Description |
63
- | --- | --- |
64
- | API URL | Base URL of your Infisical API (default: `https://app.infisical.com/api`) |
65
- | Authentication Type | Select **Service Token (Legacy)** |
66
- | Service Token | Your Infisical Service Token |
63
+ | Field | Required | Description |
64
+ | --- | --- | --- |
65
+ | API URL | Yes | Base URL of your Infisical API (default: `https://app.infisical.com/api`) |
66
+ | Authentication Type | Yes | Select **Service Token (Legacy)** |
67
+ | Service Token | Yes | Your Infisical Service Token |
67
68
 
68
69
  > For self-hosted Infisical, set API URL to your instance (e.g., `https://infisical.example.com/api`).
69
70
 
@@ -75,15 +76,15 @@ Service Tokens are deprecated by Infisical and may be removed in future versions
75
76
 
76
77
  All Secret operations require: **Project ID**, **Environment**, **Secret Path** (default: `/`).
77
78
 
78
- | Operation | Description | API |
79
- | --- | --- | --- |
80
- | **Get** | Fetch a single secret by key | `GET /v3/secrets/raw/{key}` |
81
- | **Get Many** | List all secrets in a path | `GET /v3/secrets/raw` |
82
- | **Create** | Create a single secret | `POST /v3/secrets/raw/{key}` |
83
- | **Create Many** | Create multiple secrets in one request | `POST /v4/secrets/batch` |
84
- | **Update** | Update a single secret | `PATCH /v4/secrets/{key}` |
85
- | **Update Many** | Update multiple secrets in one request | `PATCH /v4/secrets/batch` |
86
- | **Delete** | Delete a single secret by key | `DELETE /v3/secrets/raw/{key}` |
79
+ | Operation | Description | Method | API endpoint |
80
+ | --- | --- | --- | --- |
81
+ | **Get** | Fetch a single secret by key | `GET` | `/v4/secrets/{key}` |
82
+ | **Get Many** | List all secrets in a path | `GET` | `/v4/secrets` |
83
+ | **Create** | Create a single secret | `POST` | `/v4/secrets/{key}` |
84
+ | **Create Many** | Create multiple secrets in one request | `POST` | `/v3/secrets/batch/raw` |
85
+ | **Update** | Update a single secret | `PATCH` | `/v4/secrets/{key}` |
86
+ | **Update Many** | Update multiple secrets in one request | `PATCH` | `/v3/secrets/batch/raw` |
87
+ | **Delete** | Delete a single secret by key | `DELETE` | `/v4/secrets/{key}` |
87
88
 
88
89
  #### Get
89
90
 
@@ -115,7 +116,7 @@ Per-secret optional fields: Secret Comment, Skip Multiline Encoding
115
116
 
116
117
  | Field | Description |
117
118
  | --- | --- |
118
- | Secret Path Override | Use a different path than the top-level Secret Path |
119
+ | Secret Path Override | Use a different path than the top-level Secret Path for this batch |
119
120
 
120
121
  Returns each created secret as a separate output item. If a secret protection policy is active, returns an approval object instead.
121
122
 
@@ -146,7 +147,7 @@ Per-secret optional fields: Secret Value, New Secret Name, Secret Comment, Skip
146
147
  | Field | Description |
147
148
  | --- | --- |
148
149
  | Mode | `failOnNotFound` (default) — error if secret missing; `upsert` — create if missing; `ignore` — skip missing secrets |
149
- | Secret Path Override | Use a different path than the top-level Secret Path |
150
+ | Secret Path Override | Use a different path than the top-level Secret Path for this batch |
150
151
 
151
152
  Returns each updated secret as a separate output item.
152
153
 
@@ -154,6 +155,8 @@ Returns each updated secret as a separate output item.
154
155
 
155
156
  Required: **Secret Key**
156
157
 
158
+ The Delete request sends `projectId`, `environment`, and `secretPath` in the JSON request body (not as URL query parameters), as required by the v4 API.
159
+
157
160
  ### Workspace
158
161
 
159
162
  | Operation | Description |
@@ -162,6 +165,15 @@ Required: **Secret Key**
162
165
 
163
166
  ---
164
167
 
168
+ ## API behaviour notes
169
+
170
+ - **Single-secret operations** (Get, Get Many, Create, Update, Delete) use **Infisical API v4** (`/api/v4/secrets/…`).
171
+ - **Batch operations** (Create Many, Update Many) use **Infisical API v3** (`/api/v3/secrets/batch/raw`), which is Infisical's current batch endpoint.
172
+ - Single-secret ops pass the project identifier as `projectId` in the request. Batch ops pass it as `workspaceId`, as required by the respective API versions.
173
+ - When a **secret protection policy** is active on the project, create/update/delete endpoints return an approval object (`{ approval: { id, status, … } }`) instead of the secret directly.
174
+
175
+ ---
176
+
165
177
  ## Usage Examples
166
178
 
167
179
  ### Fetch a single secret
@@ -211,7 +223,7 @@ Required: **Secret Key**
211
223
  | --- | --- |
212
224
  | n8n | v1.0.0+ |
213
225
  | Infisical | Cloud and Community Edition |
214
- | Infisical API | v3 (single-secret ops), v4 (update + batch ops) |
226
+ | Infisical API | v4 (get, create, update, delete), v3 (batch ops) |
215
227
  | n8n Nodes API | v1 |
216
228
 
217
229
  ---
@@ -64,6 +64,19 @@ class InfisicalApi {
64
64
  required: true,
65
65
  description: 'The Client Secret of your Infisical Machine Identity (Universal Auth)',
66
66
  },
67
+ {
68
+ displayName: 'Organization Slug',
69
+ name: 'organizationSlug',
70
+ type: 'string',
71
+ displayOptions: {
72
+ show: {
73
+ authType: ['universalAuth'],
74
+ },
75
+ },
76
+ default: '',
77
+ description: 'Optional. Scope the access token to a specific organization. Leave blank to use the organization the machine identity was created in. ' +
78
+ 'To restrict this credential to a specific project, assign the machine identity to that project with the appropriate role in Infisical (Organization Settings → Machine Identities → your identity → Project Access).',
79
+ },
67
80
  {
68
81
  displayName: 'Service Token',
69
82
  name: 'apiKey',
Binary file
@@ -8,11 +8,18 @@ async function getInfisicalToken(helpers, credentials) {
8
8
  if (authType === 'universalAuth') {
9
9
  const clientId = credentials.clientId;
10
10
  const clientSecret = credentials.clientSecret;
11
+ const parts = [
12
+ `clientId=${encodeURIComponent(clientId)}`,
13
+ `clientSecret=${encodeURIComponent(clientSecret)}`,
14
+ ];
15
+ if (credentials.organizationSlug) {
16
+ parts.push(`organizationSlug=${encodeURIComponent(credentials.organizationSlug)}`);
17
+ }
11
18
  const tokenResponse = await helpers.httpRequest({
12
19
  method: 'POST',
13
20
  url: `${apiUrl}/v1/auth/universal-auth/login`,
14
21
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
15
- body: `clientId=${encodeURIComponent(clientId)}&clientSecret=${encodeURIComponent(clientSecret)}`,
22
+ body: parts.join('&'),
16
23
  });
17
24
  return { apiUrl, accessToken: tokenResponse.accessToken };
18
25
  }
@@ -470,13 +477,17 @@ class Infisical {
470
477
  try {
471
478
  let accessToken;
472
479
  if (authType === 'universalAuth') {
480
+ const loginForm = {
481
+ clientId: creds.clientId,
482
+ clientSecret: creds.clientSecret,
483
+ };
484
+ if (creds.organizationSlug) {
485
+ loginForm.organizationSlug = creds.organizationSlug;
486
+ }
473
487
  const tokenResponse = await this.helpers.request({
474
488
  method: 'POST',
475
489
  uri: `${apiUrl}/v1/auth/universal-auth/login`,
476
- form: {
477
- clientId: creds.clientId,
478
- clientSecret: creds.clientSecret,
479
- },
490
+ form: loginForm,
480
491
  json: true,
481
492
  });
482
493
  accessToken = tokenResponse.accessToken;
@@ -530,9 +541,9 @@ class Infisical {
530
541
  const secretKey = this.getNodeParameter('secretKey', i);
531
542
  const response = await this.helpers.httpRequest({
532
543
  method: 'GET',
533
- url: `${apiUrl}/v3/secrets/raw/${encodeURIComponent(secretKey)}`,
544
+ url: `${apiUrl}/v4/secrets/${encodeURIComponent(secretKey)}`,
534
545
  headers: baseHeaders,
535
- qs: { workspaceId, environment, secretPath },
546
+ qs: { projectId: workspaceId, environment, secretPath },
536
547
  });
537
548
  returnData.push({ json: response, pairedItem: { item: i } });
538
549
  // ── getAll ────────────────────────────────────────────────────────────
@@ -540,9 +551,9 @@ class Infisical {
540
551
  else if (operation === 'getAll') {
541
552
  const response = await this.helpers.httpRequest({
542
553
  method: 'GET',
543
- url: `${apiUrl}/v3/secrets/raw`,
554
+ url: `${apiUrl}/v4/secrets`,
544
555
  headers: baseHeaders,
545
- qs: { workspaceId, environment, secretPath },
556
+ qs: { projectId: workspaceId, environment, secretPath },
546
557
  });
547
558
  const secrets = response.secrets;
548
559
  for (const secret of secrets) {
@@ -555,9 +566,8 @@ class Infisical {
555
566
  const secretValue = this.getNodeParameter('secretValue', i);
556
567
  const createOptions = this.getNodeParameter('createOptions', i, {});
557
568
  const body = {
558
- workspaceId,
569
+ projectId: workspaceId,
559
570
  environment,
560
- secretName: secretKey,
561
571
  secretValue,
562
572
  secretPath,
563
573
  type: (_a = createOptions.type) !== null && _a !== void 0 ? _a : 'shared',
@@ -569,7 +579,7 @@ class Infisical {
569
579
  }
570
580
  const response = await this.helpers.httpRequest({
571
581
  method: 'POST',
572
- url: `${apiUrl}/v3/secrets/raw/${encodeURIComponent(secretKey)}`,
582
+ url: `${apiUrl}/v4/secrets/${encodeURIComponent(secretKey)}`,
573
583
  headers: baseHeaders,
574
584
  body: JSON.stringify(body),
575
585
  });
@@ -608,14 +618,19 @@ class Infisical {
608
618
  }
609
619
  else if (operation === 'delete') {
610
620
  const secretKey = this.getNodeParameter('secretKey', i);
621
+ const deleteBody = {
622
+ projectId: workspaceId,
623
+ environment,
624
+ secretPath,
625
+ };
611
626
  const response = await this.helpers.httpRequest({
612
627
  method: 'DELETE',
613
- url: `${apiUrl}/v3/secrets/raw/${encodeURIComponent(secretKey)}`,
628
+ url: `${apiUrl}/v4/secrets/${encodeURIComponent(secretKey)}`,
614
629
  headers: baseHeaders,
615
- qs: { workspaceId, environment, secretPath },
630
+ body: JSON.stringify(deleteBody),
616
631
  });
617
632
  returnData.push({ json: response, pairedItem: { item: i } });
618
- // ── createMany (v4 batch POST) ────────────────────────────────────────
633
+ // ── createMany (v3 batch POST) ────────────────────────────────────────
619
634
  }
620
635
  else if (operation === 'createMany') {
621
636
  const secretsParam = this.getNodeParameter('secrets', i, {});
@@ -637,14 +652,14 @@ class Infisical {
637
652
  return s;
638
653
  });
639
654
  const body = {
640
- projectId: workspaceId,
655
+ workspaceId,
641
656
  environment,
642
657
  secretPath: effectivePath,
643
658
  secrets,
644
659
  };
645
660
  const response = await this.helpers.httpRequest({
646
661
  method: 'POST',
647
- url: `${apiUrl}/v4/secrets/batch`,
662
+ url: `${apiUrl}/v3/secrets/batch/raw`,
648
663
  headers: baseHeaders,
649
664
  body: JSON.stringify(body),
650
665
  });
@@ -658,7 +673,7 @@ class Infisical {
658
673
  // Approval / policy-gated response
659
674
  returnData.push({ json: responseData, pairedItem: { item: i } });
660
675
  }
661
- // ── updateMany (v4 batch PATCH) ───────────────────────────────────────
676
+ // ── updateMany (v3 batch PATCH) ───────────────────────────────────────
662
677
  }
663
678
  else if (operation === 'updateMany') {
664
679
  const secretsToUpdateParam = this.getNodeParameter('secretsToUpdate', i, {});
@@ -683,7 +698,7 @@ class Infisical {
683
698
  return s;
684
699
  });
685
700
  const body = {
686
- projectId: workspaceId,
701
+ workspaceId,
687
702
  environment,
688
703
  secretPath: effectivePath,
689
704
  secrets,
@@ -692,7 +707,7 @@ class Infisical {
692
707
  body.mode = updateManyOptions.mode;
693
708
  const response = await this.helpers.httpRequest({
694
709
  method: 'PATCH',
695
- url: `${apiUrl}/v4/secrets/batch`,
710
+ url: `${apiUrl}/v3/secrets/batch/raw`,
696
711
  headers: baseHeaders,
697
712
  body: JSON.stringify(body),
698
713
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tadnt2003/n8n-nodes-infisical",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "n8n community node for Infisical - Secret management platform",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",