Documentazione autenticazione SingleFax

Chiavi API, OAuth per MCP e Agent Auth delegato.

Guida all’autenticazione per agenti AI e sviluppatori.

Come gli agenti si autenticano su SingleFax. Installazione HTML: https://singlefax.com/agents

Questo file è la destinazione agent_auth.skill indicata nei metadati RFC 8414 su /.well-known/oauth-authorization-server.

SingleFax supporta registrazione Auth.md anonymous e service_auth, con approvazione utente e attestazioni d’identità firmate dal servizio. Le credenziali anonime non accedono ad account prima dell’approvazione. Gli ID-JAG di fornitori esterni non sono accettati. Il precedente flusso JWT host/agente Better Auth è nel Percorso C.

Registrazione Auth.md e scambio token

Destinatari: agenti AI che si registrano per un account SingleFax esistente. Ogni metodo richiede un’autorizzazione di registrazione emessa dal titolare. Richieste pubbliche senza token valido sono respinte prima di creare la registrazione. Issuer OAuth: https://api.singlefax.com/api/auth; risorsa: https://singlefax.com/mcp. Registrarsi non invia email o fax e non addebita pagamenti.

Metodi: anonymous e service_auth. Credenziali: identity_assertion e Bearer access_token. Il titolare accede, verifica i permessi e inserisce il codice a sei cifre dell’agente. Scope supportati: fax:read, fax:draft, fax:send, inbox:read, credits:read, credits:checkout. Predefiniti: fax:read e credits:read; richiedi esplicitamente gli altri.

  1. Il titolare accede a https://singlefax.com/dashboard/agent-access, sceglie nome e permessi e crea esplicitamente un token di registrazione. Il segreto è mostrato una volta, scade in dieci minuti e registra un solo agente. Consegnalo a quell’agente. Il provisioning API usa la sessione browser proprietaria su POST https://singlefax.com/api/auth/agent/identity/manage con { "action": "enroll", "name": "My agent", "scopes": ["fax:read", "credits:read"] }. I cookie non vengono mai condivisi con l’agente. I token inutilizzati sono revocabili dalla stessa pagina.
  2. Registrati con POST https://api.singlefax.com/api/auth/agent/identity, Content-Type: application/json e { "type": "service_auth", "enrollment_token": "<owner-issued token>", "login_hint": "<enrolling owner email>" }. Ricevi registration_id, il segreto claim_token, scadenza e claim con user_code, verification_uri e intervallo di polling di cinque secondi. Nessuna attestazione prima dell’approvazione.
  3. In alternativa usa { "type": "anonymous", "enrollment_token": "<owner-issued token>" }. Anonimo descrive la credenziale prima dell’associazione, non una registrazione pubblica aperta. Ricevi subito identity_assertion firmato e claim_token. Scambiando l’attestazione preliminare ottieni un token senza scope, incapace di accedere ad account. Avvia l’approvazione con POST https://api.singlefax.com/api/auth/agent/identity/claim e { "claim_token": "<secret>", "email": "<account email>" }; leggi claim_attempt restituito.
  4. Mostra il codice separatamente e apri verification_uri per l’utente. L’URL contiene un token segreto di associazione: non aggiungere il codice all’URL. Solo l’account verificato che ha avviato la registrazione può approvare. Nome fissato dal titolare; scope riducibili, mai oltre i permessi iniziali. Email suggerita e di associazione devono coincidere con il titolare. L’utente può rifiutare. Scadenza dieci minuti; un nuovo tentativo invalida il vecchio link. Nessun account creato automaticamente.
  5. Interroga POST https://api.singlefax.com/api/auth/oauth2/token con Content-Type: application/x-www-form-urlencoded e grant_type=urn:workos:agent-auth:grant-type:claim&claim_token=<secret>&resource=https%3A%2F%2Fsinglefax.com%2Fmcp. Gestisci authorization_pending, slow_down (aumenta l’intervallo di cinque secondi), expired_token, access_denied. L’approvazione restituisce access_token opaco, token_type, expires_in, scope, identity_assertion, assertion_expires. Token e attestazioni preliminari vengono invalidati.
  6. Usa Authorization: Bearer <access_token> su MCP o A2A con gli scope concessi. I token durano al massimo un’ora. Per rinnovare usa lo stesso endpoint con grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<identity_assertion>&resource=https%3A%2F%2Fsinglefax.com%2Fmcp; non viene emesso refresh token. Le attestazioni sono riscambiabili fino a 30 giorni salvo revoca. Le firme EdDSA usano /jwks dell’issuer; typ è oauth-id-jag+jwt, e iss/aud coincidono con l’issuer.
  7. Revoca un token con POST https://api.singlefax.com/api/auth/oauth2/revoke, corpo form token=<access_token>&token_type_hint=access_token. È idempotente e lascia utilizzabile l’attestazione. Revoca la registrazione con POST https://api.singlefax.com/api/auth/agent/identity/revoke, JSON { "identity_assertion": "<identity_assertion>" }: cessano tutti i token e scambi successivi.

Il titolare può verificare e revocare i permessi su https://singlefax.com/dashboard/agent-access. Revocare la registrazione blocca tutti i token collegati e rinnovi delle attestazioni.

Le risposte di associazione e approvazione sono private e mai memorizzabili in cache. Proteggi token, attestazioni e access token. L’emissione è limitata per titolare tra tutte le repliche API, con massimo cinque token attivi inutilizzati. Le richieste pubbliche senza autorizzazione non consumano la quota del titolare. Token mancanti restituiscono enrollment_required; scaduti, revocati o consumati invalid_enrollment. Una registrazione fallita non consuma il token. Non sondare endpoint di registrazione nelle scansioni passive.

Discovery

Server risorse (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

Metadati risorsa protetta (RFC 9728): il documento radice descrive l’origine (resource https://singlefax.com); /.well-known/oauth-protected-resource/mcp descrive MCP (resource https://singlefax.com/mcp, destinazione dell’URL WWW-Authenticate). Entrambi elencano authorization_servers (issuer https://api.singlefax.com/api/auth) e scopes_supported. Richiedi token per https://singlefax.com/mcp.

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

I metadati del server autorizzativo includono issuer, authorization_endpoint, token_endpoint, registration_endpoint, jwks_uri, scopes_supported, agent_auth (skill rimanda qui).

L’origine API https://api.singlefax.com espone gli stessi documenti well-known.

Percorso A. MCP OAuth (chat)

Usalo per Cursor, Claude, ChatGPT, Codex e VS Code.

  1. Aggiungi MCP https://singlefax.com/mcp (Streamable HTTP).
  2. Su 401 leggi WWW-Authenticate e recupera PRM sopra.
  3. Registrazione client dinamica: POST {issuer}/oauth2/register (PKCE S256, token_endpoint_auth_method=none per client pubblici).
  4. Codice autorizzativo + PKCE su {issuer}/oauth2/authorize.
  5. Token su {issuer}/oauth2/token.
  6. POST /mcp con Authorization: Bearer. Per documenti normali chiama create_upload, dai all’utente uploadPageUrl, poi create_fax_draft con to e uploadToken. base64 solo per file minimi. PUT a uploadUrl usa il token HMAC nel percorso, senza header OAuth. Invia Word, Excel, PDF o immagine originali, senza conversione preventiva.

Scope: openid, profile, email, offline_access, fax:read, fax:draft, fax:send, inbox:read, credits:read, credits:checkout. Richiedi credits:checkout per acquisti crediti AP2; ogni addebito richiede comunque approvazione passkey separata.

Senza autenticazione POST /mcp accetta solo server/discover. initialize, tools/list, tools/call richiedono OAuth.

Percorso A2. A2A (agente-agente)

Scheda agente: GET https://singlefax.com/.well-known/agent-card.json (A2A 1.0). Endpoint: POST https://singlefax.com/a2a (JSON-RPC: SendMessage, GetTask, CancelTask; funzionano anche i nomi 0.3 message/send, tasks/get, tasks/cancel).

  1. Usa server OAuth, scope e token del Percorso A (risorsa https://singlefax.com/mcp). Invia Authorization: Bearer. Token vincolati DPoP non accettati su /a2a.
  2. Invia una sola parte dati: { "skill": "<skill id from the card>", "arguments": { ... } }. Il testo libero non viene interpretato.
  3. Le funzioni fax e numeri restituiscono link Stripe Checkout (checkoutUrl). A2A non spende crediti o pagine del piano. Una bozza in attesa di pagamento ha stato input-required. Interroga con GetTask.

Per crediti AP2 richiedi credits:checkout e negozia l’estensione merchant. Mandati firmati di carrello e pagamento, approvazione passkey separata, utilizzo SPT e ricevute confermate nel registro: https://singlefax.com/ap2.md.

GetTask con fax:read segue la consegna per bozze fax e pagamento/provisioning per numeri. Il compito numero termina all’attivazione. I crediti non hanno task collegato a un ordine: verifica il saldo dopo il pagamento.

Percorso B. Chiave API (backend e CLI)

  1. Crea una chiave su https://singlefax.com/dashboard/api-keys (sf_live_…).
  2. Acquista crediti prepagati.
  3. Authorization: Bearer sf_live_… su https://singlefax.com/api/v1/… (o https://api.singlefax.com/api/v1/…).
  4. CLI: npx @singlefax/cli send FILE --to +E164 con SINGLEFAX_API_KEY. Passa Word, Excel, PDF o immagine originali, senza conversione preventiva.

Esempi di linguaggio (curl, Node, Python, Go, PHP): https://singlefax.com/developers.md

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

Percorso C. JWT host/agente delegati Better Auth

Le capacità delegate (validate_fax, send_fax, get_fax_status, get_credits, create_credit_checkout) usano approvazione dispositivo.

  1. Leggi GET https://api.singlefax.com/.well-known/agent-configuration per algoritmi, endpoint, modalità e approvazioni. L’issuer Agent Auth è https://api.singlefax.com, distinto dall’issuer OAuth che termina in /api/auth. Usa questa origine come audience JWT. Genera chiavi separate host e agente con algoritmo supportato; conserva le private al sicuro.
  2. Prepara prima l’host. Registrazione dinamica host disabilitata. Il titolare deve accedere a SingleFax e chiamare POST https://singlefax.com/api/auth/host/create (equivalente API: https://api.singlefax.com/api/auth/host/create) dalla sessione browser proprietaria. Fornisci { "name": "My agent host", "public_key": <host public JWK>, "default_capabilities": [] }; hostId nella risposta identifica l’host. Impostazioni iniziali vuote assicurano approvazione separata delle capacità. Oppure ometti public_key per ricevere enrollmentToken monouso a scadenza; l’host chiama POST https://api.singlefax.com/api/auth/host/enroll con { "token": <enrollment token>, "public_key": <host public JWK>, "name": "My agent host" }. Mai condividere cookie o chiavi private con l’agente.
  3. Registrati su POST https://api.singlefax.com/api/auth/agent/register. Invia Authorization: Bearer <signed host+jwt> e JSON { "name": "My agent", "mode": "delegated", "capabilities": ["validate_fax", "get_fax_status", "get_credits"], "preferred_method": "device_authorization", "force_approval": true }. Header JWT: typ: "host+jwt", alg supportato e kid del JWK firmatario se presente. Claim: iss: <registered hostId>, aud: "https://api.singlefax.com", jti nuovo, iat corrente, exp entro 60 secondi e agent_public_key: <agent public JWK>. Firma con la chiave host predisposta. Identificatori JWT riusati vengono respinti.
  4. La registrazione restituisce agent_id, host_id, stato, capacità e oggetto approval quando necessario. Mostra il codice dispositivo e apri verification_uri_complete su SingleFax. L’utente accede e approva all’URL restituito. Registrazione, provisioning e approvazione cambiano l’account; scanner passivi devono solo leggere discovery.
  5. Interroga GET https://api.singlefax.com/api/auth/agent/status?agent_id=<registered id> con JWT host nuovo (iss: <host_id>). Dopo l’approvazione firma JWT agente con la sua chiave privata: header typ: "agent+jwt", alg/kid supportati; claim iss: <host_id>, sub: <agent_id>, aud: "https://api.singlefax.com", iat corrente, exp entro 60 secondi e jti nuovo. Chiama POST https://api.singlefax.com/api/auth/capability/execute con Authorization: Bearer <signed agent+jwt> e { "capability": "get_credits", "arguments": {} }, o un’altra capacità concessa con gli argomenti documentati. Sono prove firmate, non chiavi API o access token OAuth.
  6. Per un nuovo codice dispositivo di un agente registrato, POST https://api.singlefax.com/api/auth/agent/device/code con { "agent_id": "<registered id>" } e JWT host firmato. Questo endpoint non registra agenti. Revoca tramite POST https://api.singlefax.com/api/auth/agent/revoke con { "agent_id": "<registered id>" } e JWT host proprietario o sessione titolare. send_fax richiede verifica utente con passkey; non è autonomo.

Non inviare ID-JAG o { "type": "anonymous" } via POST qui: tipi d’identità non supportati.

Pagamenti macchina (non OAuth)

Pagamento autonomo: MPP HTTP 402 su POST /api/v1/machine/faxes con Stripe Shared Payment Token o Tempo USDC. Vedi https://singlefax.com/mpp.md. Cursor non genera SPT: usa Stripe Link CLI su quell’URL REST, non /mcp. I wallet Tempo pagano la richiesta Tempo sullo stesso URL.

HIPAA

Non inviare PHI su MCP, MPP o API pubblica. Gli enti soggetti usano HIPAA Secure sul sito con BAA elettronico.