Sketchfab APIを使って3DモデルをGLBファイルとしてダウンロードし、ブラウザ上でThree.jsで表示するWebアプリを作成しました。本記事では、セキュリティを考慮したアーキテクチャ設計から実装まで解説します。

やりたかったこと

  • Sketchfab上の3DモデルをGLB形式でダウンロードしたい
  • ダウンロードしたGLBをブラウザ上で3D表示したい
  • APIトークンを安全に管理したい

技術スタック

  • Next.js 16(App Router)
  • React Three Fiber / @react-three/drei
  • TypeScript

最初に試したこと:クライアントサイドのみで実装

最初はシンプルにHTML + JavaScriptだけで実装しようとしました。

c)cco;oon`{}nnSshssktth}toeteltrpa'decesdAa.hs:eutlfprtaoa/shgbna:o=(sprdAei{iaaP.zwtI=saaakti.aeitgwtolacnrbih'e.tf:suaprfb`olUe.Tn)Rtcos;Lcokehme.(/njvs3$o/{nma(op)di;SeT3loskU/eR$nL{}m`odelUid}/download`,

これ自体は動作しましたが、2つの問題がありました。

問題1: APIトークンの露出

クライアントサイドでAPIトークンを使用すると、ブラウザの開発者ツールから簡単に確認できてしまいます。APIトークンが漏洩すると、他人があなたのアカウントでAPIを利用できてしまうため、これは避けるべきです。

問題2: CORSエラー(場合による)

ブラウザのセキュリティ制限により、異なるオリジンへのリクエストが制限されることがあります。今回のケースでは、Sketchfab APIへのリクエスト自体はCORSが許可されていましたが、環境によっては問題になる可能性があります。

解決策:サーバーサイドAPIを経由する設計

Next.jsのAPI Routesを使って、サーバーサイドでSketchfab APIと通信する設計にしました。

(CBlrioewnster)S3(UNGRe(LLxSBte).rjvserA)PISketchfabAPI

ポイント:署名付きURLの活用

Sketchfab APIは、GLBファイルの実体ではなく「署名付きS3 URL」を返します。

{}"}gl"""buse"rix:lzp"ei{:"r:e"sh1"t0:t0p43s80:00/8/,sketchfab-prod-media.s3.amazonaws.com/archives/.../model.glb?AWSAccessKeyId=...&Signature=...&Expires=1769553560",

この署名付きURLには以下の特徴があります:

  • 有効期限付き (数分で無効化)
  • 特定ファイルへのアクセスのみ許可
  • 読み取り専用

つまり、この署名付きURLをクライアントに渡しても安全です。クライアントはこのURLから直接S3にアクセスしてGLBをダウンロードできます。

なぜサーバー経由でGLBを転送しないのか?

サーバー経由でGLBファイル全体を転送する方法もありますが、以下の理由から署名付きURLを返す方式を採用しました:

方式メリットデメリット
サーバー経由でGLB転送CORSを完全に回避サーバー負荷大、転送速度低下
署名付きURLを返す高速、サーバー負荷なしCORSに依存(今回は問題なし)

Sketchfab S3は Access-Control-Allow-Origin: * を返すため、クライアントから直接アクセス可能でした。

実装

1. 環境変数の設定

#SK.EeTnCvH.FlAoBc_aAlPI_TOKEN=your_api_token_here

APIトークンはサーバーサイドでのみ使用するため、NEXT_PUBLIC_ プレフィックスは付けません。

2. API Route(サーバーサイド)

ie}mxppccc)cr}sooooo;oe)rrrnnn`{}ntuse;cttssSshsurix/ttktth}trlzpa{aete,n:eipsmatrpaAd:rpNyopcesduaUNde/endihs:ettReadsaxceTfprhaLxta:ptloa/sotatiRfUkbna:r=R.ad/euiespieg.asqndnAei{zaslgtkucP.awpblaeet==I=stao.b.tsikiinu.gctorpaeotsrslh,nerwtnelibfqoac:r.,z.aNGucihejeebeEeetf`ss,x/xTssaTpopdt(tsfboonioRr..Ue.kn(rweeneRtces{ensqenLconeslpuxvhm.,ooet.(/$jansUSv{sdstrK3ao/e:lE/pnr.Tmi(o}NsCoT)ueeHdo;tfxaFekertrAle.oRcBsntmeh_/}sqPA$`'uaP{,nerImesa_oxtmTdt)sOe/.Kls{gEUeeNirt;dv(}e'/rud'io;dw'n)l;oad`,

3. GLBビューワーコンポーネント(クライアントサイド)

'iiiif}e}ummmmuxsppppncr)pcu}r)seoooocoe;oos,e;rrrrrtnt<rneft<ccttttisuC/tsEe[uC//lotre<Ctft..mra<<<<Cci{{{{nnnpedfcttonnadS/Oaoegtrne[ehhhdvmiu{<SrnmnCOuGMl(eitfgc(eee(abrsgEubvptarsLotrmealt`nnlsieplnsiao'nbeTdf>irub(A/((Uecebvptsn;viLFet>lU(PardicntnUieC>eatoLl=itr)IpeadatisrrnonsCao(vlist]mLoelosntoda{uef,=/a)einnets}nedsu>s=;rgaf&m>r/treueonsk>=ahla&eoGfrrrLbce{e>=tLlnlLro}lojtttr{il<tsBol}aeiGUces{igbMVmsf}dcolRhsenhaopi,rf:etnbLf.tpttcdre'orr=UajGoekeew@Emo{({Grbslsnp=lsernmGgLl/obiso{erev'uLlB]dnUtisnut.ai@'rTtVo(ritiur=tcrrtlFfi=w)loytll"stoeh:L.en)(n=il=sx-naroswuld:{o}{ttmcesacesoa0n>guhetetdereat[.=ldrn-/ren(Sda05{bietteire{t?.,}[Uoe,hxn,}auu5r"/ragmtir2,lfCemuoedl,}ieep}rd<=)1bn/l)les$)50etfe)lt{;],>reis{;Urm,}'rb/iio7;ejdndf.}rsgeo5'm}lv]f;/:|U:}rlioo{nd4mau}5dml`'eol)}@rd>}rse(>e/lnaGUucLiltTdl-F:)tL;hosratedreei/rnd.grjes}i')';;{

4. ビューワーページ

'ic}e}umo)xspns;pcr)seoSssooe;rrStrrnt<cctR:tsum//lGtra<<maidLfdniiGapeyBae[nnvoLipnnVlfm(>panBn/taisaoulCV>['meeudtuhil;iw,leeaeocetl=nwcTrU{geafhfimerlrr=udo=eoen,d{m]medce(o/.ytsledv'jnieU)einsaotileemnMd=Uwxio}>ietcVddr/(ies=/d(ele{pyA)wUtmanPeiMogaI=rdodem>P]de.iaeltcig=lUs'meUix;p(uido)sd}re(t{Se(t.'at@ta/erc(go'em0tpd.obvn8ae3ln6ut5esf)/d}G0LcB4V4i9e3w8ebr6'6)6,34{5ef0f99d6d');

セキュリティまとめ

情報露出理由
Sketchfab APIトークン❌ 非公開サーバーサイドの環境変数で管理
署名付きS3 URL✅ 公開OK有効期限付き、特定ファイルのみ、読み取り専用

注意点

  • ダウンロード可能なモデルのみ対応 : Sketchfab上で作者が「downloadable」に設定したモデルのみAPIからダウンロードできます
  • 署名付きURLの有効期限 : 数分で期限切れになるため、長時間放置後は再取得が必要です

まとめ

Sketchfab APIを使ったGLBダウンロード・表示機能を、セキュリティを考慮して実装しました。

  • APIトークンはサーバーサイドで管理し、クライアントには露出させない
  • Sketchfabが返す署名付きURLを活用し、効率的にファイルを転送
  • React Three Fiberで簡単に3Dビューワーを構築

ソースコードは以下で公開しています:
https://github.com/nakamura196/sketchfab-api-test