Flujo de aplicación nativa
Usa el flujo de aplicación nativa para integraciones que actúan en nombre de un usuario con sesión iniciada desde su propia máquina, como una app de escritorio, una CLI o un plugin de CAD. Usa Authorization Code con PKCE, un redireccionamiento loopback a localhost y sin secreto de cliente. Esta guía te acompaña en la configuración, desde la creación de la aplicación OAuth hasta tu primera llamada a la API.
Revisa primero la guía de Primeros pasos si aún no has cubierto los requisitos previos, el acceso de red y el modelo de seguridad.
Lo que harás
Sección titulada «Lo que harás»- Crear una aplicación OAuth: registra una app nativa en Prevu3D y obtén un Client ID
- Configurar el acceso del usuario: asegúrate de que el usuario que inicia sesión pueda acceder a los datos que necesita
- Autorizar con PKCE: envía al usuario a través de la página de consentimiento del navegador
- Intercambiar el código por un token: canjea el código de autorización por un token de acceso
- Encontrar tu URL de la API: descubre la URL base de tu organización (varía según la región)
- Realizar tu primera llamada: prueba la conexión con una solicitud sencilla
Paso 1: crea tu aplicación OAuth
Sección titulada «Paso 1: crea tu aplicación OAuth»- Inicia sesión en la Plataforma Prevu3D.
- Ve a Settings → OAuth.
- Haz clic para crear una nueva aplicación.
- Activa Authorization Code flow.
- Activa Native Application. El URI de redireccionamiento queda fijado a
http://localhost. - Deja el secreto de cliente desactivado. Las apps nativas no usan uno.
- Copia y guarda de forma segura tu Client ID. Lo necesitarás para cada autorización.
Paso 2: configura el acceso del usuario
Sección titulada «Paso 2: configura el acceso del usuario»El flujo nativo llama a la API como el usuario con sesión iniciada, no como un usuario de servicio. Esto cubre las capas 2 y 3 del modelo de seguridad: qué nodos puede ver el usuario (acceso al contenido) y qué puede hacer con ellos (acceso por rol / permiso).
- Asegúrate de que el usuario que iniciará sesión tenga acceso al contenido de los nodos (organizaciones, divisiones, sitios, etc.) que requiere tu caso de uso.
- Asegúrate de que el usuario tenga un rol en esos nodos con los permisos que tu integración necesita (leer, editar, gestionar, etc.).
En la pantalla de consentimiento, el usuario también selecciona qué organización autorizar. Los ámbitos que el usuario aprueba allí configuran la capa 1.
Paso 3: autoriza con PKCE
Sección titulada «Paso 3: autoriza con PKCE»Las apps nativas no pueden guardar un secreto, por lo que el flujo usa PKCE para proteger el código de autorización. Antes de abrir la página de consentimiento, genera tres valores:
| Valor | Cómo |
|---|---|
code_verifier | Cadena aleatoria, de 43 a 128 caracteres |
code_challenge | BASE64URL(SHA256(code_verifier)) sin relleno |
state | Cadena aleatoria; valídala cuando vuelva el redireccionamiento |
Inicia un servidor loopback local en un puerto libre y luego abre el navegador del usuario en la página de consentimiento.
URL de consentimiento: https://cloud.prevu3d.com/oauth
Parámetros de consulta (todos obligatorios):
| Parámetro | Valor |
|---|---|
response_type | code |
code_challenge_method | S256 |
client_id | Tu Client ID |
redirect_uri | Tu URI loopback, p. ej. http://localhost:8765 (incluye el puerto, sin barra final) |
scopes | Uno por ámbito, p. ej. scopes=read:basic&scopes=read:hierarchy |
code_challenge | El desafío PKCE de arriba |
state | Tu valor de state aleatorio |
Después de que el usuario inicie sesión y haga clic en Allow, el navegador redirige a tu URI loopback:
http://localhost:8765/?code={authorization_code}&state={state}Si el usuario deniega el acceso, recibes ?error=access_denied en su lugar. Los códigos de autorización caducan a los 60 segundos, así que intercámbialos de inmediato.
Paso 4: intercambia el código por un token de acceso
Sección titulada «Paso 4: intercambia el código por un token de acceso»Endpoint: POST https://cloud-api.prevu3d.com/oauth/token
Cabeceras: Content-Type: application/x-www-form-urlencoded
Cuerpo:
| Campo | Valor |
|---|---|
grant_type | authorization_code |
client_id | Tu Client ID |
code | Código del redireccionamiento |
redirect_uri | El mismo URI usado en el paso 3 (incluido el puerto) |
code_verifier | El verificador PKCE original |
No envíes un secreto de cliente para las apps nativas.
Ejemplo de respuesta:
{ "hasError": false, "expires_in": 86400, "access_token": "eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9...", "refresh_token": "..."}Guarda ambos tokens. Usa el access_token para las llamadas a la API. Cuando caduque, solicita uno nuevo con grant_type=refresh_token y tu refresh_token almacenado (no se requiere secreto de cliente).
Paso 5: obtén la URL base de tu API
Sección titulada «Paso 5: obtén la URL base de tu API»Llama al endpoint de detección para obtener la apiUrl de tu organización. No codifiques de forma fija una URL regional.
Endpoint: GET https://cloud-api.prevu3d.com/oauth/api-info
Cabeceras: Authorization: Bearer <your_access_token>
Ejemplo de respuesta:
{ "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 el valor de apiUrl como base para todas tus llamadas a la API. Anota también el organization.id, que necesitarás para muchos endpoints.
Paso 6: realiza tu primera llamada a la API
Sección titulada «Paso 6: realiza tu primera llamada a la API»Ahora tienes todo lo necesario: un token de acceso y tu URL base. Hagamos una solicitud sencilla para recuperar las divisiones de tu organización:
GET {apiUrl}/v1/nodes/{organization_id}/browseAuthorization: Bearer <your_access_token>Ejemplo con valores reales:
GET https://api-ue1.prevu3d.com/realityconnect-api/v1/nodes/217ebd23-ec54-4af0-a6d6-4a441a6d1966/browse HTTP/1.1Authorization: Bearer eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9...Una respuesta correcta que contenga una lista de divisiones confirma que tu integración funciona correctamente.
Pruébalo con Python
Sección titulada «Pruébalo con Python»Aquí tienes un script completo que hace todo lo anterior. Reemplaza client_id por tu Client ID y luego ejecútalo. Inicia un servidor loopback temporal, abre la página de consentimiento en tu navegador e imprime las divisiones de tu organización una vez que apruebes.
import base64import hashlibimport jsonimport secretsimport webbrowserfrom http.server import BaseHTTPRequestHandler, HTTPServerfrom 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"]
# Step 1: Authorize with PKCE and get an access tokenverifier = 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"]
# Step 2: Get your API URL and org IDapi_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"]
# Step 3: Browse divisionsdivisions = requests.get( f"{api_url}/v1/nodes/{organization_id}/browse", headers={"Authorization": f"Bearer {access_token}"},).json()
print("Divisions:", json.dumps(divisions, indent=2))Resolución de problemas
Sección titulada «Resolución de problemas»| Si ves… | Prueba esto… |
|---|---|
| Solicitud de grant de OAuth no válida tras hacer clic en Allow | Confirma que estás usando el Client ID de una app nativa (con Authorization Code y Native app activados). Una app solo de Client Credentials no tiene URI de redireccionamiento y no puede completar este flujo. |
| Error de la página de consentimiento sobre los parámetros de consulta | Asegúrate de que response_type=code, code_challenge_method=S256 y todos los parámetros obligatorios estén presentes, incluidos state y scopes. |
| 400 o 403 en el intercambio de token | Puede que el código haya caducado (límite de 60 segundos), que el redirect_uri no coincida con el del paso 3, o que el verificador y el desafío PKCE no coincidan. |
| 403 Forbidden al llamar a la API | Una solicitud debe superar las tres capas de seguridad. Comprueba los ámbitos de OAuth, el acceso al contenido del usuario con sesión iniciada y el rol del usuario en el nodo de destino. |
| Organización incorrecta en las respuestas de la API | El usuario selecciona la organización en la pantalla de consentimiento. Vuelve a autorizar y elige la correcta. |
Para problemas de conexión, DNS y URL de la API, consulta Primeros pasos.
¿Qué sigue?
Sección titulada «¿Qué sigue?»- Añade lógica para renovar tu token antes de que caduque usando
grant_type=refresh_tokencon tu token de actualización almacenado. - Explora la referencia de la API para ver todas las operaciones disponibles.