Redirect API
⚡ 8 min readHosted auth on Transcodes Auth — your app redirects; Transcodes renders MFA UI.
| Method | Purpose |
|---|---|
redirectToSignIn() | Member sign-in / sign-up |
handleSignInCallback() | Exchange ?sid= on return URL |
redirectToConsole() | Self-service passkey / TOTP management |
redirectToStepUp() | RBAC-gated step-up MFA |
handleStepUpReturnPage() | Auth-tab bootstrap after step-up MFA |
Return values (summary)
| Method | TypeScript return | Await? | Failure visible to caller? |
|---|---|---|---|
redirectToSignIn() | void | No | No — errors go to console.error only |
redirectToConsole() | void | No | No — errors go to console.error only |
redirectToStepUp() | Promise<ApiResponse<StepUpRedirectResult[]>> | Yes | Yes — check success, payload[0].decision, and status |
handleSignInCallback() | Promise<ApiResponse<AuthResult[]>> | Yes | Yes |
handleStepUpReturnPage() | void | No | No |
Only redirectToStepUp (and handleSignInCallback on the return page) give you a programmatic result. Sign-in and console redirects are fire-and-forget navigation — session outcome is handled on the callback page or not at all.
Guides: Signin · Console · Step-up Auth
redirectToSignIn()
Starts a full-page redirect to Transcodes Auth (tc_mode=signin).
transcodes.redirectToSignIn(options?: {
projectId?: string;
redirectUri?: string; // default: current page URL
browserUrl?: string; // advanced: pre-built session URL
}): voidFire-and-forget — void, not a Promise. The public wrapper discards the internal async work (void redirectToSignIn(...)). Failures (session create failed, invalid browserUrl) log to console.error and return without throwing — your code cannot await an error.
Session exchange happens later in handleSignInCallback on the return URL.
transcodes.redirectToSignIn();
// or
transcodes.redirectToSignIn({ redirectUri: 'https://app.example.com/' });handleSignInCallback()
Call once on the page that receives ?sid= after sign-in.
transcodes.handleSignInCallback(): Promise<ApiResponse<AuthResult[]>>success: true— JWT stored in IndexedDB;AUTH_STATE_CHANGEDfires.- No
?sid=on the URL — no session change. The public wrapper still returns{ success: false, payload: [], error: 'Authentication cancelled by user' }(AUTH_CANCELLED). Safe to call on every page load — only branch onresult.success === true.
const result = await transcodes.handleSignInCallback();
if (result.success) {
const { token, member } = result.payload[0];
}
// result.success === false on normal pages — ignore unless you need error UXredirectToConsole()
Opens member credential management (tc_mode=console). Requires active SDK session.
transcodes.redirectToConsole(options?: {
organizationId?: string;
projectId?: string;
memberId?: string;
redirectUri?: string;
comment?: string;
browserUrl?: string;
}): voidFire-and-forget — void, same as redirectToSignIn. Requires active SDK session; if not signed in or session create fails, logs console.error and does nothing (no throw, no return value).
transcodes.redirectToConsole();See Console.
redirectToStepUp()
RBAC gate + optional step-up in a new tab with host-page polling overlay. Requires active SDK session (same as redirectToConsole) — returns { success: false, message: 'No active session — sign in first' } when not signed in.
transcodes.redirectToStepUp(options: {
resource: string;
action: 'create' | 'read' | 'update' | 'delete';
redirectUri?: string;
comment?: string;
}): Promise<ApiResponse<StepUpRedirectResult[]>>Always await this method. Unlike the other redirects, it resolves in place (polling overlay on your page).
| Outcome | Typical success | payload[0] | Notes |
|---|---|---|---|
| RBAC allows (no MFA) | true | decision: 'allow' | Tab closed immediately |
| RBAC denies | true | decision: 'deny' | success is still true — check decision |
| Step-up verified | true | decision: 'stepup', status: 'verified' | After poll completes |
| Step-up rejected / timeout / overlay cancel | false | decision: 'stepup', status: 'rejected' | error + message set |
| No active session | false | [] | message: 'No active session — sign in first' |
| Popup blocked | false | [] | message: 'Unable to open authentication tab — check popup blocker settings' |
| SDK not initialized | false | [] | error: INIT_SDK_NOT_INITIALIZED |
Check decision, not success alone:
decision | Meaning |
|---|---|
allow | Proceed without MFA |
deny | Blocked by RBAC |
stepup | MFA required — check status === 'verified' after poll |
const res = await transcodes.redirectToStepUp({
resource: 'members',
action: 'delete',
});
const gate = res.payload[0];
const ok =
res.success &&
(gate?.decision === 'allow' ||
(gate?.decision === 'stepup' && gate?.status === 'verified'));handleStepUpReturnPage()
Run on the auth-host return page (/auth/stepup-callback?sid=) after the member completes MFA in the step-up tab.
transcodes.handleStepUpReturnPage(): voidTypes
interface AuthResult {
token: string;
member: Member;
}
interface StepUpRedirectResult {
decision: 'deny' | 'allow' | 'stepup';
resource: string;
action: string;
sid?: string;
url?: string;
expiresAt?: string;
status?: 'verified' | 'rejected';
}
interface ApiResponse<T> {
success: boolean;
payload: T;
error?: string;
}