Vanilla JS Integration
⚡ 10 min readPlain 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
| Requirement | Where |
|---|---|
| Project ID | Console → Installation Guide |
| CDN script | Copy snippet — replace {YOUR_PROJECT_ID} |
| SDK Redirect Origins | Console → Configuration → Domains if callback returns to your host |
| Members | Console → 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
| Mistake | Fix |
|---|---|
Calling transcodes before CDN loads | DOMContentLoaded or defer ordering |
isAuthenticated() without await | Always async |
| Unregistered callback URL | SDK Redirect Origins in Console |
| Popup blocked during step-up | Allow popups for your origin |
Other frameworks
Last updated on