What Secure Elements is
Secure Elements is a JavaScript SDK,@fluz/secure-elements, that mounts an isolated, Fluz-hosted frame directly into a container element on your page. The frame renders card data; your page and your servers only ever hold a short-lived, opaque token that authorizes one specific action.
This is a third way to show a user their own card details, alongside the two you already have:
If you’re already using the Embedded Widget for
everything, you don’t need this. Secure Elements is for headless or API-driven
integrations that still need to show a user their PAN, expiry, and CVV without
opening the full widget modal or pursuing
PCI_COMPLIANCE.How it works
Your backend mints a client token
Exchange your existing Fluz OAuth access
token for a short-lived
client token, scoped to a single reveal.
Your frontend mounts the frame
Hand the client token to
@fluz/secure-elements, which mounts the
Fluz-hosted frame into a container you provide — inline in your page, not a
modal.The SDK reports back via callbacks
Your page never reads the raw card data. It only sees success, error, or
mount events.
Prerequisites
- Your application is registered with Fluz and has the
CREATE_VIRTUALCARDscope enabled on your access token. - You have an
ACTIVEvirtual card id, owned by the account you’re revealing, to pass when minting a client token.
Environments
Reveal currently returns simulated results on staging while Fluz’s processor
integration is finalized. Use staging to validate your integration end to end
— production availability will be confirmed separately.
frameHostOrigin is optional on createCardViewer — omit it and it defaults to production (https://secure.fluz.app). Pass it explicitly to target staging. Only these two exact origins are accepted; anything else throws a FluzElementsError (error.code === "INVALID_FRAME_HOST_ORIGIN") as soon as you call createCardViewer, before any frame is mounted.
Loading the SDK
@fluz/secure-elements isn’t published to npm — load it as a browser global (IIFE) build from Fluz’s CDN with a <script> tag. It exposes a FluzSecureElements global:
FluzSecureElements, as above.
Each release publishes to an immutable, version-pinned path (.../v0.1.0/index.global.js) and a floating .../latest/index.global.js that always points at the newest release. Pin to a specific version for anything beyond a prototype — latest can change under you without notice.
Only the staging CDN host is live so far (
secure-cdn-staging.fluz.app).
Production hosting will be confirmed alongside production API availability.Mint a client token
Your backend calls this using the Fluz OAuth access token you already obtain through the standard OAuth grant flow. Never send that access token to the browser — only theclientToken / loadToken pair this endpoint returns should reach your frontend.
201. Both tokens are single-purpose and short-lived — mint a new pair for every reveal. clientToken is what authorizes the reveal itself (expiresIn seconds, 300 by default); loadToken is scoped even tighter (60 seconds) since it travels in a URL — see the note in Card Reveal — and is rejected everywhere except loading the frame. Pass both straight into createCardViewer, and never put clientToken in a URL yourself — the SDK already keeps it out of one.
Error responses
Error responses
Styling fields
createCardViewer accepts an optional style object, applied to every field it mounts:
style is validated before anything is sent to the frame. If a value doesn’t match what’s documented below, await viewer.mount(...) rejects with a FluzElementsError (error.code === "INVALID_STYLE") — wrap your mount() call in a try/catch if you’re accepting configurable style input yourself.
fontFamily must be an exact, case-sensitive match for one of two allowlists:
- System fonts — common OS/web-safe stacks (
system-ui,-apple-system,Helvetica Neue,Arial,Georgia,Menlo, and the genericmonospace/serif/sans-serifkeywords, among others). These render immediately, with no network request. - Google Fonts — any family from the Google Fonts catalog (
"Roboto","Inter","IBM Plex Mono", and so on), passed exactly as Google lists it. The SDK loads the font for you — you don’t need a<link>tag or@font-facerule.
A Google Font is fetched after the field mounts, not bundled up front, so
there’s a brief window on a cold cache where the field renders in the
browser’s fallback font before swapping in your chosen one. A system font has
no such delay.
Content Security Policy
If your page sets a CSP, allow the frame host you’re targeting:Security model
- Your OAuth access token never leaves your servers.
- The client token your frontend holds is opaque and single-purpose — it carries no card data and can’t be replayed for a different card or action.
- Card data is only ever readable inside the Fluz-hosted frame, isolated from your page’s own JavaScript. Each configured field mounts as its own sandboxed (
allow-scripts allow-same-origin allow-forms),referrerPolicy="no-referrer"iframe — the SDK never puts card data in the DOM outside of them. - The frame only renders inside origins you’ve pre-registered with Fluz.
Next steps
Card Reveal
Create the card viewer, mount it, and control which fields are revealed.
Live demo
See the card viewer running against staging, including reveal,
reveal-CVV-only, and mask.
Example integrations
Runnable plain-HTML and React examples, both calling real staging
infrastructure.
OAuth applications
How to obtain the access token you’ll exchange for a client token.