I built a web app that uses the Sketchfab API to download 3D models as GLB files and display them in the browser using Three.js. This article covers everything from the security-conscious architecture design to implementation.

What I Wanted to Do

  • Download 3D models from Sketchfab in GLB format
  • Display downloaded GLB files in 3D within the browser
  • Manage API tokens securely

Tech Stack

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

First Attempt: Client-Side Only Implementation

Initially, I tried implementing it with just HTML + JavaScript.

c)cco;oon`{}nnGshssetth}tottelrpa'dedesdAa.os:eutlwprtaon/shglna:o=(osprdaei{iaad.zwt=saaaUkti.RaeitgLwtolacnrbfih'e.rtf:suoaprmfb`ole.Tn)Stcos;kcokeehme.t(/njcvsh3$oSf/{niama(gbop)ndi;eAeTdPloIskS/e3$n{}Um`RoLdelUid}/download`,

This itself worked, but there were two problems.

Problem 1: API Token Exposure

Using the API token on the client side means it can be easily viewed from the browser’s developer tools. If the API token leaks, others can use the API with your account, so this should be avoided.

Problem 2: CORS Errors (depending on circumstances)

Browser security restrictions may block requests to different origins. In this case, requests to the Sketchfab API themselves had CORS allowed, but this could be problematic in some environments.

Solution: Architecture Using Server-Side API

I designed the architecture to communicate with the Sketchfab API on the server side using Next.js API Routes.

(CBlrioewnster)SSi3gn(eNGde(LxSBUte)R.rLjvserA)PISketchfabAPI

Key Point: Using Signed URLs

The Sketchfab API returns not the GLB file itself, but a “signed 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",

This signed URL has the following characteristics:

  • Time-limited (invalidated after a few minutes)
  • Only permits access to a specific file
  • Read-only

Therefore, it is safe to pass this signed URL to the client. The client can directly access S3 using this URL to download the GLB.

Why Not Transfer GLB Through the Server?

While transferring the entire GLB file through the server is possible, the signed URL approach was adopted for the following reasons:

MethodAdvantagesDisadvantages
GLB transfer through serverCompletely avoids CORSHigh server load, slower transfer speed
Return signed URLFast, no server loadDepends on CORS (no issue in this case)

Sketchfab S3 returns Access-Control-Allow-Origin: *, so direct client access was possible.

Implementation

1. Environment Variable Setup

#SK.EeTnCvH.FlAoBc_aAlPI_TOKEN=your_api_token_here

Since the API token is only used server-side, the NEXT_PUBLIC_ prefix is not added.

2. API Route (Server-Side)

ie}mxppccc)cr}sooooo;oe)rrrnnn`{}ntuse;cttssGshsRurix/ttetth}terlzpa{atte,tn:eipsmarpaAdu:rpNyopdesduarNde/endios:ettneadsaxceTwprhaxta:ptlon/sostatiRfUklna:r=iR.ad/euieospigeg.asqndnaei{zanslgtkucd.awepblaeet===stado.b.tsiUkiinu.gctorpRaeotUsrslh,nerLwtnRelibfqoac:rL.,z.aNGucfihejeebeEeertf`sts,x/xTssoaTpoopdt(tsmfboonioRr..e.knc(rweeneStcesl{ensqenkconeislpuxvehm.e,ooet.t(/$jnansUScv{stdstrKh3ao/e:lEf/pnr.Tami(o}NsCboT)ueeHdo;tfxaFAekertrAPle.oRcBIsntmeh_/}sqPA$`'uaP{,nerImesa_oxtmTdt)sOe/.Kls{gEUeeNirt;dv(}e'/rud'io;dw'n)l;oad`,

3. GLB Viewer Component (Client-Side)

'iiiif}e}ummmmuxsppppncr)pcu}r)seoooocoe;oos,e;rrrrrtnt<rneft<ccttttisuC/tsEe[uC//lotre<Ctft..mra<<<<Cci{{{{nnnpedfGcttonnadS/Oaoegtrne[eehhhdvmiu{<SrnmnCOuGMl(eitfgct(eee(abrsgEubvptarsLotrmealt`nnlsieplnsiao'nbeTdf>irub(s/((Uecebvptsn;viLFet>lU(iardicntnUieC>eatoLl=itr)gpeadatisrrnonsCao(vlnist]mLoelosntoda{uef,=e/a)einnets}nedsu>ds=;rgaf&m>r/treueonsk>=ahla&eoGfrrrLbce{Ue>=tLlnlLro}lojttRtr{il<tsBol}aeiGLces{igbMVmsf}dcolhsenhaopi,rf:etnbff.tpttcdre'orr=UrajGoekeew@Emo{({Grobslsnp=lsernmGgLlm/obiso{erev'uLlB]dnUtisnut.ai@'rTtVso(ritiur=tcrrtlFfi=ew)loytll"stoeh:L.ern)(n=il=sx-naroswuvld:{o}{ttmcesaceseoa0n>guhetetdererat[.=ldrn-/ren(Sda05{bietteire{tA?.,}[Uoe,hxn,}aPuu5r"/ragmtIir2,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. Viewer Page

'ic}e}umo)xspns;pcr)seoLssooe;rrotrrnt<ccta:tsum//ldGtra<<maidLfdniiGapeywBae[nnvoLipnniVlfm(>panBn/tatisaoulCV>['mheeudtuhil;iw,leeaeocSetl=nwcSrU{geafRfimerlr=udo=eodn,d{m]midce(o/sytsledv'anieU)einbaotileelmnMd=Uwxeio}>ietdcVddr/(ies=/d((ele{pyT)wUtmanheiMogar=rdodeme>P]de.ieaeltc.ig=lUs'jmeUix;sp(uido)sd}dre(et{Sep(t.e'atn@tad/ersc(go'eom0tnpd.obvbn8are3lon6uwt5essf)e/d}rG0LcAB4PV4Ii9se3)w8ebr6'6)6,34{5ef0f99d6d');

Security Summary

InformationExposedReason
Sketchfab API TokenNot exposedManaged as server-side environment variable
Signed S3 URLOK to exposeTime-limited, specific file only, read-only

Notes

  • Only downloadable models are supported: Only models that the author has set as “downloadable” on Sketchfab can be downloaded via the API
  • Signed URL expiration: URLs expire after a few minutes, so re-fetching is needed after extended periods

Summary

I implemented GLB download and display functionality using the Sketchfab API with security considerations.

  • API tokens are managed server-side and not exposed to the client
  • Signed URLs returned by Sketchfab are leveraged for efficient file transfer
  • React Three Fiber makes it easy to build a 3D viewer

Source code is available at: https://github.com/nakamura196/sketchfab-api-test