コンテンツにスキップ

ネイティブアプリケーションフロー

Native appフローは、デスクトップアプリ、CLI、CADプラグインなど、サインインしたユーザーのマシン上でユーザーの代理として動作する統合に使用します。PKCE付きAuthorization Codelocalhostループバックリダイレクトクライアントシークレットなしを使用します。このガイドでは、OAuthアプリケーションの作成から最初のAPI呼び出しまでを説明します。

前提条件、ネットワークアクセス、セキュリティモデルをまだ確認していない場合は、先にセットアップガイドを読んでください。


  1. OAuthアプリケーションを作成する:Prevu3Dにネイティブアプリを登録し、Client IDを取得する
  2. ユーザーアクセスを設定する:サインインするユーザーが必要なデータにアクセスできることを確認する
  3. PKCEで承認する:ブラウザの同意ページにユーザーを送る
  4. コードをトークンと交換する:認可コードをアクセストークンと交換する
  5. API URLを見つける:組織のベースURLを確認する(リージョンによって異なります)
  6. 最初の呼び出しを行う:簡単なリクエストで接続をテストする

ステップ1:OAuthアプリケーションを作成する

Section titled “ステップ1:OAuthアプリケーションを作成する”
  1. Prevu3D Platform(またはプレプロダクション環境)にログインします。
  2. SettingsOAuthに移動します。
  3. クリックして新しいアプリケーションを作成します。
  4. Authorization Code flowを有効にします。
  5. Native Applicationを有効にします。リダイレクトURIはhttp://localhostに固定されています。
  6. クライアントシークレットはオフのままにします。ネイティブアプリでは使用しません。
  7. Client IDをコピーして安全に保管します。すべての認可で必要になります。

ステップ2:ユーザーアクセスを設定する

Section titled “ステップ2:ユーザーアクセスを設定する”

ネイティブフローはサービスユーザーではなく、サインインしたユーザーとしてAPIを呼び出します。これはセキュリティモデルのレイヤー2と3に該当します。ユーザーがどのノードを参照できるか(コンテンツアクセス)、およびそれに対して何ができるか(ロール / 権限アクセス)です。

  1. サインインするユーザーが、ユースケースに必要なノード(組織、ディビジョン、サイトなど)へのコンテンツアクセスを持っていることを確認します。
  2. ユーザーがそれらのノードで、統合に必要な権限を持つロールを持っていることを確認します(読み取り、編集、管理など)。

同意画面では、ユーザーは承認する組織も選択します。そこで承認されたスコープがレイヤー1を設定します。

ネイティブアプリはシークレットを保持できないため、このフローでは認可コードを保護するためにPKCEを使用します。同意ページを開く前に、次の3つの値を生成します。

方法
code_verifier43〜128文字のランダム文字列
code_challengeパディングなしのBASE64URL(SHA256(code_verifier))
stateランダム文字列。リダイレクト時に検証する

空いているポートでローカルループバックサーバーを起動し、ユーザーのブラウザで同意ページを開きます。

本番の同意URL: https://cloud.prevu3d.com/oauth

プレプロダクションの同意URL: https://cloud.preproduction.prevu3d-int.com/oauth

クエリパラメータ(すべて必須):

パラメータ
response_typecode
code_challenge_methodS256
client_idあなたのClient ID
redirect_uriループバックURI。例:http://localhost:8765(ポートを含め、末尾のスラッシュは付けない)
scopesスコープごとに1パラメータ。例:scopes=read:basic&scopes=read:hierarchy
code_challenge上で生成したPKCEチャレンジ
stateランダムなstate値

ユーザーがサインインしてAllowをクリックすると、ブラウザはループバックURIにリダイレクトします。

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

ユーザーがアクセスを拒否した場合は、代わりに?error=access_deniedを受け取ります。認可コードは60秒で期限切れになるため、すぐに交換してください。

ステップ4:コードをアクセストークンと交換する

Section titled “ステップ4:コードをアクセストークンと交換する”

エンドポイント: POST https://cloud-api.prevu3d.com/oauth/token

ヘッダー: Content-Type: application/x-www-form-urlencoded

ボディ:

フィールド
grant_typeauthorization_code
client_idあなたのClient ID
codeリダイレクトで受け取ったコード
redirect_uriステップ3と同じURI(ポートを含む)
code_verifier元のPKCE verifier

ネイティブアプリではクライアントシークレットを送信しないでください。

レスポンス例:

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

両方のトークンを保存します。API呼び出しにはaccess_tokenを使用します。期限切れになったら、保存したrefresh_tokengrant_type=refresh_tokenを使って新しいトークンをリクエストします(クライアントシークレットは不要です)。

ステップ5:APIベースURLを取得する

Section titled “ステップ5:APIベースURLを取得する”

検出エンドポイントを呼び出して、組織のapiUrlを取得します。リージョンURLをハードコードしないでください。

エンドポイント: GET https://cloud-api.prevu3d.com/oauth/api-info

ヘッダー: Authorization: Bearer <your_access_token>

レスポンス例:

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

apiUrlの値をすべてのAPI呼び出しのベースとして使用します。多くのエンドポイントで必要になるorganization.idもメモしておいてください。

ステップ6:最初のAPI呼び出しを行う

Section titled “ステップ6:最初のAPI呼び出しを行う”

必要なものはすべて揃いました。アクセストークンとベースURLです。組織のディビジョンを取得する簡単なリクエストを送ってみましょう。

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

実際の値を使った例:

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

ディビジョンのリストを含む成功レスポンスは、統合が正しく動作していることを示します。

以下は、上記のすべてを実行する完全なスクリプトです。client_idをあなたのClient IDに置き換えて実行してください。一時的なループバックサーバーを起動し、ブラウザで同意ページを開き、承認後に組織のディビジョンを出力します。

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"]
# Step 1: Authorize with PKCE and get an 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"]
# Step 2: Get your API URL and org ID
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"]
# Step 3: Browse divisions
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))
表示される内容試すこと
Allowクリック後のInvalid OAuth grant requestネイティブアプリのClient IDを使用していることを確認してください(Authorization CodeとNative appが有効)。Client CredentialsのみのアプリにはリダイレクトURIがなく、このフローを完了できません。
アプリ作成時のRedirect URI domain must be verifiedカスタムリダイレクトURIを入力しないでください。代わりにNative appトグルをオンにしてください。現在登録できるのはhttp://localhost(ポートなし、シークレットなし)のみです。
クエリパラメータに関する同意ページのエラーresponse_type=codecode_challenge_method=S256、およびstatescopesを含むすべての必須パラメータが揃っていることを確認してください。
トークン交換時の400または403コードの期限切れ(60秒制限)、redirect_uriがステップ3と一致しない、またはPKCE verifierとchallengeが一致しない可能性があります。
API呼び出し時の403 Forbiddenリクエストは3つのセキュリティレイヤーすべてを通過する必要があります。OAuthスコープ、サインインしたユーザーのコンテンツアクセス、対象ノードでのユーザーのロールを確認してください。
APIレスポンスの組織が間違っているユーザーは同意画面で組織を選択します。再承認して正しい組織を選んでください。

接続、DNS、API URLの問題については、セットアップ — API URLとネットワークアクセスを参照してください。

  • 本番利用では、保存したリフレッシュトークンでgrant_type=refresh_tokenを使い、トークンが期限切れになる前に更新するロジックを追加してください。
  • APIリファレンスですべての利用可能な操作を確認してください。