# 인증

> 개인 API 토큰, OAuth 앱 토큰 또는 세션 JWT로 Nodaro API 호출을 인증하고, API 토큰을 만들고 범위를 지정하고 연결하고 해지하는 방법을 설명합니다.

Source: https://nodaro.ai/ko/docs/developers/api/authentication

모든 Nodaro API 요청은 `Authorization` 헤더의 **Bearer 토큰**으로 인증합니다. 내 서버가 내 계정으로 Nodaro를 호출할 때는 개인 API 토큰(`ndr_…`)을, 내 제품이 다른 Nodaro 사용자를 대신해 작동할 때는 OAuth 액세스 토큰(`ndr_app_…`)을, 셀프 호스팅 Community Edition 설치에서는 세션 JWT를 사용하세요.

```http
Authorization: Bearer ndr_4f1c…
```

## 사용할 자격 증명
| 상황 | 사용할 것 | 토큰 형식 |
| --- | --- | --- |
| 서버, cron 작업, CI 파이프라인에서 내 Nodaro 계정을 스크립트로 다룰 때 | 개인 API 토큰 | `ndr_` 뒤에 16진수 64자 |
| 다른 사용자의 Nodaro 계정에서 워크플로를 실행하는 제품을 만들 때 | OAuth 액세스 토큰 | `ndr_app_` 뒤에 16진수 64자 |
| 셀프 호스팅 Community Edition을 직접 운영할 때 | 내 세션 JWT | `eyJ`로 시작하는 JWT |

간단한 판단 기준: 서버에 자격 증명 한 세트만 필요하고 동의 화면이 필요 없다면 API 토큰을 사용하세요. 여러 고객이 각자 자기 계정에 대한 접근 권한을 내 앱에 줘야 한다면 [OAuth](https://nodaro.ai/docs/developers/oauth)를 사용하세요.

API 토큰은 Nodaro Cloud와 Business 에디션에서 사용할 수 있습니다. Community Edition에서는 같은 엔드포인트를 로그인한 세션의 액세스 토큰으로 호출하세요. [에디션](https://nodaro.ai/docs/concepts/editions)을 참조하세요.

## API 토큰 만들기
### API 토큰 페이지 열기
Nodaro에 로그인하고 **설정 › API 토큰**을 여세요. Nodaro Cloud에서는 이 페이지가 `https://app.nodaro.ai/settings/api`에 있습니다.

### 토큰 만들기
**토큰 만들기**를 클릭하세요. **API 토큰 만들기** 대화 상자에서 구분하기 쉬운 **이름**(예: `prod-scheduler`)과 1~120 사이의 <strong>요청 한도(분당 요청 수)</strong>를 입력하세요. 기본값은 분당 30회입니다.

### 지금 복사하기
**만들기**를 클릭하고 토큰을 비밀 저장소에 복사하세요. 토큰은 한 번만 표시됩니다. Nodaro는 토큰의 SHA-256 해시만 저장하므로 잃어버린 토큰은 복구할 수 없습니다. 그럴 때는 새 토큰을 만드세요.

이 페이지에는 각 토큰의 이름, 접두사, 요청 한도, 마지막 사용 시각, 생성 시각이 나열됩니다. 토큰 옆의 스위치로 토큰을 켜거나 끄고, 휴지통 버튼으로 토큰을 삭제합니다.

### API 토큰 규칙
- **계정당 토큰 최대 10개**, 활성 여부와 관계없습니다. 비활성화한 토큰도 개수에 포함되므로, 자리를 비우려면 삭제하세요. 11번째 토큰은 `400 limit_reached`로 거부됩니다.
- **만료와 지출 한도 없음.** 토큰은 비활성화하거나 삭제할 때까지 작동합니다. 토큰을 삭제하면 즉시 해지됩니다.
- **토큰은 나로서 작동합니다.** 토큰이 하는 모든 호출은 내 계정으로 실행되며 내 크레딧을 사용합니다.
- **로그인 공급자 기준으로 다시 확인하지 않습니다.** ID 공급자에서 계정이 제거되기 전에 만든 토큰은 해지할 때까지 계속 작동합니다. 모든 토큰을 영구적인 자격 증명으로 취급하세요.

## 토큰을 일부 워크플로로 제한
토큰을 워크플로 목록으로 제한할 수 있으며, 이 목록이 토큰의 **워크플로 범위**입니다. **API 토큰** 페이지에서 만든 토큰에는 범위가 없어서, 내가 소유한 모든 워크플로를 실행할 수 있습니다. `workflowIds`가 없는 토큰이 계정의 전체 접근 토큰입니다.

아래 엔드포인트로 토큰을 만들거나 업데이트할 때 `workflowIds` 필드로 최대 50개의 워크플로를 범위로 설정하세요. 범위 변경은 1분 안에 적용됩니다. 개인 공간에 있는 워크플로만 넣을 수 있으며, 워크스페이스에 있는 워크플로는 `400 invalid_workflow`로 응답합니다.

범위가 지정된 토큰은 해당 워크플로를 실행하기 위한 토큰입니다. 워크플로를 실행하고, 워크플로와 그 입력을 읽고, 그 실행을 추적할 수 있으며, 그 밖의 일은 할 수 없습니다.

- `GET /v1/api/workflows`, `GET /v1/workflows`, `GET /v1/projects/:projectId/workflows`는 해당 워크플로만 나열합니다. `GET /v1/executions`는 해당 워크플로의 실행만 나열합니다.
- `GET /v1/api/schema`, `POST /v1/api/run`, `GET /v1/workflows/:id`, `GET /v1/workflows/:id/interface`, `POST /v1/workflows/:id/run`, `POST /v1/workflows/:id/render-final/estimate`, `GET /v1/workflows/:id/executions`는 해당 워크플로에 대해서만 응답합니다.
- `GET /v1/api/status/:execId`, `GET /v1/api/result/:execId`, `GET /v1/workflow-executions/:id`와 그 `/stream`, `/cancel` 라우트는 해당 워크플로의 실행에 대해서만 응답합니다. 내 것이 아닌 실행에는 `404`로 응답합니다.
- 공개 갤러리, 모델 카탈로그와 노드 카탈로그처럼 로그인이 필요 없는 라우트는 토큰이 없을 때와 똑같이 응답합니다.

그 밖의 모든 요청은 `403 forbidden`으로 응답하며, 메시지는 “This API key is limited to specific workflows, and this request is outside them. Use a key without a workflow limit for anything else.”(이 API 키는 특정 워크플로로 제한되어 있으며, 이 요청은 그 범위를 벗어납니다. 그 밖의 작업에는 워크플로 제한이 없는 키를 사용하세요.)입니다. 다른 워크플로나 그 실행, 워크플로 편집이나 삭제, 직접 생성 라우트, 업로드, 작업, 게시된 앱, MCP, 중계 자격 증명으로 사용하는 경우가 모두 여기에 해당합니다. 요청은 아무것도 실행되기 전에 거부되므로, 크레딧이 예약되거나 청구되지 않습니다.

## 코드로 토큰 관리
| 메서드 | 경로 | 기능 |
| --- | --- | --- |
| `POST` | `/v1/api-tokens` | 토큰을 만듭니다. 본문은 `{ name, workflowIds, rateLimit }`입니다. 전체 토큰은 이 응답에서만 표시됩니다. |
| `GET` | `/v1/api-tokens` | 토큰 목록을 설정 및 워크스페이스 연결(`workspaceId`)과 함께 가져옵니다. 토큰 자체는 반환되지 않습니다. |
| `PATCH` | `/v1/api-tokens/:id` | 이름, 워크플로 범위, 요청 한도, 활성 플래그 또는 워크스페이스 연결을 변경합니다. |
| `DELETE` | `/v1/api-tokens/:id` | 토큰을 삭제합니다. 토큰은 즉시 작동을 멈춥니다. |

이 네 라우트는 로그인한 세션에서만 작동하므로, API 토큰이 아니라 세션 JWT를 보내세요. 개인 API 토큰이나 OAuth 토큰은 `403 forbidden`으로 거부되며, 메시지는 “API token management is only available from a logged-in session”(API 토큰 관리는 로그인한 세션에서만 가능)입니다. Community Edition 설치에서는 생성 라우트와 목록 라우트가 `required_edition: "business"`와 함께 `403 edition_required`로 응답합니다.

토큰을 하나의 워크스페이스에 연결하려면 [토큰을 워크스페이스에 연결](https://nodaro.ai/docs/developers/api/workspaces#bind-a-token-to-a-workspace)을 참조하세요.

## 토큰 보내기
`GET /v1/me`는 유효한 토큰에 연결된 계정을 반환하므로, 토큰을 확인하는 가장 빠른 방법입니다. 토큰이 없거나, 유효하지 않거나, 해지되었으면 `401 unauthorized`로 응답합니다.

**curl**

```bash
curl https://app.nodaro.ai/v1/me \
  -H "Authorization: Bearer $NODARO_API_KEY"
```

```json
{
"data": {
"id": "5bf0d884-47b1-468e-a7b2-2433f957b267",
"email": "ada@example.com",
"displayName": "Ada",
"avatarUrl": null,
"tier": "pro",
"isAdmin": false
}
}
```

**TypeScript SDK**

```ts

const client = createClient({
baseUrl: 'https://app.nodaro.ai',
auth: new StaticTokenAuth(process.env.NODARO_API_KEY!),
})

const me = await client.me()
console.log(me.email, me.tier)
```

**CLI**

```bash
nodaro auth login --token "$NODARO_API_KEY"
nodaro auth status
```

조직에 속한 계정에서는 같은 응답에 계정이 속한 조직과 워크스페이스도 담깁니다. [워크스페이스와 조직](https://nodaro.ai/docs/developers/api/workspaces)을 참조하세요.

SDK는 인증 공급자에게서 토큰을 받으므로, 토큰을 어떻게 찾을지 직접 선택할 수 있습니다.

| 공급자 | 용도 |
| --- | --- |
| `StaticTokenAuth` | 서버의 고정 토큰: API 토큰 또는 OAuth 액세스 토큰. |
| `supabaseAuth(supabase)` | Nodaro 설치의 로그인을 공유하는 브라우저 앱. 요청마다 세션 토큰을 읽으므로 갱신이 자동으로 이루어집니다. |
| `CallbackAuth` | 직접 만든 로직. 예를 들어 토큰을 갱신하는 세션 저장소. 콜백이 `null`을 반환하면 헤더를 보내지 않습니다. |

CLI는 토큰을 파일 모드 `0600`으로 `~/.config/nodaro/config.json`에 저장합니다. 셀프 호스팅 설치용 두 번째 로그인을 유지하려면 `--profile`과 `--base-url`을 추가하세요. 예: `nodaro auth login --profile local --base-url http://localhost:3000`.

## OAuth 액세스 토큰
각 사용자가 자신의 Nodaro 계정을 내 제품에 연결하게 할 때는 OAuth를 사용하세요. 내 서버가 인증 코드를 `ndr_app_`으로 시작하는 액세스 토큰으로 교환합니다. 토큰의 유효 기간은 90일이며, 갱신 토큰은 없습니다. 토큰이 만료되면 사용자를 동의 화면으로 다시 안내하세요.

OAuth 토큰에는 사용자가 허용한 범위만 담깁니다. 토큰에 없는 범위가 필요한 라우트는 `403 insufficient_scope`로 응답하며, 오류의 `missingScope`에 해당 범위가 표시됩니다. 대부분의 API 통합에 필요한 범위는 다음과 같습니다.

| 범위 | 허용 내용 |
| --- | --- |
| `workflows:read` | 사용자의 워크플로 읽기: `GET /v1/workflows`, `GET /v1/workflows/:id`, 워크플로 내보내기, 프로젝트별 목록. |
| `workflows:write` | 워크플로 만들기, 변경, 가져오기, 삭제. |
| `workflows:execute` | `POST /v1/workflows/:id/run`으로 워크플로 실행. |
| `jobs:read` | 일괄 폴링을 포함해 작업 상태와 결과 읽기. |

개인 API 토큰과 세션 JWT에는 범위가 없으며, 내 계정으로 작동합니다. 전체 흐름, 모든 범위, 동의 화면은 [OAuth 앱](https://nodaro.ai/docs/developers/oauth)에서 확인하세요.

## 로그인한 세션이 필요한 라우트
몇몇 라우트는 Nodaro 웹 앱 전용이며, API 토큰과 OAuth 토큰을 모두 거부합니다.

| 라우트 | 토큰에 대한 응답 |
| --- | --- |
| `/v1/api-tokens`(토큰 관리) | `403 forbidden` |
| `/v1/billing/*`(결제, 충전, 자동 충전, 구매 내역) | `403 forbidden` |
| 노드 프리셋 쓰기 | `403 forbidden` |
| `/v1/copilot/*`([Workflow Copilot](https://nodaro.ai/docs/get-started/workflow-copilot)) | `403 in_app_only` |
| `/v1/http-credentials`(Webhook 출력 노드용으로 저장된 키) | `403 in_app_only` |

코드로 워크플로를 만들려면 [워크플로 엔드포인트](https://nodaro.ai/docs/developers/api/workflows), [SDK](https://nodaro.ai/docs/developers/sdk) 또는 [MCP 서버](https://nodaro.ai/docs/mcp)를 사용하세요.

## 클라이언트 식별
`X-Nodaro-Client` 헤더를 보내면 Nodaro가 그 값을 요청으로 생성되는 모든 작업의 출처로 기록합니다.

```http
X-Nodaro-Client: sdk/1.10.0
```

인식되는 형식은 `sdk/<version>`, `cli/<version>`, `extension/<name>` 세 가지뿐입니다. 이 헤더는 인증되지 않으므로 그 밖의 값은 무시됩니다. `@nodaro/sdk`와 `@nodaro/cli`가 이 헤더를 자동으로 보내므로, REST API를 직접 호출할 때만 필요합니다. 생략해도 괜찮습니다. 그러면 해당 작업은 일반 API 호출로 기록됩니다.

브라우저에서 호출할 때는 이 헤더를 보내지 마세요. 브라우저의 `Origin` 헤더가 이미 사이트를 알려 주며, Nodaro는 그 값을 우선합니다. SDK는 브라우저에서 실행될 때 이 헤더를 자동으로 생략합니다.

## 토큰은 서버에 보관
브라우저 코드에 있는 토큰은 개발자 도구만 있으면 누구나 읽을 수 있고, 내 크레딧을 쓸 수 있습니다. 토큰은 서버 라우트, 엣지 함수 또는 플랫폼의 비밀 저장소에 두고, 브라우저는 내 서버와만 통신하게 하세요.

```text
Browser  ->  your server (holds NODARO_API_KEY)  ->  Nodaro API
```

예를 들어 Next.js에서는 라우트 핸들러에서 `NEXT_PUBLIC_` 접두사가 없는 환경 변수로 토큰을 읽으세요. OAuth 토큰으로 브라우저에서 Nodaro를 호출한다면, 개발자 앱의 허용된 출처에 사이트의 출처를 추가하세요.

## 토큰으로 셀프 호스팅 설치 연결
워크플로 범위가 없는 개인 API 토큰은 셀프 호스팅 설치의 생성 작업을 Nodaro Cloud에서 실행하는 가장 간단한 방법이기도 합니다. 셀프 호스팅 설치에서 `NODARO_CLOUD_URL`을 Nodaro Cloud 주소로, `NODARO_API_KEY`를 내 토큰으로 설정하세요. 그러면 모든 생성이 Nodaro Cloud에서 실행되고 토큰 계정으로 청구되며, OAuth 연결은 필요하지 않습니다. [Nodaro Cloud에 연결](https://nodaro.ai/docs/self-hosting/cloud-connect)을 참조하세요.

## 결제 계정이 하나인 배포
일부 배포에는 모든 사용자의 비용을 내는 결제 계정이 하나만 있습니다. 이런 배포에서는 다음과 같습니다.

- 결제 계정만 토큰을 만들 수 있습니다. 다른 사용자는 `403 api_tokens_payer_only`를 받으며, 기존 토큰은 소유자가 계속 목록에서 보고 해지할 수 있습니다.
- 설정에 API 토큰 카드가 표시되지 않습니다. 결제 계정은 `/settings/api`를 직접 엽니다.
- 토큰이 하는 모든 호출은 배포의 공동 잔액에서 지불됩니다.
- 토큰으로는 그 공동 잔액을 읽을 수 없습니다. 결제 계정의 토큰으로 잔액을 읽으면 `403 payer_balance_jwt_only`로 응답하고, 배포 결제 라우트는 `403 payer_required`로 응답합니다.

## 오류
| 상태 | 코드 | 의미 |
| --- | --- | --- |
| 400 | `limit_reached` | 활성 여부와 관계없이 이미 토큰이 10개 있습니다. 먼저 하나를 삭제하세요. |
| 400 | `invalid_workflow` | `workflowIds` 항목이 개인 공간의 워크플로가 아닙니다. |
| 400 | `token_workspace_mismatch` | 한 워크스페이스에 연결된 토큰이 다른 워크스페이스를 지정한 `X-Nodaro-Workspace` 헤더와 함께 전송되었습니다. |
| 401 | `unauthorized` | 토큰이 없거나, 유효하지 않거나, 만료되었거나, 해지되었습니다. |
| 403 | `forbidden` | 토큰에 워크플로 범위가 있고 요청이 그 범위를 벗어났거나, 라우트에 로그인한 세션이 필요합니다. |
| 403 | `access_blocked` | Nodaro Cloud와 Business 에디션에서 관리자가 계정을 차단했습니다. 계정의 모든 자격 증명이 거부됩니다. |
| 403 | `insufficient_scope` | OAuth 토큰에 라우트에 필요한 범위가 없습니다. `missingScope`에 그 범위가 표시됩니다. |
| 403 | `in_app_only` | Nodaro 웹 앱 전용 라우트입니다. |
| 403 | `edition_required` | 더 높은 에디션이 필요한 라우트입니다. `required_edition`에 최소 에디션이 표시됩니다. |
| 403 | `api_tokens_payer_only` | 결제 계정이 하나인 배포에서는 그 계정만 토큰을 만들 수 있습니다. |
| 403 | `sso_required` | 배포가 로그인을 자체 ID 공급자로 제한하고 있으며, 이 세션의 계정은 그 공급자를 통해 만들어지지 않았습니다. API 토큰과 OAuth 토큰에는 영향이 없습니다. |

모든 오류는 같은 응답 형식을 사용합니다. 전체 목록은 [오류](https://nodaro.ai/docs/developers/api/errors)를 참조하세요.

## 자주 묻는 질문

### Nodaro API 키는 어떻게 받나요?

Nodaro에 로그인하고 설정 › API 토큰을 연 다음 토큰 만들기를 클릭하세요. 토큰의 이름과 요청 한도를 정한 다음 토큰을 복사하세요. 토큰은 ndr_로 시작하며 한 번만 표시됩니다.

### Nodaro API 토큰은 만료되나요?

아니요. 개인 API 토큰은 비활성화하거나 삭제할 때까지 작동하며, 지출 한도도 없습니다. 비밀번호처럼 보관하고, 더 이상 필요하지 않으면 삭제하세요.

### API 토큰과 OAuth 중 무엇을 써야 하나요?

내 서버가 내 계정으로 Nodaro를 호출할 때는 개인 API 토큰을 사용하세요. 제품을 만들고 각 사용자가 자신의 Nodaro 계정을 연결하게 할 때는 OAuth를 사용하세요.

### 셀프 호스팅 Community Edition에서도 API를 사용할 수 있나요?

네. API 토큰은 Nodaro Cloud와 Business 에디션에서 사용할 수 있습니다. Community Edition 설치에서는 그 대신 로그인한 세션의 JWT를 Bearer 토큰으로 보내세요.

### 브라우저에서 Nodaro API를 호출할 수 있나요?

브라우저 코드에 있는 개인 API 토큰은 누구나 읽을 수 있으므로, 절대 브라우저 코드에 넣지 마세요. 내 서버에서 Nodaro를 호출하거나, OAuth를 사용하고 개발자 앱에 사이트의 출처를 등록하세요.
