Stirling-Tools/Stirling-PDF · warning · Error
No authentication token available
Error message
No authentication token available
What it means
Thrown by requireToken() in the desktop billing service when authService.getAuthToken() resolves to a falsy value. The user is not signed in, so there is no desktop JWT to attach as the Bearer header for the Stripe edge-function calls (create-checkout-session / create-customer-portal-session).
Source
Thrown at frontend/editor/src/desktop/services/billing.ts:42
export type {
CheckoutParams,
CheckoutSession,
PortalParams,
PortalSession,
} from "@cloud/services/billing";
/**
* Deep-link the SaaS billing backend uses as Stripe's success/cancel/return
* URL on desktop. The OS routes it back to the running app, which the deep-link
* handler picks up to refresh the wallet after checkout/portal.
*/
const DESKTOP_BILLING_RETURN_URL = "stirlingpdf://billing/return";
/** Resolve the desktop JWT, throwing a friendly error when signed out. */
async function requireToken(): Promise<string> {
const token = await authService.getAuthToken();
if (!token) {
throw new Error("No authentication token available");
}
return token;
}
/**
* Create a Stripe Checkout Session for the PAYG subscription via the
* {@code create-checkout-session} edge function (see StripeCheckoutPanel),
* routed through Tauri (explicit bearer, deep-link callback). The Tauri webview
* has no CSP, so the component mounts the embedded Stripe iframe from the
* returned clientSecret (falling back to the hosted url otherwise).
*/
export async function createCheckoutSession(
params: CheckoutParams,
): Promise<CheckoutSession> {
const token = await requireToken();
const { data, error } = await supabase.functions.invoke<{
client_secret?: string;View on GitHub (pinned to 9ef20dcab8)
Solutions
- Gate the billing UI behind an authenticated check and prompt sign-in before calling these functions.
- Call authService.ensureSession() / await a valid token before invoking billing, retrying once after a refresh.
- If the token genuinely expired, route the user to the login screen before billing.
Example fix
// before
const session = await createCheckoutSession(params);
// after: ensure a token exists first
const token = await authService.getAuthToken();
if (!token) { navigateToLogin(); return; }
const session = await createCheckoutSession(params); Defensive patterns
Strategy: validation
Validate before calling
const token = await authService.getAuthToken();
if (!token) { navigateToLogin(); return; } Type guard
function isMissingToken(e: unknown): e is Error {
return e instanceof Error && e.message === 'No authentication token available';
} Try / catch
try { await createCheckoutSession(params); }
catch (e) {
if (isMissingToken(e)) { navigateToLogin(); return; }
throw e;
} Prevention
- Gate billing/wallet UI behind an authenticated check.
- Call getAuthToken() once and pass it down instead of re-resolving per call.
- Re-check auth before any Stripe flow since tokens expire.
When it happens
Trigger: Calling createCheckoutSession() or createPortalSession() while signed out: no token in the Tauri store, the session expired and refresh failed, or logout just ran. getAuthToken() returns null/empty.
Common situations: Billing/wallet UI rendered before login completes; JWT expired and the refresh path failed silently; user navigated to upgrade flow after signing out in another window.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Failed to save authentication token
- Unable to open system browser for SSO. Please check your sys
- unconfigured
- Edge function ${name} failed
- Edge function ${name} returned no data
AI-assisted analysis of Stirling-Tools/Stirling-PDF@9ef20dcab8 (2026-08-13).
Data as JSON: /api/errors/670a32cdc0d5af0a.
Report an issue: GitHub.