본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 22. 06:15

Mastra의 인증 라인업에 Kinde가 없어서 직접 프로바이더를 만들었습니다

요약

TypeScript 기반 AI 에이전트 프레임워크인 Mastra에서 Kinde 인증 프로바이더를 사용할 수 있도록 직접 구현한 방법을 소개합니다. Kinde의 조직 구조와 멀티 테넌시 기능을 활용하여 B2B SaaS AI 에이전트를 구축하는 가이드를 제공합니다.

핵심 포인트

  • Mastra의 MastraAuthProvider를 확장하여 Kinde 인증 구현 가능
  • Kinde의 조직(org) 모델을 활용한 멀티 테넌시 에이전트 구축
  • JWT 검증 및 사용자 권한 부여를 통한 API와 UI 보호
  • 머신 투 머신(M2M) 인증을 통한 백그라운드 에이전트 작업 지원

SaaS AI 에이전트 제품을 구축 중이고 이미 Kinde를 사용하고 있다면, 여러분은 이미 그 문제를 알고 있을 것입니다.

Mastra는 TypeScript 우선(TypeScript-first) AI 에이전트 프레임워크입니다. Mastra는 Clerk, Auth0, Supabase, Firebase, WorkOS, 그리고 Better Auth를 위한 공식 인증 (auth) 프로바이더를 함께 제공합니다. 하지만 Kinde는 그 목록에 없습니다.

당연한 질문이 생길 것입니다. Auth0가 이미 있는데 왜 다른 프로바이더를 사용하지 않느냐는 것이죠.

Kinde를 선택하는 대부분의 개발자는 단순히 로그인 기능 그 이상에 의존합니다. Kinde는 제품에 실제로 필요한 조직 구조 (organizational structures), 권한 시스템 (permission systems), 그리고 수익화 도구 (monetization tools)를 함께 제공하며, 인증 (auth), 결제 (billing), 피처 플래그 (feature flags), 그리고 멀티 테넌시 (multi-tenancy)를 하나의 플랫폼으로 통합합니다. 만약 여러분이 Kinde 기반으로 B2B SaaS 제품을 구축하고 있다면, 고객을 세분화하기 위해 Kinde orgs를 사용하고, 구독 관리를 위해 Kinde billing을 사용하며, 플랜별로 기능을 제한하기 위해 Kinde feature flags를 사용하고 있을 것입니다. Mastra 에이전트를 지원하기 위해 Auth0나 Clerk으로 전환한다는 것은 이 모든 것을 다른 곳에서 다시 구축해야 한다는 의미이며, 이는 현실적인 선택지가 아닙니다.

그 간극이 바로 문제입니다. Mastra와 함께 Kinde를 사용해야 하지만, 지금까지는 이 둘을 연결할 깔끔한 방법이 없었습니다.

그래서 제가 mastra-auth-kinde를 만들었습니다.

Mastra의 인증 시스템이 실제로 하는 일

Mastra에 인증 프로바이더를 추가하면, 두 가지를 동시에 보호합니다: 모든 API 라우트 (/api/agents/*, /api/workflows/* 등)와 Mastra Studio UI입니다. 보호된 라우트로 가는 모든 요청은 다른 곳에 도달하기 전에 프로바이더를 거치게 됩니다.

여러분은 Mastra의 MastraAuthProvider 기본 클래스를 확장하고 두 가지 메서드를 구현합니다:

  • authenticateToken(token, request)는 JWT를 검증하고 디코딩된 사용자 정보를 반환하며, 실패 시 null을 반환합니다.
  • authorizeUser(user, request)는 요청을 허용하려면 true를, 403 에러를 내려면 false를 반환합니다.

Mastra는 그 외의 모든 것을 처리합니다: Authorization 헤더에서 Bearer 토큰을 추출하고, 여러분의 메서드를 순서대로 호출하며, 검증된 사용자를 요청 컨텍스트 (request context)에 저장하여 에이전트와 도구들이 이에 접근할 수 있도록 합니다.

왜 하필 Kinde인가

위에서 언급한 결제 및 조직(org) 관련 이야기 외에도, 몇 가지 요소가 특히 에이전트 개발자들에게 Kinde가 적합한 이유를 만들어줍니다.

첫째, Kinde의 조직(org) 모델은 멀티 테넌시 (multi-tenancy)에 직접적으로 매핑되므로, 개발자가 직접 구축하지 않아도 각 고객이 격리된 데이터와 설정을 가질 수 있습니다. 각 Kinde 조직은 하나의 테넌트(tenant)이며, 모든 토큰의 org_code 클레임 (claim)은 사용자가 정확히 어떤 조직에 속해 있는지를 알려줍니다. 동일한 인프라에서 서로 다른 고객에게 서비스를 제공하는 멀티 테넌트 에이전트에게는 바로 이것이 필요합니다.

둘째, 머신 투 머신 (machine-to-machine) 인증이 값비싼 추가 기능이 아닌 표준 사양으로 제공됩니다. AI 에이전트는 인간 사용자의 개입 없이 백그라운드 작업, 예약된 워크플로우 (workflows), 야간 파이프라인 (pipelines)을 실행해야 하는 경우가 빈번합니다. Kinde는 클라이언트 자격 증명 토큰 (client credentials tokens)을 통해 이를 네이티브하게 처리하며, 이 프로바이더 (provider) 또한 아래에서 설명할 해당 기능을 처리합니다.

셋째, 무료 티어 (free tier)가 실제 제품에 사용 가능할 정도로 강력합니다. 여기에는 월간 활성 사용자 (MAU) 10,500명, 무제한 조직, 그리고 SSO를 포함한 모든 인증 방식이 포함됩니다. 규모가 커지기 전까지는 비용을 전혀 지불하지 않고도 실제 멀티 테넌트 에이전트 제품을 구축할 수 있습니다.

설치 (Installation)

npm install github:sholajegede/mastra-auth-kinde

이미 설치되어 있지 않다면 @mastra/core도 필요합니다:

npm install @mastra/core

1단계 — 기본 설정 (Basic setup)

프로바이더를 Mastra 인스턴스에 연결합니다:

import { Mastra } from '@mastra/core'
import { MastraAuthKinde } from 'mastra-auth-kinde'

...

또는 환경 변수 (environment variables)를 사용하세요:

KINDE_DOMAIN=https://yourapp.kinde.com
KINDE_AUDIENCE=https://api.yourapp.com  # 선택 사항 — 아래의 audience 섹션 참조
export const mastra = new Mastra({
  server: {
    auth: new MastraAuthKinde(),
...

이 설정이 완료되면, /api/*로 가는 모든 요청은 Authorization: Bearer <token> 헤더에 유효한 Kinde 액세스 토큰 (access token)을 포함해야 합니다. 인증되지 않은 요청은 401을 받게 되며, 권한 확인에 실패한 요청은 403을 받게 됩니다.

2단계 — 사용자 토큰 인증 (User token authentication)

표준적인 Kinde 사용자 액세스 토큰 (user access token)은 다음과 같은 클레임 (claims)을 포함합니다:

iss, sub, aud, azp, exp, iat, jti, scp

프로바이더 (provider)는 Kinde의 JWKS 엔드포인트 (endpoint)를 통해 토큰을 검증하고, 발행자 (issuer)와 만료 시간 (expiry)을 확인하며, 해당 옵션이 설정되어 있는 경우 오디언스 (audience) 클레임을 체크합니다.

Kinde's JWKS 엔드포인트는 일반적으로 /.well-known/jwks.json이라고 가정하는 것과 달리, .json 확장자가 없는 /.well-known/jwks 경로에 위치합니다. 당연하게 여기기 전에 귀하의 테넌트 (tenant) 디스커버리 문서 (discovery document)를 통해 확인하십시오:

curl -s https://yourapp.kinde.com/.well-known/openid-configuration | jq .jwks_uri
# "https://yourapp.kinde.com/.well-known/jwks"

프로바이더는 이 부분을 별도의 설정 없이도 올바르게 처리합니다.

오디언스 (audience) 옵션

audience (또는 KINDE_AUDIENCE)는 Kinde 대시보드에서 API 오디언스를 등록하고 바인딩 (binding)한 후에만 설정하십시오. 기본 Kinde 사용자 토큰은 비어 있는 aud 배열을 포함하며, 옵션이 설정되어 있을 때 aud가 비어 있는 토큰은 오디언스 체크를 통과하지 못합니다.

new MastraAuthKinde({
  domain: 'https://yourapp.kinde.com',
  audience: 'https://api.yourapp.com', // Kinde에서 API 오디언스를 바인딩한 후에만 이 부분을 추가하세요
...

3단계 — M2M / 시스템 액터 (system-actor) 지원

표준적인 에이전트 (agent) 설정에서는 사람이 로그인하고, 프론트엔드 (frontend)가 토큰을 받으며, 그 토큰이 Mastra API로 전달됩니다. 이는 사용자 대상 에이전트에게 적합합니다. 실제 에이전트 아키텍처 (architecture)에는 사람이 개입하지 않고 실행되는 야간 워크플로우 (nightly workflows), 예약된 파이프라인 (scheduled pipelines), 크론 작업 (cron tasks)과 같은 백그라운드 작업 (background jobs)도 존재합니다.

Kinde는 OAuth 클라이언트 자격 증명 흐름 (client credentials flow)을 사용하는 머신 투 머신 (machine-to-machine, M2M) 앱을 통해 이를 처리합니다. 결과로 생성된 토큰은 사용자 토큰과 형태가 다릅니다:

{
  "aud": ["https://yourapp.kinde.com/api"],
  "azp": "your_client_id",
...

주의해야 할 두 가지 사항이 있습니다. sub 클레임(claim)이 없으며, gty 클레임이 ["client_credentials"]로 설정되어 있다는 점입니다. 이 조합은 이것이 사람이 아닌 머신(machine)임을 알려줍니다.

프로바이더(provider)는 이를 감지하여 토큰을 거부하는 대신 신뢰할 수 있는 시스템 액터(system actor)로 취급합니다. 에이전트 도구(agent tools)나 라우트 핸들러(route handlers)에서 이를 확인할 수 있습니다:

import { isSystemActor } from 'mastra-auth-kinde'

const user = requestContext.get('user')
...

따라서 야간 워크플로(nightly workflow)가 Kinde M2M 토큰을 발행하여 Mastra API에 전달하면, 별도의 사용자 개입 없이도 깔끔하게 인증을 수행할 수 있습니다.

4단계 — 조직 기반 액세스 제어 (Org-based access control)

서로 다른 조직이 각자의 에이전트와 데이터에만 접근해야 하는 멀티 테넌트(multi-tenant) 제품을 구축 중이라면, allowedOrgCodes를 사용하세요:

new MastraAuthKinde({
  domain: 'https://yourapp.kinde.com',
  allowedOrgCodes: ['org_abc123', 'org_def456'],
...

프로바이더는 모든 토큰의 org_code 클레임을 확인하며, 일치하지 않는 것은 모두 거부합니다. 이는 사용자 토큰(Kinde에서 조직 클레임이 활성화된 경우)과 M2M 토큰 모두에 적용됩니다. M2M 토큰은 앱이 Kinde에서 조직 범위(org-scoped)로 설정되어 있을 때 org_code를 자동으로 포함합니다.

사용자 토큰의 경우, Kinde 대시보드의 토큰 커스텀 설정에서 조직 클레임을 활성화해야만 org_code가 나타납니다. 따라서 기본 사용자 토큰을 디코딩했을 때 해당 클레임이 없다면, 이는 프로바이더의 버그가 아니라 Kinde 설정 단계의 문제입니다.

5단계 — 엣지 배포 (Edge deployment)

프로바이더는 JWT 검증을 위해 jose를 사용합니다. 이는 Web Crypto와 fetch 위에서 동작하며, Node.js 내장 기능(built-ins)을 사용하지 않으므로 Cloudflare Workers에서 nodejs_compat 플래그가 필요하지 않습니다.

이는 Mastra 에이전트를 엣지(edge)에 배포할 계획이라면 매우 중요한 사항입니다. Node 전용 JWKS 라이브러리는 crypto, buffer, stream, http, https, events, util이 없는 Workers 환경의 빌드 타임에서 실패합니다. jose를 사용하면 추가 플래그 없이도 깔끔하게 빌드되고 실행됩니다. 이는 Mastra 자체의 Auth0 프로바이더가 사용하는 것과 동일한 방식입니다.

종합하기

다음은 인간 사용자(human users)와 백그라운드 M2M 워크플로우(background M2M workflows)를 모두 지원하는 멀티 테넌트(multi-tenant) Mastra 에이전트의 전체 설정입니다:

import { Mastra } from '@mastra/core'
import { Agent } from '@mastra/core/agent'
import { openai } from '@ai-sdk/openai'
...

프론트엔드에서는 Kinde SDK로부터 액세스 토큰(access token)을 가져와 Bearer 토큰으로 전달합니다:

import { useKindeAuth } from '@kinde-oss/kinde-auth-nextjs'

const { getToken } = useKindeAuth()
...

백그라운드 워크플로우의 경우, 클라이언트 자격 증명 흐름(client credentials flow)을 통해 M2M 토큰을 가져옵니다:

// 서버 측 전용 — 브라우저에 client_secret을 절대 노출하지 마세요
const tokenResponse = await fetch(
  `${process.env.KINDE_DOMAIN}/oauth2/token`,
...

두 토큰 유형 모두 동일한 프로바이더(provider), 동일한 API, 그리고 동일한 Mastra 인스턴스를 통해 작동합니다.

프로바이더가 내보내는 것 (What the provider exports)

import {
  MastraAuthKinde,  // 메인 인증 프로바이더 클래스
  isSystemActor,    // M2M / 클라이언트 자격 증명 토큰인 경우 true 반환
...

전체 옵션:

new MastraAuthKinde({
  domain: 'https://yourapp.kinde.com',     // 필수
  audience: 'https://api.yourapp.com',      // 선택 사항 — Kinde에서 바인딩한 후에만 설정
...

다음 단계

이 프로바이더는 오픈 소스이며 지금 바로 github.com/sholajegede/mastra-auth-kinde에서 사용할 수 있습니다.

Kinde는 월간 활성 사용자(MAU) 10,500명까지 무료이며, 시작 시 신용카드가 필요하지 않습니다. 계정을 생성하고 kinde.com에서 테스트 조직을 대상으로 이 프로바이더를 시도해 볼 수 있습니다.

이 글이 시간을 절약해 주었다면 리액션을 남겨주세요. 그리고 Mastra 에이전트로 무언가를 만들고 계신다면, 댓글로 들려주시면 감사하겠습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0