Nodaro 문서
문서노드 레퍼런스모델템플릿AI 에이전트(MCP)개발자셀프 호스팅리서치비교
TypeScript SDK

인증

StaticTokenAuth, CallbackAuth, supabaseAuth 중에서 Nodaro SDK의 인증 방식을 고르고, 하위 도메인 사이에서 브라우저 로그인 하나를 공유하세요.

인증 공급자는 Nodaro SDK에 어떤 토큰을 보낼지 알려 줍니다. 클라이언트는 모든 요청 전에 공급자의 getToken()을 호출하고, 그 결과를 Authorization: Bearer <token>으로 보냅니다. 공급자가 null을 반환하면 요청은 헤더 없이 익명 요청으로 전송됩니다.

공급자 선택

공급자용도토큰의 출처
StaticTokenAuth서버 코드, 스크립트, 예약된 작업고정된 API 토큰 또는 OAuth 액세스 토큰
CallbackAuth만료되어 갱신이 필요한 토큰, 사용자 지정 세션 저장소모든 요청 전에 호출되는 내 함수
supabaseAuth사용자가 같은 Nodaro 인스턴스에 로그인하는 브라우저 앱자동으로 갱신되는 사용자의 현재 세션
직접 만든 객체그 밖의 모든 경우getToken() 메서드가 있는 모든 객체

사용할 수 있는 토큰

토큰형태누구로서 작동하는지받는 곳
API 토큰ndr_ 뒤에 16진수 64자나Nodaro의 설정 › API 토큰
OAuth 액세스 토큰ndr_app_ 뒤에 16진수 64자내 앱을 승인한 사용자OAuth 코드 교환, client.oauth.exchangeCode()
세션 토큰로그인한 세션로그인한 사용자supabaseAuth를 통한 Nodaro 로그인
  • API 토큰은 지출 한도가 없는 영구 자격 증명입니다. 비활성화하거나 삭제할 때까지 작동하므로 서버에 보관하세요. 한도와 요청 한도 설정은 API 인증을 참조하세요.
  • OAuth 액세스 토큰에는 사용자가 승인한 범위만 들어 있습니다. 내 앱이 다른 사람을 대신해 작동할 때 사용하세요. OAuth를 참조하세요.
  • 셀프 호스팅 Community Edition 설치에서는 앱이 API 토큰을 제공하지 않습니다. 대신 로그인해서 supabaseAuth나 CallbackAuth로 내 세션 토큰을 사용하세요.

Auth 인터페이스

interface Auth {
  getToken(): Promise<string | null>
}

이 형태를 가진 객체는 무엇이든 createClient의 auth 옵션이 될 수 있습니다. 아래의 세 공급자가 이 인터페이스를 구현합니다.

StaticTokenAuth

new StaticTokenAuth(token: string)

고정된 토큰 하나를 감쌉니다. 프로세스가 실행되는 동안 토큰이 바뀌지 않을 때 사용하세요. API 토큰이나, 내 서버가 인증 코드 흐름으로 받은 OAuth 액세스 토큰이 여기에 해당합니다.

속성

타입

import { createClient, StaticTokenAuth } from "@nodaro/sdk"

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

CallbackAuth

new CallbackAuth(fn: () => string | null | Promise<string | null>)

모든 요청 전에 내 함수를 호출하고, 함수가 반환한 토큰을 보냅니다. 함수는 동기 함수일 수도, 비동기 함수일 수도 있습니다. 토큰 없이 요청을 보내려면 null을 반환하세요.

속성

타입

토큰을 갱신하거나, 사용자 지정 세션 저장소를 읽거나, 자격 증명을 교체할 때 사용하세요.

import { createClient, CallbackAuth } from "@nodaro/sdk"

const client = createClient({
  baseUrl: "https://app.nodaro.ai",
  auth: new CallbackAuth(async () => {
    const session = await sessionStore.read()
    if (!session) return null
    if (Date.now() > session.expiresAt - 60_000) {
      await refresh(session)
    }
    return session.accessToken
  }),
})

supabaseAuth(supabase)

supabaseAuth(supabase: SupabaseLikeClient): Auth

모든 요청 전에 Supabase v2 클라이언트에서 로그인한 사용자의 토큰을 읽습니다. 사용자가 같은 Nodaro 인스턴스에 로그인하는 브라우저 앱, 예를 들어 셀프 호스팅 설치용으로 직접 만든 프런트엔드에서 사용하세요. Nodaro 편집기도 같은 공급자를 사용합니다. 토큰을 실시간으로 읽으므로, 갱신된 세션이 자동으로 반영됩니다.

속성

타입

import { createClient, supabaseAuth } from "@nodaro/sdk"
import { createClient as createSupabase } from "@supabase/supabase-js"

const supabase = createSupabase(
  import.meta.env.VITE_SUPABASE_URL,
  import.meta.env.VITE_SUPABASE_ANON_KEY,
)

const client = createClient({
  baseUrl: import.meta.env.VITE_API_URL ?? "",
  auth: supabaseAuth(supabase),
})

아무도 로그인하지 않았으면 요청은 토큰 없이 전송됩니다.

createSharedSupabaseClient(options)

import { createSharedSupabaseClient } from "@nodaro/sdk/supabase"

createSharedSupabaseClient<Db = any>(options: {
  url: string
  anonKey: string
  cookieDomain?: string
}): SupabaseClient<Db>

세션을 로컬 저장소 대신 쿠키에 보관하는 브라우저용 Supabase 클라이언트를 만듭니다. cookieDomain을 쓰면 형제 하위 도메인에 있는 여러 앱이 로그인 하나를 공유합니다. 한 곳에서 로그인한 사용자는 모든 곳에 로그인되고, 어디서든 로그아웃하면 모든 곳에서 로그아웃됩니다.

속성

타입

import { createClient, supabaseAuth } from "@nodaro/sdk"
import { createSharedSupabaseClient } from "@nodaro/sdk/supabase"

const supabase = createSharedSupabaseClient({
  url: SUPABASE_URL,
  anonKey: SUPABASE_ANON_KEY,
  cookieDomain: ".example.com",
})

const client = createClient({ baseUrl: "", auth: supabaseAuth(supabase) })
  • cookieDomain은 페이지의 호스트가 그 도메인이거나 그 하위 도메인일 때만 적용됩니다. localhost나 미리보기 URL 같은 다른 호스트에서는 쿠키가 현재 호스트에 머무르므로, 로컬 개발에서는 출처마다 별도의 세션이 유지됩니다.
  • 처음 불러올 때 로컬 저장소에 있던 기존 세션이 쿠키로 옮겨지고, 이전 항목은 삭제됩니다. 이미 로그인해 있던 사용자는 로그인 상태가 유지됩니다. 만료된 세션은 버려집니다.
  • 이 내보내기는 별도 경로인 @nodaro/sdk/supabase에 있으므로, 기본 패키지는 Supabase에 의존하지 않습니다. 사용하려면 @supabase/supabase-js와 @supabase/ssr을 설치하세요.

범위와 누락된 권한

OAuth 액세스 토큰에는 workflows:read나 workflows:execute처럼 사용자가 승인한 범위가 들어 있습니다. 각 리소스의 레퍼런스 페이지에 그 메서드에 필요한 범위가 나와 있습니다. 토큰에 필요한 범위가 없으면 메서드는 missingScope에 그 범위를 담은 ForbiddenError를 발생시킵니다.

import { ForbiddenError } from "@nodaro/sdk"

try {
  await client.workflows.run(workflowId)
} catch (err) {
  if (err instanceof ForbiddenError && err.missingScope) {
    requestConsentFor([err.missingScope]) // send the user through OAuth again
  } else {
    throw err
  }
}

API 토큰과 세션 토큰은 범위의 제한을 받지 않습니다. 모든 오류 클래스는 오류를 참조하세요.

브라우저 규칙

  • API 토큰을 브라우저로 보내지 마세요. 누구나 페이지에서 읽을 수 있고, 그 토큰은 나로서 작동합니다.
  • 브라우저의 OAuth 토큰은 내 개발자 앱의 allowedOrigins에 나열된 출처에서만 작동합니다. OAuth와 개발자 앱을 참조하세요.
  • supabaseAuth의 세션 토큰은 그 목록으로 검사하지 않습니다.
  • 비밀 값은 서버에 두세요. OAuth 코드 교환에는 클라이언트 시크릿이 필요하므로, client.oauth.exchangeCode()는 서버 코드에서만 실행하세요.

자주 묻는 질문

서버에서는 어떤 인증 공급자를 사용해야 하나요?

StaticTokenAuth입니다. 환경 변수에서 읽은, ndr_로 시작하는 API 토큰이나 ndr_app_로 시작하는 OAuth 액세스 토큰을 전달하세요.

SDK로 만료되는 토큰을 갱신하려면 어떻게 하나요?

CallbackAuth를 사용하세요. SDK가 모든 요청 전에 내 함수를 호출하므로, 함수가 만료 시각을 확인하고 토큰을 갱신한 뒤 새 토큰을 반환할 수 있습니다.

브라우저 앱에 API 토큰을 넣어도 되나요?

아니요. API 토큰은 지출 한도 없이 나로서 작동하며, 누구나 브라우저 코드에서 읽을 수 있습니다. 브라우저에서는 사용자를 로그인시켜 그 세션을 사용하거나, OAuth를 사용하세요.

ForbiddenError.missingScope는 무슨 뜻인가요?

OAuth 토큰은 유효하지만 엔드포인트에 필요한 범위, 예를 들어 workflows:execute를 허락받지 못했다는 뜻입니다. 사용자에게 그 범위를 허락해 달라고 요청한 다음, 새 토큰으로 다시 시도하세요.

최종 업데이트

목차