Skip to Content

Vanilla JS Integration

⚡ 10 min read

Plain HTML + JavaScript with the Transcodes CDN script — no bundler required. Same redirect flow as React/Vue/Next.js.

Canonical walkthrough: Signin · API: Redirect API


Before you start

RequirementWhere
Project IDConsole → Installation Guide
CDN scriptCopy snippet — replace {YOUR_PROJECT_ID}
SDK Redirect OriginsConsole → Configuration → Domains if callback returns to your host
MembersConsole → RBAC → Users

Load the SDK

index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>My App</title> <script src="https://cdn.transcodes.link/YOUR_PROJECT_ID/webworker.js" defer ></script> </head> <body> <button id="signin-btn" type="button">Sign in</button> <button id="signout-btn" type="button" hidden>Sign out</button> <button id="delete-btn" type="button" hidden>Delete document</button> <script src="./app.js" defer></script> </body> </html>

Load your app logic after the CDN script (defer on app.js or wait for DOMContentLoaded). Use window.transcodes — do not call APIs before the module script runs.


Bootstrap on load

handleSignInCallback() is safe on every page load — no session change when ?sid= is missing (success: false, AUTH_CANCELLED).

public/app.js
document.addEventListener('DOMContentLoaded', async () => { const result = await transcodes.handleSignInCallback(); if (result?.success) { updateUI(true); } else { updateUI(await transcodes.token.isAuthenticated()); } transcodes.on('AUTH_STATE_CHANGED', ({ isAuthenticated }) => { updateUI(isAuthenticated); }); }); function updateUI(isAuthenticated) { document.getElementById('signin-btn').hidden = isAuthenticated; document.getElementById('signout-btn').hidden = !isAuthenticated; document.getElementById('delete-btn').hidden = !isAuthenticated; }

Sign in / sign out

document.getElementById('signin-btn').addEventListener('click', () => { transcodes.redirectToSignIn(); // optional: transcodes.redirectToSignIn({ redirectUri: 'https://app.example.com/' }); }); document.getElementById('signout-btn').addEventListener('click', async () => { await transcodes.token.signOut(); });

Step-up (sensitive action)

Requires an active signed-in session. Opens Transcodes Auth in a new tab and polls on your page.

document.getElementById('delete-btn').addEventListener('click', async () => { const res = await transcodes.redirectToStepUp({ resource: 'documents', action: 'delete', }); const gate = res.payload[0]; const ok = res.success && (gate?.decision === 'allow' || (gate?.decision === 'stepup' && gate?.status === 'verified')); if (ok) { // run sensitive action } });

Check decision and status === 'verified' — not success alone. Step-up Auth


Fetch with member JWT

const token = await transcodes.token.getAccessToken(); const response = await fetch('/api/me', { headers: { Authorization: `Bearer ${token}` }, });

Verify JWT on your server with ES256 — Step 5.


Common mistakes

MistakeFix
Calling transcodes before CDN loadsDOMContentLoaded or defer ordering
isAuthenticated() without awaitAlways async
Unregistered callback URLSDK Redirect Origins in Console
Popup blocked during step-upAllow popups for your origin

Other frameworks

Last updated on