or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mderror-handling.mdhelpers.mdindex.md

error-handling.mddocs/

0

# Error Handling and Abort Control

1

2

Comprehensive error handling with WebAuthn-specific error codes and abort service for managing ceremony lifecycles. This module provides detailed error classification and control mechanisms for WebAuthn operations.

3

4

## Capabilities

5

6

### WebAuthn Error Classification

7

8

The `WebAuthnError` class provides detailed error information for WebAuthn ceremony failures, with specific error codes that help identify the exact cause of failures.

9

10

```typescript { .api }

11

/**

12

* A custom Error used to return a more nuanced error detailing why one of the eight

13

* documented errors in the WebAuthn spec was raised after calling

14

* navigator.credentials.create() or navigator.credentials.get()

15

*/

16

class WebAuthnError extends Error {

17

/** Specific WebAuthn error code providing detailed failure reason */

18

code: WebAuthnErrorCode;

19

20

constructor(options: {

21

/** Human-readable error message */

22

message: string;

23

/** Specific WebAuthn error code */

24

code: WebAuthnErrorCode;

25

/** Original error that caused this WebAuthnError */

26

cause: Error;

27

/** Optional custom error name, defaults to cause.name */

28

name?: string;

29

});

30

}

31

```

32

33

### Error Codes

34

35

Comprehensive set of error codes covering all WebAuthn failure scenarios:

36

37

```typescript { .api }

38

type WebAuthnErrorCode =

39

/** User cancelled the WebAuthn ceremony */

40

| 'ERROR_CEREMONY_ABORTED'

41

/** Current domain is not valid for WebAuthn */

42

| 'ERROR_INVALID_DOMAIN'

43

/** Relying Party ID is invalid */

44

| 'ERROR_INVALID_RP_ID'

45

/** User ID length exceeds maximum allowed */

46

| 'ERROR_INVALID_USER_ID_LENGTH'

47

/** Public key credential parameters are malformed */

48

| 'ERROR_MALFORMED_PUBKEYCREDPARAMS'

49

/** General authenticator error occurred */

50

| 'ERROR_AUTHENTICATOR_GENERAL_ERROR'

51

/** Authenticator doesn't support discoverable credentials */

52

| 'ERROR_AUTHENTICATOR_MISSING_DISCOVERABLE_CREDENTIAL_SUPPORT'

53

/** Authenticator doesn't support user verification */

54

| 'ERROR_AUTHENTICATOR_MISSING_USER_VERIFICATION_SUPPORT'

55

/** Credential is already registered to this authenticator */

56

| 'ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED'

57

/** Authenticator doesn't support any of the specified algorithms */

58

| 'ERROR_AUTHENTICATOR_NO_SUPPORTED_PUBKEYCREDPARAMS_ALG'

59

/** Auto-registration failed due to user verification failure */

60

| 'ERROR_AUTO_REGISTER_USER_VERIFICATION_FAILURE'

61

/** Generic error - check the cause property for details */

62

| 'ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY';

63

```

64

65

**Usage Examples:**

66

67

```typescript

68

import { startRegistration, WebAuthnError } from '@simplewebauthn/browser';

69

70

try {

71

const response = await startRegistration({ optionsJSON });

72

// Success - send to server

73

await verifyWithServer(response);

74

} catch (error) {

75

if (error instanceof WebAuthnError) {

76

switch (error.code) {

77

case 'ERROR_CEREMONY_ABORTED':

78

showMessage('Registration was cancelled. Please try again.');

79

break;

80

81

case 'ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED':

82

showMessage('This authenticator is already registered. Please use a different one.');

83

break;

84

85

case 'ERROR_AUTHENTICATOR_MISSING_USER_VERIFICATION_SUPPORT':

86

showMessage('Your authenticator doesn\'t support user verification. Please use a different one.');

87

break;

88

89

case 'ERROR_INVALID_DOMAIN':

90

showMessage('WebAuthn is not supported on this domain.');

91

break;

92

93

case 'ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY':

94

console.error('WebAuthn error details:', error.cause);

95

showMessage('An unexpected error occurred. Please try again.');

96

break;

97

98

default:

99

console.error('WebAuthn error:', error.code, error.message);

100

showMessage('Registration failed. Please try again.');

101

}

102

} else {

103

// Handle non-WebAuthn errors

104

console.error('General error:', error.message);

105

showMessage('An error occurred. Please check your browser support.');

106

}

107

}

108

```

109

110

### Abort Service

111

112

The `WebAuthnAbortService` ensures only one WebAuthn ceremony is active at a time and provides manual cancellation capabilities.

113

114

```typescript { .api }

115

/**

116

* A service singleton to help ensure that only a single WebAuthn ceremony

117

* is active at a time. Automatically manages AbortSignal creation and cleanup.

118

*/

119

interface WebAuthnAbortService {

120

/**

121

* Prepare an abort signal that will help support multiple auth attempts

122

* without needing to reload the page. Automatically called by startRegistration()

123

* and startAuthentication().

124

* @returns AbortSignal for the current WebAuthn operation

125

*/

126

createNewAbortSignal(): AbortSignal;

127

128

/**

129

* Manually cancel any active WebAuthn registration or authentication attempt.

130

* Useful for handling navigation events or user-initiated cancellations.

131

*/

132

cancelCeremony(): void;

133

}

134

135

/** Singleton instance of the abort service */

136

declare const WebAuthnAbortService: WebAuthnAbortService;

137

```

138

139

**Usage Examples:**

140

141

```typescript

142

import { WebAuthnAbortService, startAuthentication } from '@simplewebauthn/browser';

143

144

// Manual cancellation (useful for navigation handling)

145

function handleRouteChange() {

146

// Cancel any ongoing WebAuthn ceremony

147

WebAuthnAbortService.cancelCeremony();

148

149

// Navigate to new route

150

navigateToRoute('/dashboard');

151

}

152

153

// Custom timeout handling

154

async function authenticateWithTimeout(optionsJSON: any, timeoutMs: number) {

155

const timeoutId = setTimeout(() => {

156

WebAuthnAbortService.cancelCeremony();

157

}, timeoutMs);

158

159

try {

160

const response = await startAuthentication({ optionsJSON });

161

clearTimeout(timeoutId);

162

return response;

163

} catch (error) {

164

clearTimeout(timeoutId);

165

166

if (error instanceof WebAuthnError && error.code === 'ERROR_CEREMONY_ABORTED') {

167

throw new Error('Authentication timed out');

168

}

169

170

throw error;

171

}

172

}

173

174

// The service is automatically used by startRegistration/startAuthentication

175

// No manual signal creation needed for normal usage

176

const response = await startAuthentication({ optionsJSON });

177

```

178

179

## Error Handling Patterns

180

181

### Comprehensive Error Handling

182

183

Handle both WebAuthn-specific and general errors appropriately:

184

185

```typescript

186

import { startRegistration, WebAuthnError, browserSupportsWebAuthn } from '@simplewebauthn/browser';

187

188

async function registerWithErrorHandling(optionsJSON: any) {

189

// Pre-flight checks

190

if (!browserSupportsWebAuthn()) {

191

throw new Error('WebAuthn is not supported in this browser');

192

}

193

194

try {

195

const response = await startRegistration({ optionsJSON });

196

return { success: true, response };

197

} catch (error) {

198

if (error instanceof WebAuthnError) {

199

return {

200

success: false,

201

errorCode: error.code,

202

userMessage: getUserFriendlyMessage(error.code),

203

technicalDetails: error.message

204

};

205

} else {

206

return {

207

success: false,

208

errorCode: 'GENERAL_ERROR',

209

userMessage: 'Registration failed. Please try again.',

210

technicalDetails: error.message

211

};

212

}

213

}

214

}

215

216

function getUserFriendlyMessage(errorCode: WebAuthnErrorCode): string {

217

const messages = {

218

'ERROR_CEREMONY_ABORTED': 'Registration was cancelled.',

219

'ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED': 'This authenticator is already registered.',

220

'ERROR_AUTHENTICATOR_MISSING_USER_VERIFICATION_SUPPORT': 'Your authenticator doesn\'t support the required verification.',

221

'ERROR_INVALID_DOMAIN': 'This website cannot use passwordless authentication.',

222

'ERROR_INVALID_RP_ID': 'Website configuration error. Please contact support.',

223

'ERROR_INVALID_USER_ID_LENGTH': 'User ID is too long. Please contact support.',

224

'ERROR_MALFORMED_PUBKEYCREDPARAMS': 'Invalid registration parameters. Please contact support.',

225

'ERROR_AUTHENTICATOR_GENERAL_ERROR': 'Your authenticator encountered an error.',

226

'ERROR_AUTHENTICATOR_MISSING_DISCOVERABLE_CREDENTIAL_SUPPORT': 'Your authenticator doesn\'t support this type of credential.',

227

'ERROR_AUTHENTICATOR_NO_SUPPORTED_PUBKEYCREDPARAMS_ALG': 'Your authenticator doesn\'t support the required algorithms.',

228

'ERROR_AUTO_REGISTER_USER_VERIFICATION_FAILURE': 'Automatic registration failed. Please try manual registration.',

229

'ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY': 'An unexpected error occurred.'

230

};

231

232

return messages[errorCode] || 'An unknown error occurred.';

233

}

234

```

235

236

### Retry Logic with Abort Handling

237

238

Implement smart retry logic that respects user cancellations:

239

240

```typescript

241

import { startAuthentication, WebAuthnError, WebAuthnAbortService } from '@simplewebauthn/browser';

242

243

async function authenticateWithRetry(optionsJSON: any, maxRetries: number = 3) {

244

for (let attempt = 1; attempt <= maxRetries; attempt++) {

245

try {

246

const response = await startAuthentication({ optionsJSON });

247

return response;

248

} catch (error) {

249

if (error instanceof WebAuthnError) {

250

// Don't retry if user explicitly cancelled

251

if (error.code === 'ERROR_CEREMONY_ABORTED') {

252

throw new Error('Authentication was cancelled by user');

253

}

254

255

// Don't retry configuration errors

256

if (['ERROR_INVALID_DOMAIN', 'ERROR_INVALID_RP_ID'].includes(error.code)) {

257

throw error;

258

}

259

260

// Retry other WebAuthn errors

261

if (attempt < maxRetries) {

262

console.log(`Authentication attempt ${attempt} failed, retrying...`);

263

await new Promise(resolve => setTimeout(resolve, 1000)); // Brief delay

264

continue;

265

}

266

}

267

268

// Final attempt or non-WebAuthn error

269

throw error;

270

}

271

}

272

}

273

```

274

275

### Navigation and Cleanup

276

277

Handle navigation events to prevent memory leaks:

278

279

```typescript

280

import { WebAuthnAbortService } from '@simplewebauthn/browser';

281

282

// React Router example

283

import { useEffect } from 'react';

284

import { useNavigate } from 'react-router-dom';

285

286

function WebAuthnPage() {

287

const navigate = useNavigate();

288

289

useEffect(() => {

290

// Cleanup on component unmount

291

return () => {

292

WebAuthnAbortService.cancelCeremony();

293

};

294

}, []);

295

296

const handleBackButton = () => {

297

WebAuthnAbortService.cancelCeremony();

298

navigate('/login');

299

};

300

301

// ... component logic

302

}

303

304

// Vanilla JS example

305

window.addEventListener('beforeunload', () => {

306

WebAuthnAbortService.cancelCeremony();

307

});

308

309

// Single Page App routing

310

document.addEventListener('route-change', () => {

311

WebAuthnAbortService.cancelCeremony();

312

});

313

```

314

315

## Browser Error Mapping

316

317

WebAuthn errors are derived from the eight documented DOM exceptions:

318

319

- **AbortError**`ERROR_CEREMONY_ABORTED`

320

- **ConstraintError** → Various constraint-related codes

321

- **InvalidStateError**`ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED`

322

- **NotAllowedError** → Various permission/policy codes

323

- **NotSupportedError** → Various capability-related codes

324

- **SecurityError**`ERROR_INVALID_DOMAIN`, `ERROR_INVALID_RP_ID`

325

- **TypeError**`ERROR_MALFORMED_PUBKEYCREDPARAMS`, `ERROR_INVALID_USER_ID_LENGTH`

326

- **UnknownError**`ERROR_PASSTHROUGH_SEE_CAUSE_PROPERTY`

327

328

The library analyzes the original browser error and maps it to the most specific `WebAuthnErrorCode` possible, providing better debugging and user experience.