Vai al contenuto
Torna alla documentazione di Launch

Scarica MarkdownDocumento originale su GitHub

Guida all'integrazione di un sistema di autorizzazione personalizzato

Il codice sorgente attuale supporta due fornitori di autorizzazioni: Licentivo e custom_http. I commercianti ne selezionano e abilitano uno in Impostazioni di sistema → Sistema di autorizzazione; tutti i prodotti e gli ambienti sandbox/live usano lo stesso fornitore. Le connessioni personalizzate e le mappature dei piani si configurano comunque separatamente per prodotto e ambiente. Questa funzionalità non include un sistema di autorizzazione sviluppato internamente: i commercianti continuano a usare i propri servizi di autorizzazione e SDK.

Lo scambio degli account Licentivo, gli SDK in nove linguaggi e la gestione dei dispositivi esistenti continuano a seguire la procedura originale. I prodotti personalizzati sincronizzano lo stato degli acquisti tramite il protocollo descritto in questo documento; i clienti consultano le informazioni di consegna dell'autorizzazione nel centro account, senza passare dalla procedura degli SDK Licentivo.

Avvio rapido

  1. Implementare nel proprio servizio le quattro interfacce HTTP riportate di seguito, configurando identificativi e chiavi di firma HMAC distinti per ogni connessione.
  2. In «Sistema di autorizzazione», selezionare «Servizio di autorizzazione personalizzato» e aggiungere una connessione. Inserire indirizzo, ambiente, identificativo della connessione, key ID e chiave in Base64 standard, verificare e salvare, quindi fare clic su «Abilita servizio di autorizzazione personalizzato».
  3. Creare le bozze del prodotto e dei piani di vendita. Il tipo di acquisto e il prezzo si gestiscono in Launch; le regole di autorizzazione si gestiscono nel proprio sistema.
  4. Selezionare il prodotto, l'ambiente e la connessione, quindi inserire i riferimenti esterni del prodotto e del piano e salvare. Il fornitore dipende dalla scelta valida per tutto il sito; non è possibile abilitare contemporaneamente Licentivo per altri prodotti.
  5. Pubblicare una versione di test nella pagina dei piani di vendita, completare il collaudo di pagamento, consegna, rinnovo, upgrade, rimborso e ripristino dopo un errore, quindi configurare separatamente l'ambiente di produzione.

Dopo la creazione non è possibile modificare indirizzo, ambiente, identificativo della connessione o politica di accesso alla rete; se necessario, creare una nuova connessione. Le chiavi di firma possono essere ruotate; lasciare il campo vuoto per conservare la chiave originale. Se esistono ordini associati a un altro sistema di autorizzazione, non è possibile cambiare direttamente il fornitore dell'intero sito: occorre prima completare la migrazione. Dopo il cambio, i piani originali diventano disponibili solo in anteprima e devono essere ripubblicati; le credenziali delle connessioni e le mappature salvate vengono conservate. I prodotti con ordini esistenti non possono cambiare direttamente connessione e le mappature dei piani in vendita non possono essere sostituite direttamente; per nuovi prezzi o mappature, usare una nuova versione del piano.

Per la configurazione tramite API, chiamare prima PUT /api/v1/admin/licensing/provider con corpo della richiesta {"provider":"custom_http"} oppure {"provider":"licentivo"}, quindi salvare la mappatura del prodotto. Per i fornitori non abilitati non è possibile salvare le associazioni di autorizzazione dei prodotti né le mappature delle politiche dei piani Licentivo.

La verifica della connessione controlla il protocollo, l'autenticazione, l'ambiente e i tipi di acquisto supportati; non crea né conferma piani esterni per conto del commerciante. Prima di incassare pagamenti reali, è necessario completare il collaudo dell'integrazione in sandbox usando piani esterni effettivi.

3. Procedura di integrazione per i commercianti

  1. Implementare le quattro interfacce di questo documento davanti al sistema di autorizzazione esistente; la logica delle licenze già presente nel sistema viene mantenuta.
  2. Creare in Launch una connessione «Servizio di autorizzazione personalizzato», configurando indirizzo HTTPS, identificativo della connessione, ambiente e chiave di firma.
  3. Launch chiama l'interfaccia di verifica delle funzionalità per confermare la versione del protocollo, il supporto per gli acquisti permanenti/a tempo limitato e il metodo di consegna.
  4. Selezionare questa connessione per il prodotto e mappare la versione del piano di vendita ai riferimenti esterni product_ref e plan_ref. Gli identificativi esterni possono essere stringhe proprie del commerciante; non è obbligatorio usare UUID Licentivo.
  5. Completare in sandbox il collaudo di pagamento, rinnovo, upgrade, rimborso e ripristino dopo un errore, quindi pubblicare separatamente la configurazione live.
  6. Dopo aver verificato il pagamento, Launch salva l'ordine, la copertura dell'acquisto e le attività da inviare all'interno della stessa transazione del database.
  7. Il backend invia un'istantanea completa dell'acquisto al servizio di autorizzazione personalizzato; il servizio salva in modo persistente il record ricevuto prima di confermarne la ricezione.
  8. Il servizio di autorizzazione elabora lo stato di destinazione. Launch consulta la ricevuta dell'evento originale: solo applied conferma il completamento di questa sincronizzazione.
  9. Launch recupera le informazioni di consegna per i clienti autenticati titolari dell'acquisto e mostra nel centro clienti il codice di autorizzazione, il punto di accesso all'attivazione o le istruzioni in testo semplice. L'applicazione si integra con il sistema di autorizzazione del commerciante.
  10. Rinnovi, upgrade, rimborsi, storni di pagamento, sospensioni e scadenze generano una nuova versione dell'istantanea completa. Il servizio di autorizzazione elabora lo stato di destinazione più recente.

Gli ambienti sandbox/live dello stesso prodotto vengono associati a connessioni distinte. Dopo che è stato effettuato un acquisto, il cambio di fornitore richiede una procedura di migrazione separata; i vecchi ordini e le vecchie attività non devono essere inviati al nuovo servizio senza avviso solo perché è cambiata la selezione nel backend.

4. API da implementare nel servizio di autorizzazione personalizzato

Tutte le interfacce seguenti sono ricevute dal servizio di autorizzazione del commerciante e chiamate dal server Launch. base_url può includere un prefisso di percorso fisso; i percorsi della tabella vengono aggiunti dopo tale prefisso.

Metodi e percorsi Scopo
GET /launch/v1/capabilities Verifica della connessione, dichiarazione del protocollo e delle funzionalità
POST /launch/v1/events Riceve lo stato di destinazione completo dell'acquisto; i tentativi successivi riutilizzano l'evento originale
GET /launch/v1/events/{event_id} Verifica se l'evento è stato effettivamente applicato e recupera le risposte perse
GET /launch/v1/entitlements/{entitlement_ref}/delivery Legge le informazioni di consegna di un'autorizzazione esistente, senza crearne una seconda

La prima versione consulta attivamente le ricevute e non introduce endpoint di callback esterni per modificare gli ordini. I servizi personalizzati non hanno il permesso di confermare pagamenti, modificare prezzi o riscrivere i periodi di acquisto.

4.1 Convenzioni generali e autenticazione

  • JSON usa UTF-8; gli orari usano UTC RFC 3339; version usa numeri interi positivi.
  • Una risposta riuscita è {"data": {...}, "request_id": "..."}; una risposta di errore è {"error": {"code": "...", "message": "..."}, "request_id": "..."}.
  • Ogni ambiente e ogni connessione usano una chiave distinta. La chiave deve contenere almeno 32 byte casuali e in Launch fa riferimento all'archivio cifrato delle chiavi esistente; non deve essere inclusa nella configurazione frontend, negli esempi o nei pacchetti di installazione dell'applicazione.
  • Ogni richiesta include X-Launch-Key-Id, X-Launch-Timestamp, X-Launch-Nonce e X-Launch-Signature.
  • Il timestamp è espresso in secondi Unix in formato decimale. Il nonce è la codifica base64url senza padding di un valore casuale di almeno 128 bit; per ogni tentativo di rete viene generato un nuovo valore.

L'input della firma è costituito dai seguenti sette elementi codificati in byte UTF-8 e uniti da un singolo carattere di nuova riga, senza una nuova riga finale:

v1
<key_id>
<timestamp>
<nonce>
<UPPERCASE HTTP method>
<encoded request path and raw query, including the base_url path prefix>
<lowercase hexadecimal SHA-256 digest of the exact request body>

X-Launch-Signature è costituito da v1= seguito dalla codifica base64url senza padding del risultato di HMAC-SHA256. Le richieste GET hanno corpo vuoto. Il destinatario verifica la firma e la finestra temporale prima della deserializzazione; usa un confronto a tempo costante, ammette per impostazione predefinita uno scarto di 300 secondi in più o in meno e conserva i nonce per almeno 600 secondi per impedire attacchi di replay. I nonce non vengono riutilizzati tra i tentativi, ma gli ID evento e il corpo funzionale della richiesta devono rimanere invariati.

Le firme non sostituiscono HTTPS. Le richieste non includono password dei clienti, chiavi di pagamento o chiavi amministrative Licentivo; per impostazione predefinita vengono inviati solo riferimenti anonimi agli account, senza indirizzi email. I client HTTP del server devono prevedere timeout e limiti alla dimensione delle risposte e impedire l'inoltro delle credenziali durante i reindirizzamenti. Gli indirizzi di destinazione personalizzati devono essere convalidati; l'accesso alla rete interna deve essere una funzionalità di distribuzione configurata esplicitamente dagli amministratori.

4.2 Verifica delle funzionalità

GET /launch/v1/capabilities restituisce HTTP 200, ad esempio:

{
  "data": {
    "protocol": "launch-external-licensing-v1",
    "connection_ref": "merchant-01-sandbox",
    "environment": "sandbox",
    "purchase_types": ["perpetual", "fixed_term"],
    "delivery_types": ["license_key", "activation_url", "instructions"],
    "devices": false,
    "identity_exchange": false
  },
  "request_id": "check-001"
}

protocol, connection_ref, environment, purchase_types e delivery_types sono obbligatori. Gli ultimi due devono essere array non vuoti; i tipi di acquisto non supportati non possono essere pubblicati per la vendita. Nella prima versione, devices e identity_exchange devono essere false; il supporto può essere dichiarato solo dopo aver completato il contratto esteso e la relativa implementazione.

4.3 Istantanea dell'acquisto

Esempio di richiesta per POST /launch/v1/events:

{
  "schema": "launch-external-licensing-v1",
  "event_id": "7bf84b91-2749-4b01-a6a7-bd527c488ee8",
  "connection_ref": "merchant-01-sandbox",
  "environment": "sandbox",
  "type": "entitlement.snapshot",
  "change_reason": "purchase",
  "account_ref": "customer_opaque_001",
  "entitlement_ref": "purchase_opaque_001",
  "launch_product_id": "c6dd463e-50f7-4b76-8239-0a8ec6fc304b",
  "launch_plan_version_id": "5459a073-9362-4b46-949d-9b0c5d84421a",
  "product_ref": "desktop-editor",
  "plan_ref": "professional-yearly-v1",
  "version": 1,
  "desired_state": "active",
  "valid_from": "2026-10-25T00:00:00Z",
  "valid_until": "2027-10-25T00:00:00Z"
}

Tutti i campi dell'esempio precedente sono obbligatori. valid_until impostato a null indica un acquisto permanente; qualsiasi altro valore deve essere successivo a valid_from.

Campo Vincoli e significato
event_id UUID generato da Launch; rimane invariato nei tentativi successivi dello stesso evento
connection_ref / environment Deve corrispondere alla connessione e all'ambiente a cui appartiene la chiave di firma
account_ref Riferimento anonimo stabile dell'account; il destinatario identifica il cliente combinando connessione, ambiente e questo riferimento
entitlement_ref Riferimento stabile per una relazione di acquisto; dopo una revoca completa, un nuovo acquisto usa un nuovo riferimento
launch_product_id / launch_plan_version_id UUID del prodotto Launch e della versione immutabile del piano
product_ref / plan_ref Riferimento esterno configurato da chi esegue l'integrazione; 1–128 caratteri ASCII, con lettere, numeri, _, - e . consentiti; non crea automaticamente piani esterni
version Versione di destinazione che cresce monotonicamente per la stessa connessione, lo stesso ambiente e lo stesso riferimento di acquisto
desired_state active, suspended, expired, revoked
change_reason purchase, renewal, upgrade, refund, reversal, suspension, resumption, expiry, reconciliation

account_ref e entitlement_ref usano da 1 a 128 caratteri tra lettere, numeri, trattini bassi o trattini. schema e type hanno i valori fissi indicati nell'esempio. Il destinatario applica il risultato in base a desired_state e all'intero periodo di validità assoluto, senza aggiungere autonomamente giorni o revocare l'intera autorizzazione in base al motivo.

In particolare, per i rimborsi: dopo il rimborso di un ordine di rinnovo o upgrade può restare valido l'acquisto di base. In tal caso l'istantanea può ancora essere active, ma con un periodo più breve o un piano diverso. Lo stato di cessazione corrispondente viene inviato solo quando, dopo il ricalcolo del registro contabile, non rimane alcuna copertura di acquisto valida.

4.4 Ricezione, ricevute e ripristino

Il destinatario deve restituire HTTP 202 solo dopo aver salvato in modo persistente l'ID evento, il digest del corpo originale della richiesta e l'attività da eseguire; le richieste duplicate la cui sincronizzazione è già stata completata possono restituire HTTP 200. Entrambe le risposte restituiscono la struttura della ricevuta riportata di seguito.

{
  "data": {
    "event_id": "7bf84b91-2749-4b01-a6a7-bd527c488ee8",
    "connection_ref": "merchant-01-sandbox",
    "environment": "sandbox",
    "entitlement_ref": "purchase_opaque_001",
    "version": 1,
    "payload_sha256": "<64-character lowercase hexadecimal SHA-256 digest of the exact event body>",
    "status": "pending",
    "error_code": null
  },
  "request_id": "receipt-001"
}

Il segnaposto del digest deve essere sostituito con il digest effettivo. Tutti i campi della ricevuta indicati sopra sono obbligatori; in assenza di errori, error_code è null. La richiesta GET /launch/v1/events/{event_id} restituisce la stessa struttura con HTTP 200; lo stato può essere:

status Significato Elaborazione da parte di Launch
pending Salvato in modo persistente, ma la modifica effettiva dell'autorizzazione non è ancora completata Ripetere la consultazione in seguito; non è possibile contrassegnare la sincronizzazione come completata
applied Il servizio di autorizzazione conferma che lo stato di destinazione è stato effettivamente applicato Confermare il completamento della sincronizzazione dopo aver verificato tutti i campi di correlazione e il digest
rejected È certo che non possa essere applicato, ad esempio perché il piano esterno non esiste Interrompere i tentativi automatici e mostrare un errore esplicito
manual_review Risultato incerto o conflitto di stato; è necessaria una verifica manuale Conservare l'attività e l'evento originali in attesa di un intervento tracciabile

Lo stato della consegna è indipendente dalla ricevuta di sincronizzazione; applied non può fungere direttamente da permesso di esecuzione per l'applicazione del cliente.

Requisiti di affidabilità:

  • La consegna avviene almeno una volta e il destinatario deve garantire l'idempotenza delle operazioni applicative; non è possibile promettere «una sola chiamata» a livello di rete.
  • Per lo stesso ID evento e lo stesso corpo originale della richiesta, restituire il risultato esistente; per lo stesso ID ma un corpo diverso, restituire HTTP 409 IDEMPOTENCY_CONFLICT.
  • Le versioni precedenti non devono sovrascrivere quelle più recenti. Eventi o stati di destinazione diversi per la stessa versione di acquisto non devono essere accettati senza segnalazione: occorre restituire HTTP 409 STATE_VERSION_CONFLICT per consentire la verifica.
  • Se la risposta POST viene persa o il processo viene riavviato, Launch consulta prima l'evento originale tramite GET; reinvia l'ID e il corpo originali solo dopo una risposta esplicita EVENT_NOT_FOUND.
  • Se l'esito effettivo del rilascio remoto è incerto, anche chi esegue l'integrazione deve verificarlo usando il proprio riferimento di idempotenza persistente; un nuovo invio non deve generare un'altra autorizzazione.
  • Per HTTP 429 rispettare Retry-After; per timeout ed errori 5xx, riprovare con attese progressive. Superato il limite, passare alla verifica manuale. I rifiuti dovuti ad autenticazione, configurazione o regole applicative non devono essere considerati sincronizzazioni riuscite.

Codici di errore consigliati: SIGNATURE_INVALID (401), SIGNATURE_EXPIRED (401), NONCE_REPLAYED (409), SCOPE_MISMATCH (403), EVENT_NOT_FOUND (404), IDEMPOTENCY_CONFLICT (409), STATE_VERSION_CONFLICT (409), PLAN_UNKNOWN (422), PURCHASE_TYPE_UNSUPPORTED (422), RATE_LIMITED (429), SERVICE_UNAVAILABLE (503). I messaggi di errore non devono contenere credenziali.

4.5 Consegna dell'autorizzazione

GET /launch/v1/entitlements/{entitlement_ref}/delivery può soltanto leggere i risultati di consegna già esistenti per la connessione e l'ambiente indicati; la consultazione non deve essere trattata come un comando di nuovo rilascio. Esempio di HTTP 200:

{
  "data": {
    "connection_ref": "merchant-01-sandbox",
    "environment": "sandbox",
    "entitlement_ref": "purchase_opaque_001",
    "version": 1,
    "status": "ready",
    "delivery": {
      "type": "license_key",
      "value": "EXAMPLE-ONLY-NOT-A-REAL-LICENSE",
      "expires_at": null
    }
  },
  "request_id": "delivery-001"
}

status è pending, ready oppure unavailable; quando non è ready, delivery è null. Quando è ready, type deve essere uno dei valori dichiarati license_key, activation_url o instructions; value può contenere al massimo 4096 byte UTF-8 e expires_at è un orario UTC oppure null. Tutti i campi di correlazione della risposta devono corrispondere alla versione di acquisto corrente in Launch; le consegne di versioni precedenti non possono essere considerate risultati correnti.

I codici di autorizzazione sono dati sensibili; le risposte di consegna usano Cache-Control: no-store e il loro corpo non deve essere registrato nei log. Se occorre conservarle in modo persistente, usare un archivio cifrato. Per gli URL di attivazione sono ammesse soltanto le origini HTTPS consentite dalla configurazione della connessione; instructions viene visualizzato come testo semplice, senza eseguire HTML o script. Gli account con autorizzazione revocata, rimborso totale o nessun acquisto valido non possono continuare a ottenere le informazioni di consegna tramite Launch; l'invalidazione effettiva delle credenziali già consegnate viene eseguita dal sistema esterno.

API amministrative e per i clienti di Launch

Queste interfacce si trovano nell'origine Launch distribuita dal commerciante e non usano l'autenticazione con chiave HMAC del servizio esterno. Gli amministratori usano la sessione del sito esistente e le richieste di scrittura devono includere X-CSRF-Token. I clienti possono leggere soltanto i propri acquisti.

Metodi e percorsi Scopo
GET /api/v1/admin/licensing/connections Restituisce connections, bindings, mappings e default_provider; l'elenco delle connessioni contiene solo quelle personalizzate, mentre Licentivo continua a usare l'interfaccia amministrativa originale
POST /api/v1/admin/licensing/connections Verifica e aggiunge una connessione personalizzata
PUT /api/v1/admin/licensing/connections/{id} Modifica il nome, le origini di attivazione consentite e la configurazione della firma; l'indirizzo di ricezione storico rimane invariato
POST /api/v1/admin/licensing/connections/{id}/check Esegue nuovamente la verifica; un valore diverso da null per last_check_error nella risposta HTTP 200 indica che la verifica è fallita
PUT /api/v1/admin/products/{id}/licensing Configura il fornitore, la connessione e le mappature dei piani esterni per l'ambiente selezionato del prodotto
GET /api/v1/me/products/{id}/delivery?environment=sandbox Il cliente corrente legge la consegna dell'autorizzazione relativa al proprio acquisto personalizzato attualmente valido; autenticazione tramite Cookie o Bearer desktop
GET /api/v1/licensing/documentation Questo documento, senza necessità di accesso
GET /api/v1/licensing/protocol OpenAPI che il servizio personalizzato deve implementare, senza necessità di accesso

Corpo della richiesta per aggiungere una connessione personalizzata:

{
  "provider": "custom_http",
  "name": "My licensing service",
  "base_url": "https://licenses.example.com",
  "environment": "sandbox",
  "connection_ref": "merchant-01-sandbox",
  "key_id": "key-1",
  "signing_key": "<standard Base64 encoding of 32 to 128 random bytes>",
  "allow_private_network": false,
  "allow_local_http": false,
  "activation_origins": ["https://activate.example.com"]
}

data della risposta è l'oggetto della connessione con i dati sensibili rimossi; non restituisce la chiave di firma né il secret ID. allow_local_http consente solo indirizzi localhost/loopback in sandbox; gli indirizzi HTTPS su reti private richiedono l'autorizzazione esplicita di un amministratore. La chiave può essere lasciata vuota solo quando si modifica una connessione esistente. Licentivo continua a essere configurato tramite POST /api/v1/admin/connections/licentivo.

Corpo della richiesta per configurare il prodotto:

{
  "provider": "custom_http",
  "environment": "sandbox",
  "connection_id": "<id returned when creating the connection>",
  "mappings": [
    {
      "version_id": "<Launch plan version UUID>",
      "product_ref": "desktop-editor",
      "plan_ref": "professional-yearly-v1"
    }
  ]
}

Quando si seleziona Licentivo, inviare {"provider":"licentivo","environment":"sandbox","mappings":[]}; le mappature dei suoi prodotti e delle sue politiche continuano a usare l'interfaccia originale. Il primo cambio trasforma le pubblicazioni esistenti in anteprime, che devono essere nuovamente verificate e pubblicate per il nuovo fornitore. mappings può contenere soltanto le versioni da aggiungere o conservare; l'omissione non elimina le vecchie mappature.

La consegna al cliente usa il contenitore data standard con HTTP 200; in assenza di un acquisto restituisce 404. Per i prodotti Licentivo restituisce 409 LICENSING_DELIVERY_UNSUPPORTED; per acquisti non sincronizzati, sospesi, scaduti o interamente rimborsati restituisce 409 ENTITLEMENT_NOT_READY; se il servizio esterno è temporaneamente non disponibile o la ricevuta non corrisponde, restituisce 503. «Visualizza consegna dell'autorizzazione» nel centro clienti verifica nuovamente la titolarità e lo stato, senza scrivere le credenziali negli URL o nei log.

Per i prodotti personalizzati, le interfacce Licentivo identity, device e integration-check restituiscono 409 CUSTOM_LICENSING_SDK_REQUIRED. Il vecchio /credential continua a restituire 410. L'applicazione deve usare l'SDK del commerciante, senza considerare lo stato ready di Launch come autorizzazione all'esecuzione.

Esempi e collaudo

L'esempio di adattatore leggero in Python fornisce una struttura di ricezione con firma, nonce, deduplicazione degli eventi e persistenza delle ricevute; l'elaborazione effettiva dell'autorizzazione richiede l'integrazione con il sistema del commerciante.

L'OpenAPI del protocollo personalizzato e l'OpenAPI di Launch descrivono separatamente le due direzioni. Il destinatario non deve implementare le interfacce Licentivo per il catalogo prodotti, il catalogo delle politiche o l'attendibilità delle identità.

La verifica locale usa un MySQL isolato, un adattatore HTTP reale e servizi di autorizzazione/pagamento simulati; copre perdita delle risposte, riavvii, rinnovi, upgrade, rimborsi, disattivazione degli account, ricevute non corrispondenti e isolamento delle consegne. Il collaudo in produzione richiede anche il servizio di autorizzazione e l'applicazione del commerciante. Launch non integra le funzionalità non dichiarate relative a dispositivi, accesso con account condivisi e funzionamento offline.