SingleFax 인증 문서

API 키, MCP OAuth, 위임 Agent Auth.

AI 에이전트와 개발자를 위한 인증 가이드.

에이전트가 SingleFax에 인증하는 방법. HTML 설치 안내: https://singlefax.com/agents

이 파일은 /.well-known/oauth-authorization-server의 RFC 8414 메타데이터에 명시된 agent_auth.skill 대상입니다.

SingleFax는 사용자 승인과 서비스가 서명한 신원 증명을 사용하는 Auth.md anonymous 및 service_auth 등록을 지원합니다. 익명 자격 증명은 승인 전에 어떤 계정에도 접근할 수 없습니다. 외부 제공업체의 ID-JAG는 허용되지 않습니다. 이전 Better Auth 호스트/에이전트 JWT 흐름은 경로 C에 별도로 설명되어 있습니다.

Auth.md 등록 및 토큰 교환

대상: 기존 SingleFax 계정을 대신해 작업하도록 등록하는 AI 에이전트. 모든 등록 방식에는 소유자가 발급한 등록 허가가 필요합니다. 유효한 등록 허가 토큰이 없는 공개 요청은 등록이 생성되기 전에 거부됩니다. OAuth 발급자는 https://api.singlefax.com/api/auth이며 리소스는 https://singlefax.com/mcp입니다. 등록 자체로 이메일이나 팩스가 발송되거나 결제가 청구되지는 않습니다.

지원 등록 방식: anonymous, service_auth. 자격 증명: identity_assertion, Bearer access_token. 계정 소유자는 SingleFax에 로그인해 요청된 권한을 검토하고 에이전트의 6자리 코드를 입력합니다. 지원 범위는 fax:read, fax:draft, fax:send, inbox:read, credits:read, credits:checkout입니다. 기본 권한은 fax:read 및 credits:read이며, 추가 범위는 명시적으로 요청해야 합니다.

  1. 소유자는 https://singlefax.com/dashboard/agent-access 에 로그인해 에이전트 이름과 허용할 권한을 선택한 뒤 등록 허가 토큰을 명시적으로 생성합니다. 이 임시 비밀값은 한 번만 표시되며 10분 후 만료되고 에이전트 한 개만 등록할 수 있습니다. 해당 에이전트에게 전달하세요. API 프로비저닝은 POST https://singlefax.com/api/auth/agent/identity/manage에서 { "action": "enroll", "name": "My agent", "scopes": ["fax:read", "credits:read"] }과 함께 소유자의 자사 브라우저 세션을 사용합니다. 브라우저 쿠키를 에이전트와 공유하지 않습니다. 소유자는 같은 페이지에서 사용하지 않은 토큰을 취소할 수 있습니다.
  2. POST https://api.singlefax.com/api/auth/agent/identity에 Content-Type: application/json 및 { "type": "service_auth", "enrollment_token": "<owner-issued token>", "login_hint": "<enrolling owner email>" }를 사용해 등록합니다. 응답에는 registration_id, 비밀값 claim_token, 만료 시각, 그리고 user_code, verification_uri, 5초 폴링 간격이 포함된 claim이 반환됩니다. 승인 전에는 신원 증명이 발급되지 않습니다.
  3. 또는 { "type": "anonymous", "enrollment_token": "<owner-issued token>" }으로 등록합니다. 여기서 익명은 계정 연결 전 자격 증명을 뜻하며, 누구나 할 수 있는 공개 가입을 뜻하지 않습니다. 서명된 identity_assertion 및 claim_token가 즉시 반환됩니다. 연결 전 신원 증명을 교환하면 권한 범위가 비어 있는 토큰이 발급되며 어떤 계정에도 접근할 수 없습니다. POST https://api.singlefax.com/api/auth/agent/identity/claim에 { "claim_token": "<secret>", "email": "<account email>" }를 사용해 승인을 시작하고 반환된 claim_attempt를 확인하세요.
  4. 코드를 별도로 표시하고 사용자를 위해 verification_uri을 여세요. URL에는 계정 연결 시도의 비밀 토큰이 포함되므로 해당 URL에 코드를 넣지 마세요. 등록 허가를 발급한 인증된 계정만 승인할 수 있습니다. 이름은 해당 소유자가 정한 값으로 고정됩니다. 요청 범위는 줄일 수 있지만 등록 허가의 권한을 초과할 수는 없습니다. 이메일 힌트와 연결 이메일은 등록 허가를 발급한 소유자와 일치해야 합니다. 사용자는 거절할 수 있습니다. 연결 시도는 10분 후 만료되며 새 연결 시도를 하면 이전 링크는 무효화됩니다. 계정은 자동으로 생성되지 않습니다.
  5. POST https://api.singlefax.com/api/auth/oauth2/token을 Content-Type: application/x-www-form-urlencoded 및 grant_type=urn:workos:agent-auth:grant-type:claim&claim_token=<secret>&resource=https%3A%2F%2Fsinglefax.com%2Fmcp로 폴링하세요. authorization_pending, slow_down(간격을 5초 늘림), expired_token, access_denied을 처리하세요. 승인되면 불투명한 access_token, token_type, expires_in, scope, identity_assertion, assertion_expires가 반환됩니다. 승인 시 연결 전 토큰과 신원 증명은 무효화됩니다.
  6. 부여된 권한 범위로 MCP 또는 A2A에서 Authorization: Bearer <access_token>을 사용하세요. 토큰 수명은 최대 1시간입니다. 갱신하려면 같은 토큰 엔드포인트에 grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<identity_assertion>&resource=https%3A%2F%2Fsinglefax.com%2Fmcp을 사용하세요. 갱신 토큰은 발급되지 않습니다. 등록이 취소되지 않는 한 신원 증명은 최대 30일 동안 다시 교환할 수 있습니다. EdDSA 서명에는 발급자의 /jwks를 사용합니다. typ은 oauth-id-jag+jwt이며 iss/aud은 모두 발급자와 같습니다.
  7. POST https://api.singlefax.com/api/auth/oauth2/revoke과 폼 본문 token=<access_token>&token_type_hint=access_token로 토큰 하나를 취소하세요. 이 작업은 멱등성을 가지며 신원 증명은 계속 사용할 수 있습니다. POST https://api.singlefax.com/api/auth/agent/identity/revoke와 JSON { "identity_assertion": "<identity_assertion>" }으로 등록을 취소하면 모든 액세스 토큰과 이후 교환이 중단됩니다.

계정 소유자는 https://singlefax.com/dashboard/agent-access 에서 권한 부여 내역을 검토하고 취소할 수 있습니다. 등록을 취소하면 관련된 모든 액세스 토큰과 신원 증명을 통한 갱신이 중단됩니다.

계정 연결 및 승인 응답은 비공개이며 절대 캐시할 수 없습니다. 연결 토큰, 신원 증명, 액세스 토큰을 비밀로 유지하세요. 등록 허가 발급은 API 복제본 전체에서 소유자별로 제한되며, 사용하지 않은 활성 토큰은 최대 5개입니다. 등록 허가가 없는 공개 요청은 소유자의 등록 한도를 사용하지 않습니다. 토큰이 없으면 enrollment_required, 만료·취소·사용된 토큰이면 invalid_enrollment이 반환됩니다. 등록에 실패해도 등록 허가 토큰은 소모되지 않습니다. 수동적인 준비 상태 점검 중에는 등록 엔드포인트를 시험 호출하지 마세요.

검색

리소스 서버(MCP + API BFF): https://singlefax.com

GET https://singlefax.com/.well-known/oauth-protected-resource
GET https://singlefax.com/.well-known/oauth-protected-resource/mcp

보호된 리소스 메타데이터(RFC 9728): 루트 문서는 출처(resource https://singlefax.com)를 설명하고, /.well-known/oauth-protected-resource/mcp는 MCP 서버(resource https://singlefax.com/mcp, URL WWW-Authenticate의 대상)를 설명합니다. 두 문서 모두 authorization_servers(발급자 https://api.singlefax.com/api/auth) 및 scopes_supported을 나열합니다. https://singlefax.com/mcp용 토큰을 요청하세요.

GET https://singlefax.com/.well-known/oauth-authorization-server
GET https://singlefax.com/.well-known/oauth-authorization-server/api/auth

인증 서버 메타데이터에는 issuer, authorization_endpoint, token_endpoint, registration_endpoint, jwks_uri, scopes_supported, agent_auth이 포함됩니다(skill이 이곳을 가리킴).

API 출처 https://api.singlefax.com에서도 같은 well-known 문서를 제공합니다.

경로 A. MCP OAuth(채팅 앱)

Cursor, Claude, ChatGPT, Codex, VS Code에는 이 방식을 사용하세요.

  1. MCP https://singlefax.com/mcp(Streamable HTTP)을 추가하세요.
  2. 401 응답을 받으면 WWW-Authenticate을 읽고 위 PRM을 가져오세요.
  3. 동적 클라이언트 등록: POST {issuer}/oauth2/register(PKCE S256, 공개 클라이언트는 token_endpoint_auth_method=none).
  4. {issuer}/oauth2/authorize에서 인증 코드 + PKCE.
  5. {issuer}/oauth2/token에서 토큰.
  6. POST /mcp에 Authorization: Bearer을 사용하세요. 일반적인 서류는 create_upload을 호출하고 사용자에게 uploadPageUrl를 제공한 다음 create_fax_draft에 to 및 uploadToken를 사용하세요. base64은 아주 작은 파일에만 사용합니다. uploadUrl로 PUT할 때는 경로의 HMAC 토큰을 사용하며 OAuth 헤더는 필요하지 않습니다. 원본 Word, Excel, PDF 또는 이미지를 보내세요. 먼저 PDF로 변환하지 마세요.

권한 범위: openid, profile, email, offline_access, fax:read, fax:draft, fax:send, inbox:read, credits:read, credits:checkout. AP2 선불 잔액 구매에는 credits:checkout을 명시적으로 요청하세요. 각 청구에는 여전히 별도의 소유자 패스키 승인이 필요합니다.

인증되지 않은 POST /mcp은 server/discover만 허용합니다. initialize, tools/list, tools/call에는 OAuth가 필요합니다.

경로 A2. A2A(에이전트 간 통신)

에이전트 카드: GET https://singlefax.com/.well-known/agent-card.json(A2A 1.0). 엔드포인트: POST https://singlefax.com/a2a(JSON-RPC: SendMessage, GetTask, CancelTask; 0.3 명칭인 message/send, tasks/get, tasks/cancel도 작동).

  1. 경로 A와 같은 OAuth 서버, 권한 범위, 토큰을 사용하세요(리소스 https://singlefax.com/mcp 요청). Authorization: Bearer을 보내세요. /a2a에서는 DPoP에 바인딩된 토큰을 허용하지 않습니다.
  2. 데이터 파트 하나를 보내세요: { "skill": "<skill id from the card>", "arguments": { ... } }. 자유 형식 텍스트는 해석하지 않습니다.
  3. 팩스와 번호 스킬은 Stripe Checkout 링크(checkoutUrl)를 반환합니다. A2A는 계정의 선불 잔액이나 요금제 페이지를 사용하지 않습니다. 결제 대기 중인 초안의 작업 상태는 input-required입니다. GetTask으로 폴링하세요.

AP2로 선불 잔액을 구매하려면 credits:checkout을 요청하고 판매자 확장을 협상하세요. 서명된 장바구니 및 결제 위임, 별도의 소유자 패스키 승인, Stripe Shared Payment Token 사용, 원장으로 확인된 영수증은 https://singlefax.com/ap2.md 에 설명되어 있습니다.

GetTask에 fax:read을 사용하면 팩스 초안은 팩스 전송을, 번호 구매는 결제와 프로비저닝을 추적합니다. 번호가 활성화되면 번호 작업이 완료됩니다. 선불 잔액 패키지 구매에는 폴링할 주문 기반 작업이 없으므로 결제 후 잔액을 확인하세요.

경로 B. API 키(백엔드 및 CLI)

  1. https://singlefax.com/dashboard/api-keys 에서 키를 만드세요(sf_live_…).
  2. 선불 잔액을 구매하세요.
  3. https://singlefax.com/api/v1/…(또는 https://api.singlefax.com/api/v1/…)에서 Authorization: Bearer sf_live_…을 사용하세요.
  4. CLI: npx @singlefax/cli send FILE --to +E164에 SINGLEFAX_API_KEY를 사용하세요. 원본 Word, Excel, PDF 또는 이미지를 전달하고 먼저 PDF로 변환하지 마세요.

언어별 예시(curl, Node, Python, Go, PHP): https://singlefax.com/developers.md

OpenAPI: https://singlefax.com/openapi.json

경로 C. Better Auth 위임 호스트/에이전트 JWT

위임 기능(validate_fax, send_fax, get_fax_status, get_credits, create_credit_checkout)은 기기 승인을 사용합니다.

  1. GET https://api.singlefax.com/.well-known/agent-configuration에서 알고리즘, 엔드포인트, 모드, 승인 방식을 확인하세요. **Agent Auth 발급자는 https://api.singlefax.com**이며, /api/auth로 끝나는 OAuth 발급자와 다릅니다. 이 출처를 JWT 대상자로 사용하세요. 지원되는 알고리즘으로 호스트와 에이전트의 서명 키를 각각 생성하고 비공개 키를 비밀로 유지하세요.
  2. 호스트를 먼저 프로비저닝하세요. 동적 호스트 등록은 비활성화되어 있습니다. 계정 소유자는 SingleFax에 로그인하고 자사 브라우저 세션으로 POST https://singlefax.com/api/auth/host/create(API 출처의 동일 기능: https://api.singlefax.com/api/auth/host/create)을 호출해야 합니다. { "name": "My agent host", "public_key": <host public JWK>, "default_capabilities": [] }를 제공하세요. 응답의 hostId는 등록된 호스트를 식별합니다. 기본값이 비어 있어 각 기능은 별도 승인을 요구합니다. 또는 public_key을 생략하면 만료 시간이 있는 일회용 enrollmentToken을 받을 수 있습니다. 이후 호스트가 POST https://api.singlefax.com/api/auth/host/enroll을 { "token": <enrollment token>, "public_key": <host public JWK>, "name": "My agent host" }로 호출합니다. 브라우저 쿠키나 비공개 서명 키를 에이전트와 절대 공유하지 마세요.
  3. POST https://api.singlefax.com/api/auth/agent/register에서 등록하세요. Authorization: Bearer <signed host+jwt>과 JSON { "name": "My agent", "mode": "delegated", "capabilities": ["validate_fax", "get_fax_status", "get_credits"], "preferred_method": "device_authorization", "force_approval": true }를 보내세요. JWT 헤더에는 typ: "host+jwt"과 지원되는 alg를 사용합니다(서명 JWK에 kid가 있으면 함께 사용). 클레임에는 iss: <registered hostId>, aud: "https://api.singlefax.com", 새 jti, 현재 iat, 60초 이내의 exp, agent_public_key: <agent public JWK>을 포함합니다. 프로비저닝된 호스트 키로 서명하세요. 재사용한 JWT 식별자는 거부됩니다.
  4. 등록 응답에는 agent_id, host_id, 상태, 기능 권한 부여 내역, 필요한 경우 approval 객체가 반환됩니다. 기기 코드를 표시하고 SingleFax 사이트에서 verification_uri_complete를 여세요. 사용자가 로그인한 뒤 반환된 인증 URL에서 승인합니다. 등록, 프로비저닝, 승인은 계정 상태를 변경하므로 수동적인 스캐너는 검색 문서만 읽어야 합니다.
  5. 새 호스트 JWT(iss: <host_id>)로 GET https://api.singlefax.com/api/auth/agent/status?agent_id=<registered id>을 폴링하세요. 승인 후 에이전트의 비공개 키로 에이전트 JWT를 서명하세요. 헤더에는 typ: "agent+jwt"과 지원되는 alg/kid, 클레임에는 iss: <host_id>, sub: <agent_id>, aud: "https://api.singlefax.com", 현재 iat, 60초 이내의 exp, 새 jti을 사용합니다. POST https://api.singlefax.com/api/auth/capability/execute을 Authorization: Bearer <signed agent+jwt> 및 { "capability": "get_credits", "arguments": {} }로 호출하거나 문서화된 인수를 사용해 부여된 다른 기능을 호출하세요. 이 자격 증명은 서명된 증명이며 API 키나 OAuth 액세스 토큰이 아닙니다.
  6. 등록된 에이전트의 새 기기 코드를 받으려면 POST https://api.singlefax.com/api/auth/agent/device/code에 { "agent_id": "<registered id>" }과 서명된 호스트 JWT를 사용하세요. 이 엔드포인트로 에이전트를 등록할 수는 없습니다. POST https://api.singlefax.com/api/auth/agent/revoke에 { "agent_id": "<registered id>" }과 소유 호스트의 JWT 또는 소유자 세션을 사용해 취소하세요. send_fax에는 패스키를 통한 사용자 확인이 필요하며 자율적으로 실행되지 않습니다.

여기에 ID-JAG나 { "type": "anonymous" }을 POST하지 마세요. 이 신원 유형은 지원되지 않습니다.

기계 결제(OAuth 아님)

자율 결제는 POST /api/v1/machine/faxes에서 Stripe Shared Payment Token 또는 Tempo USDC를 사용하는 MPP HTTP 402 방식입니다. https://singlefax.com/mpp.md 를 확인하세요. Cursor는 SPT를 발급할 수 없습니다. /mcp이 아니라 해당 REST URL을 대상으로 Stripe Link CLI를 사용하세요. Tempo 지갑은 같은 URL의 Tempo 결제 요청을 결제합니다.

HIPAA

MCP, MPP 또는 공개 API로 PHI를 보내지 마세요. HIPAA 적용 대상 기관은 웹사이트에서 전자 BAA가 포함된 HIPAA Secure 모드를 사용합니다.