Skip to Content
DocumentationIntegrationOverview

Integration Guides

⚡ 12 min read

Integrate Transcodes WebAuthn/Passkey authentication into your application. Choose your framework below.


Choose Your Framework


Framework Comparison

FrameworkBuild ToolTypeScriptSSRState Management
ReactViteYesNoContext API
Next.jsNext.jsYesYesContext API
Vue.jsViteYesNoComposables / Pinia
Vanilla JSViteNoNoClass / Module

Universal Setup

All integrations follow the same core steps:

1. Add SDK Script

Add the Transcodes SDK to your HTML. For Vite projects, use environment variable placeholders:

index.html
<script type="module" src="https://cdn.transcodes.link/%VITE_TRANSCODES_PROJECT_ID%/webworker.js" ></script>

For Next.js, use the next/script component:

app/layout.tsx
<Script src={`https://cdn.transcodes.link/${process.env.NEXT_PUBLIC_TRANSCODES_PROJECT_ID}/webworker.js`} strategy='beforeInteractive' />

2. Set Environment Variables

Vite (React, Vue, Vanilla):

.env
VITE_TRANSCODES_PROJECT_ID=proj_abc123xyz

Next.js:

.env.local
NEXT_PUBLIC_TRANSCODES_PROJECT_ID=proj_abc123xyz

3. Open Login Modal

const result = await transcodes.openAuthLoginModal({ projectId: 'proj_abc123xyz', }); if (result.success) { const { token, user } = result.payload[0]; console.log('Logged in as:', user.email); }

4. Check Authentication Status

isAuthenticated() is an async method. Always use await.

// CORRECT: use await const isAuth = await transcodes.token.isAuthenticated(); if (isAuth) { // User is logged in }

5. Subscribe to Auth Events

// on() returns an unsubscribe function const unsubscribe = transcodes.on('AUTH_STATE_CHANGED', (payload) => { console.log('Auth state:', payload.isAuthenticated); }); // Later: cleanup unsubscribe();

6. Sign Out

await transcodes.token.signOut();

SDK API Overview

The Transcodes SDK exposes the following on the global transcodes object:

// Token Management transcodes.token.getCurrentUser(): Promise<User | null> transcodes.token.getAccessToken(): Promise<string | null> transcodes.token.hasToken(): boolean transcodes.token.hasPrivateKey(): Promise<boolean> transcodes.token.validateToken(): boolean transcodes.token.isAuthenticated(): Promise<boolean> // async! transcodes.token.signOut(): Promise<void> // User Information transcodes.user.get(params): Promise<ApiResponse<User[]>> // Authentication Modals transcodes.openAuthLoginModal(params): Promise<ApiResponse<AuthResult[]>> transcodes.openAuthModal(params): Promise<ApiResponse<null>> transcodes.openAuthMfaModal(params): Promise<ApiResponse<AuthResult[]>> // Event Subscription transcodes.on(event, callback): () => void // returns unsubscribe transcodes.off(event, callback): void

Available Events

EventDescription
AUTH_STATE_CHANGEDAuthentication state changed (login/logout)
TOKEN_REFRESHEDAccess token was automatically refreshed
TOKEN_EXPIREDToken expired and cannot be refreshed
ERRORSDK error occurred

TypeScript Support

All framework guides include complete TypeScript type definitions. Here’s a summary:

types/transcodes.d.ts
declare global { const transcodes: { token: { getCurrentUser(): Promise<User | null>; getAccessToken(): Promise<string | null>; hasToken(): boolean; hasPrivateKey(): Promise<boolean>; validateToken(): boolean; isAuthenticated(): Promise<boolean>; signOut(): Promise<void>; }; user: { get(params: { projectId?: string; userId?: string; email?: string; fields?: string; }): Promise<ApiResponse<User[]>>; }; on<T extends TranscodesEventName>( event: T, callback: (payload: TranscodesEventMap[T]) => void ): () => void; off<T extends TranscodesEventName>( event: T, callback: (payload: TranscodesEventMap[T]) => void ): void; openAuthLoginModal(params: { projectId?: string; userId?: string; }): Promise<ApiResponse<AuthResult[]>>; openAuthModal(params: { userId: string; projectId?: string; }): Promise<ApiResponse<null>>; openAuthMfaModal(params: { userId: string; projectId?: string; }): Promise<ApiResponse<AuthResult[]>>; }; } type TranscodesEventName = | 'AUTH_STATE_CHANGED' | 'TOKEN_REFRESHED' | 'TOKEN_EXPIRED' | 'ERROR';

See individual framework guides for complete type definitions.


Common Patterns

Protected Route Pattern

All frameworks implement a similar protected route pattern:

  1. Check isAuthenticated() (async)
  2. If not authenticated, show login modal
  3. If login cancelled, redirect to home
  4. If authenticated, render protected content

React/Next.js: <ProtectedRoute> component with useEffect Vue: <AuthGuard> component with watch Vanilla JS: init() function with async/await

Auth State Management

FrameworkPatternFile
ReactContext + use() hookAuthContext.tsx
Next.jsContext + 'use client'AuthProvider.tsx
VueComposable / PiniauseAuth.ts / auth.ts
Vanilla JSClass / Moduleauth.js

Common Mistakes

// WRONG: isAuthenticated() is async if (transcodes.token.isAuthenticated()) { // This always runs! (Promise is truthy) } // CORRECT: use await if (await transcodes.token.isAuthenticated()) { // This correctly checks auth status }
// WRONG: Method name await transcodes.token.logout(); // CORRECT: use signOut await transcodes.token.signOut();

Troubleshooting

SDK Not Loading

// Check if SDK is loaded if (typeof transcodes === 'undefined') { console.error('Transcodes SDK not loaded'); }

CORS Errors

Ensure your domain is added to the allowed list in the Transcodes Dashboard :

  • localhost:5173 (Vite dev server)
  • localhost:3000 (Next.js dev server)
  • yourdomain.com (production)

CSP (Content Security Policy)

Add Transcodes domains to your CSP headers:

<meta http-equiv="Content-Security-Policy" content=" script-src 'self' https://cdn.transcodes.link; connect-src 'self' https://api.transcodes.io; frame-src 'self' https://auth.transcodes.io; " />

Next Steps

Last updated on