Salta ai contenuti

Flusso Native Application

Usa il flusso Native app per integrazioni che agiscono per conto di un utente che ha effettuato l’accesso dalla propria macchina, come un’app desktop, una CLI o un plugin CAD. Usa Authorization Code con PKCE, un redirect loopback su localhost e nessun client secret. Questa guida ti accompagna nella configurazione dalla creazione dell’applicazione OAuth alla tua prima chiamata all’API.

Rivedi prima la guida Per iniziare se non hai ancora coperto i prerequisiti, l’accesso di rete e il modello di sicurezza.


  1. Creare un’applicazione OAuth: registra un’app nativa in Prevu3D e ottieni un Client ID
  2. Configurare l’accesso dell’utente: assicurati che l’utente che accede possa raggiungere i dati di cui ha bisogno
  3. Autorizzare con PKCE: invia l’utente attraverso la pagina di consenso nel browser
  4. Scambiare il codice con un token: scambia il codice di autorizzazione con un access token
  5. Trovare l’URL della tua API: scopri l’URL di base della tua organizzazione (varia in base alla regione)
  6. Effettuare la prima chiamata: testa la connessione con una semplice richiesta
  1. Accedi alla Prevu3D Platform.
  2. Vai su SettingsOAuth.
  3. Fai clic per creare una nuova applicazione.
  4. Abilita il flusso Authorization Code.
  5. Abilita Native Application. L’URI di redirect è fissato a http://localhost.
  6. Lascia il client secret disattivato. Le app native non ne usano uno.
  7. Copia e conserva in modo sicuro il tuo Client ID. Ti servirà per ogni autorizzazione.

Il flusso nativo chiama l’API come l’utente che ha effettuato l’accesso, non un utente di servizio. Questo copre i livelli 2 e 3 del modello di sicurezza: quali nodi l’utente può vedere (accesso ai contenuti) e cosa può farci (accesso a ruoli / permessi).

  1. Assicurati che l’utente che effettuerà l’accesso abbia l’accesso ai contenuti dei nodi (organizzazioni, divisioni, siti, ecc.) richiesti dal tuo caso d’uso.
  2. Assicurati che l’utente abbia un ruolo su quei nodi con i permessi di cui la tua integrazione ha bisogno (lettura, modifica, gestione, ecc.).

Nella schermata di consenso, l’utente seleziona anche quale organizzazione autorizzare. Gli scope che l’utente approva lì configurano il livello 1.

Le app native non possono conservare un segreto, quindi il flusso usa PKCE per proteggere il codice di autorizzazione. Prima di aprire la pagina di consenso, genera tre valori:

ValoreCome
code_verifierStringa casuale, da 43 a 128 caratteri
code_challengeBASE64URL(SHA256(code_verifier)) senza padding
stateStringa casuale; validala quando il redirect ritorna

Avvia un server loopback locale su una porta libera, quindi apri il browser dell’utente sulla pagina di consenso.

URL di consenso: https://cloud.prevu3d.com/oauth

Parametri di query (tutti obbligatori):

ParametroValore
response_typecode
code_challenge_methodS256
client_idIl tuo Client ID
redirect_uriIl tuo URI di loopback, ad esempio http://localhost:8765 (includi la porta, nessuna barra finale)
scopesUno per scope, ad esempio scopes=read:basic&scopes=read:hierarchy
code_challengeIl challenge PKCE generato sopra
stateIl tuo valore di stato casuale

Dopo che l’utente ha effettuato l’accesso e ha fatto clic su Allow, il browser reindirizza al tuo URI di loopback:

http://localhost:8765/?code={authorization_code}&state={state}

Se l’utente nega l’accesso, ricevi invece ?error=access_denied. I codici di autorizzazione scadono dopo 60 secondi, quindi scambiali subito.

Passaggio 4: scambia il codice con un access token

Sezione intitolata “Passaggio 4: scambia il codice con un access token”

Endpoint: POST https://cloud-api.prevu3d.com/oauth/token

Header: Content-Type: application/x-www-form-urlencoded

Body:

CampoValore
grant_typeauthorization_code
client_idIl tuo Client ID
codeCodice dal redirect
redirect_uriLo stesso URI usato nel Passaggio 3 (inclusa la porta)
code_verifierIl verifier PKCE originale

Non inviare un client secret per le app native.

Esempio di risposta:

{
"hasError": false,
"expires_in": 86400,
"access_token": "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "..."
}

Salva entrambi i token. Usa l’access_token per le chiamate all’API. Quando scade, richiedine uno nuovo con grant_type=refresh_token e il tuo refresh_token salvato (nessun client secret richiesto).

Passaggio 5: ottieni l’URL di base della tua API

Sezione intitolata “Passaggio 5: ottieni l’URL di base della tua API”

Chiama l’endpoint di discovery per ottenere l’apiUrl della tua organizzazione. Non codificare staticamente un URL regionale.

Endpoint: GET https://cloud-api.prevu3d.com/oauth/api-info

Header: Authorization: Bearer <your_access_token>

Esempio di risposta:

{
"user": { "..." : "..." },
"organization": {
"id": "217ebd23-ec54-4af0-a6d6-4a441a6d1966",
"name": "Test Organization"
},
"scopes": ["read:basic", "read:hierarchy"],
"apiUrl": "https://api-ue1.prevu3d.com/realityconnect-api"
}

Usa il valore apiUrl come base per tutte le tue chiamate all’API. Annota anche l’organization.id, che ti servirà per molti endpoint.

Passaggio 6: effettua la tua prima chiamata all’API

Sezione intitolata “Passaggio 6: effettua la tua prima chiamata all’API”

Ora hai tutto ciò che ti serve: un access token e il tuo URL di base. Facciamo una semplice richiesta per recuperare le divisioni della tua organizzazione:

GET {apiUrl}/v1/nodes/{organization_id}/browse
Authorization: Bearer <your_access_token>

Esempio con valori reali:

GET https://api-ue1.prevu3d.com/realityconnect-api/v1/nodes/217ebd23-ec54-4af0-a6d6-4a441a6d1966/browse HTTP/1.1
Authorization: Bearer eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9...

Una risposta di successo contenente un elenco di divisioni conferma che la tua integrazione funziona correttamente.

Ecco uno script completo che fa tutto quanto sopra. Sostituisci client_id con il tuo Client ID, quindi eseguilo. Avvia un server loopback temporaneo, apre la pagina di consenso nel tuo browser e stampa le divisioni della tua organizzazione una volta che approvi.

import base64
import hashlib
import json
import secrets
import webbrowser
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import parse_qs, quote, urlencode, urlparse
import requests
client_id = "your-client-id"
base_url = "https://cloud-api.prevu3d.com"
scopes = ["read:basic", "read:hierarchy"]
# Passaggio 1: autorizza con PKCE e ottieni un access token
verifier = secrets.token_urlsafe(48)[:64]
challenge = base64.urlsafe_b64encode(hashlib.sha256(verifier.encode()).digest()).decode().rstrip("=")
state = secrets.token_urlsafe(32)
auth_result = {"code": None, "state": None}
class Handler(BaseHTTPRequestHandler):
def log_message(self, *args):
pass
def do_GET(self):
query = parse_qs(urlparse(self.path).query)
auth_result["code"] = query.get("code", [None])[0]
auth_result["state"] = query.get("state", [None])[0]
self.send_response(200)
self.end_headers()
server = HTTPServer(("localhost", 0), Handler)
redirect_uri = f"http://localhost:{server.server_address[1]}"
consent_params = urlencode(
{
"response_type": "code",
"code_challenge_method": "S256",
"client_id": client_id,
"redirect_uri": redirect_uri,
"code_challenge": challenge,
"state": state,
}
)
consent_url = f"{base_url.replace('cloud-api.', 'cloud.', 1)}/oauth?{consent_params}"
consent_url += "&" + "&".join(f"scopes={quote(scope)}" for scope in scopes)
webbrowser.open(consent_url)
server.handle_request()
if auth_result["state"] != state:
raise RuntimeError("Invalid state")
if not auth_result["code"]:
raise RuntimeError("Authorization failed")
token_response = requests.post(
f"{base_url}/oauth/token",
data={
"grant_type": "authorization_code",
"client_id": client_id,
"code": auth_result["code"],
"redirect_uri": redirect_uri,
"code_verifier": verifier,
},
)
token_response.raise_for_status()
access_token = token_response.json()["access_token"]
# Passaggio 2: ottieni l'URL della tua API e l'ID dell'organizzazione
api_info = requests.get(
f"{base_url}/oauth/api-info",
headers={"Authorization": f"Bearer {access_token}"},
).json()
api_url = api_info["apiUrl"]
organization_id = api_info["organization"]["id"]
# Passaggio 3: esplora le divisioni
divisions = requests.get(
f"{api_url}/v1/nodes/{organization_id}/browse",
headers={"Authorization": f"Bearer {access_token}"},
).json()
print("Divisions:", json.dumps(divisions, indent=2))
Se vedi…Prova questo…
Invalid OAuth grant request dopo aver fatto clic su AllowConferma di usare il Client ID di un’app nativa (Authorization Code e Native app abilitati). Un’app con solo Client Credentials non ha un URI di redirect e non può completare questo flusso.
Errore della pagina di consenso relativo ai parametri di queryAssicurati che response_type=code, code_challenge_method=S256 e tutti i parametri richiesti siano presenti, inclusi state e scopes.
400 o 403 durante lo scambio del tokenIl codice potrebbe essere scaduto (limite di 60 secondi), il redirect_uri potrebbe non corrispondere al Passaggio 3, oppure il verifier e il challenge PKCE potrebbero non corrispondere.
403 Forbidden durante la chiamata all’APIUna richiesta deve superare tutti e tre i livelli di sicurezza. Verifica gli scope OAuth, l’accesso ai contenuti dell’utente che ha effettuato l’accesso e il ruolo dell’utente sul nodo di destinazione.
Organizzazione errata nelle risposte dell’APIL’utente seleziona l’organizzazione nella schermata di consenso. Riautorizza e scegli quella corretta.

Per problemi di connessione, DNS e URL dell’API, consulta Per iniziare.

  • Aggiungi la logica per aggiornare il tuo token prima che scada usando grant_type=refresh_token con il tuo refresh token salvato.
  • Esplora il riferimento API per vedere tutte le operazioni disponibili.