InfoGrab DocsInfoGrab Docs

워크플로 관리

요약

이 섹션의 상세 내용은 n8n 공식 문서를 참조하세요. 팀이나 조직에 걸친 n8n OEM 배포를 관리할 때는 여러 사용자에 대해 동일한(또는 유사한) 워크플로를 실행해야 하는 경우가 많습니다. 이 문서에서 참조하는 API는 언제든지 변경될 수 있습니다.

참고

이 섹션의 상세 내용은 n8n 공식 문서를 참조하세요.

팀이나 조직에 걸친 n8n OEM 배포를 관리할 때는 여러 사용자에 대해 동일한(또는 유사한) 워크플로를 실행해야 하는 경우가 많습니다. 이를 수행하는 방법에는 두 가지가 있습니다.

솔루션 장점 단점
사용자마다 워크플로 생성 워크플로 시작 방식에 제한이 없음(어떤 트리거든 사용 가능) 여러 워크플로를 관리해야 함.
단일 워크플로를 생성하고, 실행 시 사용자 자격 증명을 전달 워크플로 관리가 단순화됨(하나의 워크플로만 변경하면 됨). 워크플로를 실행하려면 제품에서 이를 호출해야 함
Warning

이 문서에서 참조하는 API는 언제든지 변경될 수 있습니다. 버전을 업그레이드할 때마다 계속 정상적으로 작동하는지 반드시 확인하세요.

사용자별 워크플로#

일반적으로 세 단계를 따르면 됩니다.

  • 각 사용자의 자격 증명과, 워크플로에 따라 필요할 수 있는 추가 매개변수를 확보합니다.
  • 이 사용자를 위한 n8n 자격 증명1을 생성합니다.
  • 워크플로를 생성합니다.

1. 사용자 자격 증명 확보#

이 사용자가 인증해야 하는 모든 노드/서비스에 대한 자격 증명과, 해당 워크플로에 필요한 추가 매개변수를 모두 확보해야 합니다. 필요한 자격 증명과 매개변수는 워크플로 및 수행하려는 작업에 따라 달라집니다.

2. 사용자 자격 증명 생성#

관련된 모든 자격 증명 세부 정보를 확보했다면, n8n에서 해당 서비스 자격 증명을 생성할 수 있습니다. 이는 편집기 UI 또는 API 호출을 사용하여 수행할 수 있습니다.

편집기 UI 사용#

  1. 메뉴에서 Credentials > New를 선택합니다.
  2. 드롭다운을 사용하여 생성할 Credential type을 선택합니다. 예: Airtable. Create New Credentials drop-down
  3. Create New Credentials 모달에서 해당 사용자에 대한 자격 증명 세부 정보를 입력하고, 이 자격 증명에 접근할 수 있는 노드를 선택합니다. Create New Credentials modal
  4. Create를 클릭하여 완료하고 저장합니다.

API 사용#

편집기 UI가 사용하는 프런트엔드 API를 호출하여 동일한 결과를 얻을 수도 있습니다. API 엔드포인트 형식은 다음과 같습니다: https://<n8n-domain>/rest/credentials.

예를 들어, 위의 편집기 UI 예시와 동일한 자격 증명을 생성하려면 요청은 다음과 같습니다.

POST https://<n8n-domain>/rest/credentials

요청 본문은 다음과 같습니다.

{
   "name":"MyAirtable",
   "type":"airtableApi",
   "nodesAccess":[
      {
         "nodeType":"n8n-nodes-base.airtable"
      }
   ],
   "data":{
      "apiKey":"q12we34r5t67yu"
   }
}

응답에는 새 자격 증명의 ID가 포함되며, 이 사용자를 위한 워크플로를 생성할 때 이 ID를 사용하게 됩니다.

{
   "data":{
      "name":"MyAirtable",
      "type":"airtableApi",
      "data":{
         "apiKey":"q12we34r5t67yu"
      },
      "nodesAccess":[
         {
            "nodeType":"n8n-nodes-base.airtable",
            "date":"2021-09-10T07:41:27.770Z"
         }
      ],
      "id":"29",
      "createdAt":"2021-09-10T07:41:27.777Z",
      "updatedAt":"2021-09-10T07:41:27.777Z"
   }
}

3. 워크플로 생성#

모범 사례는 "기본" 워크플로를 만들어 두고, 새 사용자가 생길 때마다 이를 복제하여 해당 사용자의 자격 증명(및 기타 세부 정보)에 맞게 커스터마이징하는 것입니다.

편집기 UI 또는 API 호출을 사용하여 템플릿 워크플로를 복제하고 커스터마이징할 수 있습니다.

편집기 UI 사용#

  1. 메뉴에서 Workflows > Open을 선택하여 복제할 템플릿 워크플로를 엽니다.

  2. Workflows > Duplicate를 선택한 다음, 이 새 워크플로의 이름을 입력하고 Save를 클릭합니다. Duplicate workflow

  3. 관련된 모든 노드를 업데이트하여 (위에서 생성한) 이 사용자의 자격 증명을 사용하도록 합니다.

  4. 이 워크플로를 Save하고, 우측 상단의 토글을 사용하여 Active로 설정합니다.

API 사용#

  1. 다음 엔드포인트를 사용하여 템플릿 워크플로의 JSON을 가져옵니다: https://<n8n-domain>/rest/workflows/<workflow_id>
GET https://<n8n-domain>/rest/workflows/1012

응답에는 선택한 워크플로의 JSON 데이터가 포함됩니다.

{
  "data": {
    "id": "1012",
    "name": "Nathan's Workflow",
    "active": false,
    "nodes": [
      {
        "parameters": {},
        "name": "Start",
        "type": "n8n-nodes-base.start",
        "typeVersion": 1,
        "position": [
          130,
          640
        ]
      },
      {
        "parameters": {
          "authentication": "headerAuth",
          "url": "https://internal.users.n8n.cloud/webhook/custom-erp",
          "options": {
            "splitIntoItems": true
          },
          "headerParametersUi": {
            "parameter": [
              {
                "name": "unique_id",
                "value": "recLhLYQbzNSFtHNq"
              }
            ]
          }
        },
        "name": "HTTP Request",
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 1,
        "position": [
          430,
          300
        ],
        "credentials": {
          "httpHeaderAuth": "beginner_course"
        }
      },
      {
        "parameters": {
          "operation": "append",
          "application": "appKBGQfbm6NfW6bv",
          "table": "processingOrders",
          "options": {}
        },
        "name": "Airtable",
        "type": "n8n-nodes-base.airtable",
        "typeVersion": 1,
        "position": [
          990,
          210
        ],
        "credentials": {
          "airtableApi": "Airtable"
        }
      },
      {
        "parameters": {
          "conditions": {
            "string": [
              {
                "value1": "={{$json[\"orderStatus\"]}}",
                "value2": "processing"
              }
            ]
          }
        },
        "name": "IF",
        "type": "n8n-nodes-base.if",
        "typeVersion": 1,
        "position": [
          630,
          300
        ]
      },
      {
        "parameters": {
          "keepOnlySet": true,
          "values": {
            "number": [
              {
                "name": "=orderId",
                "value": "={{$json[\"orderID\"]}}"
              }
            ],
            "string": [
              {
                "name": "employeeName",
                "value": "={{$json[\"employeeName\"]}}"
              }
            ]
          },
          "options": {}
        },
        "name": "Set",
        "type": "n8n-nodes-base.set",
        "typeVersion": 1,
        "position": [
          800,
          210
        ]
      },
      {
        "parameters": {
          "functionCode": "let totalBooked = items.length;\nlet bookedSum = 0;\n\nfor(let i=0; i < items.length; i++) {\n  bookedSum = bookedSum + items[i].json.orderPrice;\n}\nreturn [{json:{totalBooked, bookedSum}}]\n"
        },
        "name": "Function",
        "type": "n8n-nodes-base.function",
        "typeVersion": 1,
        "position": [
          800,
          400
        ]
      },
      {
        "parameters": {
          "webhookUri": "https://discord.com/api/webhooks/865213348202151968/oD5_WPDQwtr22Vjd_82QP3-_4b_lGhAeM7RynQ8Js5DzyXrQEnj0zeAQIA6fki1JLtXE",
          "text": "=This week we have {{$json[\"totalBooked\"]}} booked orders with a total value of {{$json[\"bookedSum\"]}}. My Unique ID: {{ $(\"HTTP Request\").params.headerParameters.parameters[0].value }}"
        },
        "name": "Discord",
        "type": "n8n-nodes-base.discord",
        "typeVersion": 1,
        "position": [
          1000,
          400
        ]
      },
      {
        "parameters": {
          "triggerTimes": {
            "item": [
              {
                "mode": "everyWeek",
                "hour": 9
              }
            ]
          }
        },
        "name": "Cron",
        "type": "n8n-nodes-base.cron",
        "typeVersion": 1,
        "position": [
          220,
          300
        ]
      }
    ],
    "connections": {
      "HTTP Request": {
        "main": [
          [
            {
              "node": "IF",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Start": {
        "main": [
          []
        ]
      },
      "IF": {
        "main": [
          [
            {
              "node": "Set",
              "type": "main",
              "index": 0
            }
          ],
          [
            {
              "node": "Function",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Set": {
        "main": [
          [
            {
              "node": "Airtable",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Function": {
        "main": [
          [
            {
              "node": "Discord",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Cron": {
        "main": [
          [
            {
              "node": "HTTP Request",
              "type": "main",
              "index": 0
            }
          ]
        ]
      }
    },
    "createdAt": "2021-07-16T11:15:46.066Z",
    "updatedAt": "2021-07-16T12:05:44.045Z",
    "settings": {},
    "staticData": null,
    "tags": []
  }
}
  1. 반환된 JSON 데이터를 저장하고, 새 사용자에 맞게 관련 자격 증명과 필드를 업데이트합니다.

  2. 업데이트된 JSON을 요청 본문으로 사용하여 다음 엔드포인트에서 새 워크플로를 생성합니다: https://<n8n-domain>/rest/workflows

POST https://<n8n-domain>/rest/workflows/

응답에는 새 워크플로의 ID가 포함되며, 다음 단계에서 이를 사용하게 됩니다.

  1. 마지막으로 새 워크플로를 게시합니다.
PATCH https://<n8n-domain>/rest/workflows/1012

JSON 페이로드에 추가 값 active를 전달합니다.

// ...
"active":true,
"settings": {},
"staticData": null,
"tags": []

단일 워크플로#

이 방법을 구현하려면 네 단계를 따라야 합니다.

  • 각 사용자의 자격 증명과, 워크플로에 따라 필요할 수 있는 추가 매개변수를 확보합니다. 위의 사용자 자격 증명 확보를 참고하세요.
  • 이 사용자를 위한 n8n 자격 증명을 생성합니다. 위의 사용자 자격 증명 생성을 참고하세요.
  • 워크플로를 생성합니다.
  • 필요에 따라 워크플로를 호출합니다.

워크플로 생성#

이 워크플로의 세부 사항과 범위는 개별 사용 사례에 따라 크게 달라지지만, 염두에 두어야 할 몇 가지 설계 구현 사항이 있습니다.

  • 이 워크플로는 반드시 Webhook 노드에 의해 트리거되어야 합니다.
  • 수신되는 웹훅 호출에는 사용자의 자격 증명과 필요한 기타 워크플로 매개변수가 포함되어야 합니다.
  • 사용자의 자격 증명이 필요한 각 노드는 표현식을 사용해야, 해당 노드의 자격 증명 필드가 웹훅 호출에서 제공된 자격 증명을 읽도록 할 수 있습니다.
  • Webhook 노드에 대해 프로덕션 URL이 선택되었는지 확인하면서 워크플로를 저장하고 게시합니다. 자세한 내용은 webhook node를 참고하세요.

워크플로 호출#

새로 등록된 각 사용자나, 필요에 따라 기존 사용자에 대해, 워크플로 트리거로 정의된 웹훅을 호출하고 필요한 자격 증명(및 기타 워크플로 매개변수)을 제공합니다.

Footnotes

  1. n8n에서 자격 증명은 특정 앱 및 서비스에 연결하기 위한 인증 정보를 저장합니다. 인증 정보(사용자 이름과 비밀번호, API 키, OAuth 시크릿 등)로 자격 증명을 생성한 후, 연결된 앱 노드를 사용하여 해당 서비스와 상호 작용할 수 있습니다.

워크플로 관리

n8n v2.29
원문 보기
요약

이 섹션의 상세 내용은 n8n 공식 문서를 참조하세요. 팀이나 조직에 걸친 n8n OEM 배포를 관리할 때는 여러 사용자에 대해 동일한(또는 유사한) 워크플로를 실행해야 하는 경우가 많습니다. 이 문서에서 참조하는 API는 언제든지 변경될 수 있습니다.

참고

이 섹션의 상세 내용은 n8n 공식 문서를 참조하세요.

팀이나 조직에 걸친 n8n OEM 배포를 관리할 때는 여러 사용자에 대해 동일한(또는 유사한) 워크플로를 실행해야 하는 경우가 많습니다. 이를 수행하는 방법에는 두 가지가 있습니다.

솔루션 장점 단점
사용자마다 워크플로 생성 워크플로 시작 방식에 제한이 없음(어떤 트리거든 사용 가능) 여러 워크플로를 관리해야 함.
단일 워크플로를 생성하고, 실행 시 사용자 자격 증명을 전달 워크플로 관리가 단순화됨(하나의 워크플로만 변경하면 됨). 워크플로를 실행하려면 제품에서 이를 호출해야 함
Warning

이 문서에서 참조하는 API는 언제든지 변경될 수 있습니다. 버전을 업그레이드할 때마다 계속 정상적으로 작동하는지 반드시 확인하세요.

사용자별 워크플로#

일반적으로 세 단계를 따르면 됩니다.

  • 각 사용자의 자격 증명과, 워크플로에 따라 필요할 수 있는 추가 매개변수를 확보합니다.
  • 이 사용자를 위한 n8n 자격 증명1을 생성합니다.
  • 워크플로를 생성합니다.

1. 사용자 자격 증명 확보#

이 사용자가 인증해야 하는 모든 노드/서비스에 대한 자격 증명과, 해당 워크플로에 필요한 추가 매개변수를 모두 확보해야 합니다. 필요한 자격 증명과 매개변수는 워크플로 및 수행하려는 작업에 따라 달라집니다.

2. 사용자 자격 증명 생성#

관련된 모든 자격 증명 세부 정보를 확보했다면, n8n에서 해당 서비스 자격 증명을 생성할 수 있습니다. 이는 편집기 UI 또는 API 호출을 사용하여 수행할 수 있습니다.

편집기 UI 사용#

  1. 메뉴에서 Credentials > New를 선택합니다.
  2. 드롭다운을 사용하여 생성할 Credential type을 선택합니다. 예: Airtable. Create New Credentials drop-down
  3. Create New Credentials 모달에서 해당 사용자에 대한 자격 증명 세부 정보를 입력하고, 이 자격 증명에 접근할 수 있는 노드를 선택합니다. Create New Credentials modal
  4. Create를 클릭하여 완료하고 저장합니다.

API 사용#

편집기 UI가 사용하는 프런트엔드 API를 호출하여 동일한 결과를 얻을 수도 있습니다. API 엔드포인트 형식은 다음과 같습니다: https://<n8n-domain>/rest/credentials.

예를 들어, 위의 편집기 UI 예시와 동일한 자격 증명을 생성하려면 요청은 다음과 같습니다.

POST https://<n8n-domain>/rest/credentials

요청 본문은 다음과 같습니다.

{
   "name":"MyAirtable",
   "type":"airtableApi",
   "nodesAccess":[
      {
         "nodeType":"n8n-nodes-base.airtable"
      }
   ],
   "data":{
      "apiKey":"q12we34r5t67yu"
   }
}

응답에는 새 자격 증명의 ID가 포함되며, 이 사용자를 위한 워크플로를 생성할 때 이 ID를 사용하게 됩니다.

{
   "data":{
      "name":"MyAirtable",
      "type":"airtableApi",
      "data":{
         "apiKey":"q12we34r5t67yu"
      },
      "nodesAccess":[
         {
            "nodeType":"n8n-nodes-base.airtable",
            "date":"2021-09-10T07:41:27.770Z"
         }
      ],
      "id":"29",
      "createdAt":"2021-09-10T07:41:27.777Z",
      "updatedAt":"2021-09-10T07:41:27.777Z"
   }
}

3. 워크플로 생성#

모범 사례는 "기본" 워크플로를 만들어 두고, 새 사용자가 생길 때마다 이를 복제하여 해당 사용자의 자격 증명(및 기타 세부 정보)에 맞게 커스터마이징하는 것입니다.

편집기 UI 또는 API 호출을 사용하여 템플릿 워크플로를 복제하고 커스터마이징할 수 있습니다.

편집기 UI 사용#

  1. 메뉴에서 Workflows > Open을 선택하여 복제할 템플릿 워크플로를 엽니다.

  2. Workflows > Duplicate를 선택한 다음, 이 새 워크플로의 이름을 입력하고 Save를 클릭합니다. Duplicate workflow

  3. 관련된 모든 노드를 업데이트하여 (위에서 생성한) 이 사용자의 자격 증명을 사용하도록 합니다.

  4. 이 워크플로를 Save하고, 우측 상단의 토글을 사용하여 Active로 설정합니다.

API 사용#

  1. 다음 엔드포인트를 사용하여 템플릿 워크플로의 JSON을 가져옵니다: https://<n8n-domain>/rest/workflows/<workflow_id>
GET https://<n8n-domain>/rest/workflows/1012

응답에는 선택한 워크플로의 JSON 데이터가 포함됩니다.

{
  "data": {
    "id": "1012",
    "name": "Nathan's Workflow",
    "active": false,
    "nodes": [
      {
        "parameters": {},
        "name": "Start",
        "type": "n8n-nodes-base.start",
        "typeVersion": 1,
        "position": [
          130,
          640
        ]
      },
      {
        "parameters": {
          "authentication": "headerAuth",
          "url": "https://internal.users.n8n.cloud/webhook/custom-erp",
          "options": {
            "splitIntoItems": true
          },
          "headerParametersUi": {
            "parameter": [
              {
                "name": "unique_id",
                "value": "recLhLYQbzNSFtHNq"
              }
            ]
          }
        },
        "name": "HTTP Request",
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 1,
        "position": [
          430,
          300
        ],
        "credentials": {
          "httpHeaderAuth": "beginner_course"
        }
      },
      {
        "parameters": {
          "operation": "append",
          "application": "appKBGQfbm6NfW6bv",
          "table": "processingOrders",
          "options": {}
        },
        "name": "Airtable",
        "type": "n8n-nodes-base.airtable",
        "typeVersion": 1,
        "position": [
          990,
          210
        ],
        "credentials": {
          "airtableApi": "Airtable"
        }
      },
      {
        "parameters": {
          "conditions": {
            "string": [
              {
                "value1": "={{$json[\"orderStatus\"]}}",
                "value2": "processing"
              }
            ]
          }
        },
        "name": "IF",
        "type": "n8n-nodes-base.if",
        "typeVersion": 1,
        "position": [
          630,
          300
        ]
      },
      {
        "parameters": {
          "keepOnlySet": true,
          "values": {
            "number": [
              {
                "name": "=orderId",
                "value": "={{$json[\"orderID\"]}}"
              }
            ],
            "string": [
              {
                "name": "employeeName",
                "value": "={{$json[\"employeeName\"]}}"
              }
            ]
          },
          "options": {}
        },
        "name": "Set",
        "type": "n8n-nodes-base.set",
        "typeVersion": 1,
        "position": [
          800,
          210
        ]
      },
      {
        "parameters": {
          "functionCode": "let totalBooked = items.length;\nlet bookedSum = 0;\n\nfor(let i=0; i < items.length; i++) {\n  bookedSum = bookedSum + items[i].json.orderPrice;\n}\nreturn [{json:{totalBooked, bookedSum}}]\n"
        },
        "name": "Function",
        "type": "n8n-nodes-base.function",
        "typeVersion": 1,
        "position": [
          800,
          400
        ]
      },
      {
        "parameters": {
          "webhookUri": "https://discord.com/api/webhooks/865213348202151968/oD5_WPDQwtr22Vjd_82QP3-_4b_lGhAeM7RynQ8Js5DzyXrQEnj0zeAQIA6fki1JLtXE",
          "text": "=This week we have {{$json[\"totalBooked\"]}} booked orders with a total value of {{$json[\"bookedSum\"]}}. My Unique ID: {{ $(\"HTTP Request\").params.headerParameters.parameters[0].value }}"
        },
        "name": "Discord",
        "type": "n8n-nodes-base.discord",
        "typeVersion": 1,
        "position": [
          1000,
          400
        ]
      },
      {
        "parameters": {
          "triggerTimes": {
            "item": [
              {
                "mode": "everyWeek",
                "hour": 9
              }
            ]
          }
        },
        "name": "Cron",
        "type": "n8n-nodes-base.cron",
        "typeVersion": 1,
        "position": [
          220,
          300
        ]
      }
    ],
    "connections": {
      "HTTP Request": {
        "main": [
          [
            {
              "node": "IF",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Start": {
        "main": [
          []
        ]
      },
      "IF": {
        "main": [
          [
            {
              "node": "Set",
              "type": "main",
              "index": 0
            }
          ],
          [
            {
              "node": "Function",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Set": {
        "main": [
          [
            {
              "node": "Airtable",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Function": {
        "main": [
          [
            {
              "node": "Discord",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Cron": {
        "main": [
          [
            {
              "node": "HTTP Request",
              "type": "main",
              "index": 0
            }
          ]
        ]
      }
    },
    "createdAt": "2021-07-16T11:15:46.066Z",
    "updatedAt": "2021-07-16T12:05:44.045Z",
    "settings": {},
    "staticData": null,
    "tags": []
  }
}
  1. 반환된 JSON 데이터를 저장하고, 새 사용자에 맞게 관련 자격 증명과 필드를 업데이트합니다.

  2. 업데이트된 JSON을 요청 본문으로 사용하여 다음 엔드포인트에서 새 워크플로를 생성합니다: https://<n8n-domain>/rest/workflows

POST https://<n8n-domain>/rest/workflows/

응답에는 새 워크플로의 ID가 포함되며, 다음 단계에서 이를 사용하게 됩니다.

  1. 마지막으로 새 워크플로를 게시합니다.
PATCH https://<n8n-domain>/rest/workflows/1012

JSON 페이로드에 추가 값 active를 전달합니다.

// ...
"active":true,
"settings": {},
"staticData": null,
"tags": []

단일 워크플로#

이 방법을 구현하려면 네 단계를 따라야 합니다.

  • 각 사용자의 자격 증명과, 워크플로에 따라 필요할 수 있는 추가 매개변수를 확보합니다. 위의 사용자 자격 증명 확보를 참고하세요.
  • 이 사용자를 위한 n8n 자격 증명을 생성합니다. 위의 사용자 자격 증명 생성을 참고하세요.
  • 워크플로를 생성합니다.
  • 필요에 따라 워크플로를 호출합니다.

워크플로 생성#

이 워크플로의 세부 사항과 범위는 개별 사용 사례에 따라 크게 달라지지만, 염두에 두어야 할 몇 가지 설계 구현 사항이 있습니다.

  • 이 워크플로는 반드시 Webhook 노드에 의해 트리거되어야 합니다.
  • 수신되는 웹훅 호출에는 사용자의 자격 증명과 필요한 기타 워크플로 매개변수가 포함되어야 합니다.
  • 사용자의 자격 증명이 필요한 각 노드는 표현식을 사용해야, 해당 노드의 자격 증명 필드가 웹훅 호출에서 제공된 자격 증명을 읽도록 할 수 있습니다.
  • Webhook 노드에 대해 프로덕션 URL이 선택되었는지 확인하면서 워크플로를 저장하고 게시합니다. 자세한 내용은 webhook node를 참고하세요.

워크플로 호출#

새로 등록된 각 사용자나, 필요에 따라 기존 사용자에 대해, 워크플로 트리거로 정의된 웹훅을 호출하고 필요한 자격 증명(및 기타 워크플로 매개변수)을 제공합니다.

Footnotes

  1. n8n에서 자격 증명은 특정 앱 및 서비스에 연결하기 위한 인증 정보를 저장합니다. 인증 정보(사용자 이름과 비밀번호, API 키, OAuth 시크릿 등)로 자격 증명을 생성한 후, 연결된 앱 노드를 사용하여 해당 서비스와 상호 작용할 수 있습니다.