Skip to content

Error Handling

Overview

Every async method in @authrim/web returns an AuthResponse<T> — a discriminated union that makes error handling type-safe and consistent:

type AuthResponse<T> =
| { data: T; error: null }
| { data: null; error: AuthError };

This means you never need try/catch for SDK methods. Check error first, then use data:

const { data, error } = await auth.passkey.login();
if (error) {
// Handle error
console.error(error.message);
return;
}
// TypeScript knows data is non-null here
console.log(data.user);

AuthError Structure

interface AuthError {
/** Authrim error code (e.g., 'AR003002') */
code: string;
/** OAuth 2.0 error code (e.g., 'user_cancelled') */
error: string;
/** Human-readable error message */
message: string;
/** Whether the operation can be retried */
retryable: boolean;
/** Error severity level */
severity: 'info' | 'warn' | 'error' | 'critical';
}

Error Code Format

Error codes follow the pattern AR{domain}{number}:

PrefixDomainExamples
AR001Session / AuthSession errors
AR002Email CodeSend/verify errors
AR003Passkey (WebAuthn)Ceremony errors
AR004Social LoginProvider/callback errors
AR005OAuth / OIDCToken/callback errors

Severity Levels

LevelMeaningTypical Action
infoExpected state (e.g., not authenticated)Update UI normally
warnRecoverable issue (e.g., silent auth failed)Log and continue
errorFailed operation (e.g., invalid code)Show error message
criticalUnexpected failure (e.g., server error)Show error + suggest retry

Retryable Flag

if (error.retryable) {
showMessage('Something went wrong. Please try again.');
// Offer retry button
} else {
showMessage(error.message);
// Don't offer retry — issue needs user action
}

Error Handling Patterns

Basic Pattern

const { data, error } = await auth.passkey.login();
if (error) {
showErrorMessage(error.message);
return;
}
// Success
redirect('/dashboard');

Switch on Error Code

const { data, error } = await auth.emailCode.verify(email, code);
if (error) {
switch (error.code) {
case 'AR002003':
// Code expired — resend
await auth.emailCode.send(email);
showMessage('Code expired. A new code has been sent.');
break;
case 'AR002004':
// Wrong code
showMessage('Incorrect code. Please try again.');
break;
case 'AR002005':
// Too many attempts
showMessage('Too many attempts. Please wait before trying again.');
break;
default:
showMessage(error.message);
}
return;
}

Severity-Based Handling

function handleAuthError(error: AuthError) {
switch (error.severity) {
case 'info':
// Not really an error — expected state
console.log(error.message);
break;
case 'warn':
// Recoverable — log but don't alert
console.warn(`[${error.code}] ${error.message}`);
break;
case 'error':
// Show to user
showToast(error.message, 'error');
break;
case 'critical':
// Show prominently + log for debugging
showAlert(error.message);
logToService(error);
break;
}
}

Retry Pattern

async function loginWithRetry(maxRetries = 2) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const { data, error } = await auth.passkey.login();
if (!error) {
return data;
}
if (!error.retryable || attempt === maxRetries) {
showMessage(error.message);
return null;
}
// Brief delay before retry
await new Promise(resolve => setTimeout(resolve, 1000));
}
return null;
}

Error Codes Reference

Passkey (AR003xxx)

CodeErrorRetryableDescription
AR003000passkey_errorVariesGeneral passkey error
AR003001webauthn_not_supportedNoBrowser does not support WebAuthn
AR003002user_cancelledYesUser cancelled the ceremony
AR003003credential_not_foundNoNo matching credential
AR003004authenticator_errorYesAuthenticator device error
AR003005server_validation_failedYesServer rejected the credential

Email Code (AR002xxx)

CodeErrorRetryableDescription
AR002000email_code_errorVariesGeneral email code error
AR002001invalid_emailNoInvalid email format
AR002002rate_limitedNoToo many send requests
AR002003code_expiredNoVerification code expired
AR002004invalid_codeYesWrong code entered
AR002005max_attemptsNoToo many failed verifications

Social Login (AR004xxx)

CodeErrorRetryableDescription
AR004001provider_not_configuredNoProvider not set up
AR004002popup_blockedNoBrowser blocked the popup
AR004003user_deniedYesUser denied consent
AR004004provider_errorYesProvider returned an error
AR004005callback_failedNoCallback validation failed

OAuth (AR005xxx)

CodeErrorRetryableDescription
AR005001oauth_callback_errorNoCallback handling failed
AR005002silent_auth_failedNoSilent authentication failed
AR005003no_tokensNoNo tokens received
AR005004popup_login_errorYesPopup login failed

Centralized Error Handler

Create a reusable error handler for your application:

function handleError(error: AuthError, context: string) {
// Log all errors
console.error(`[${context}] ${error.code}: ${error.message}`);
// User-facing message
if (error.severity === 'critical') {
showAlert('An unexpected error occurred. Please try again later.');
} else if (error.severity === 'error') {
showToast(error.message);
}
// Analytics
trackError({ code: error.code, context, severity: error.severity });
}
// Usage
const { data, error } = await auth.passkey.login();
if (error) {
handleError(error, 'passkey-login');
return;
}

Next Steps