or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdbrowser-support.mddata-encoding.mderror-handling.mdindex.mdregistration.mdserver.md

server.mddocs/

0

# SimpleWebAuthn Server

1

2

Server-side WebAuthn functionality for Node.js, Deno, and other JavaScript runtimes. Provides functions to generate WebAuthn options, verify responses, and manage authenticator metadata.

3

4

## Additional Imports

5

6

The server package also exports helper functions for advanced use cases:

7

8

```typescript

9

import {

10

generateChallenge,

11

generateUserID,

12

convertAAGUIDToString,

13

decodeAttestationObject,

14

decodeClientDataJSON,

15

parseAuthenticatorData,

16

toHash,

17

convertCOSEtoPKCS,

18

verifySignature,

19

isoBase64URL,

20

isoUint8Array,

21

} from "@simplewebauthn/server/helpers";

22

```

23

24

## Capabilities

25

26

### Registration Options Generation

27

28

Generates options for WebAuthn registration ceremonies.

29

30

```typescript { .api }

31

/**

32

* Prepare a value to pass into navigator.credentials.create(...) for authenticator registration

33

*/

34

function generateRegistrationOptions(options: {

35

rpName: string;

36

rpID: string;

37

userName: string;

38

userID?: Uint8Array;

39

challenge?: string | Uint8Array;

40

userDisplayName?: string;

41

timeout?: number;

42

attestationType?: 'direct' | 'enterprise' | 'none';

43

excludeCredentials?: {

44

id: Base64URLString;

45

transports?: AuthenticatorTransportFuture[];

46

}[];

47

authenticatorSelection?: AuthenticatorSelectionCriteria;

48

extensions?: AuthenticationExtensionsClientInputs;

49

supportedAlgorithmIDs?: COSEAlgorithmIdentifier[];

50

preferredAuthenticatorType?: 'securityKey' | 'localDevice' | 'remoteDevice';

51

}): Promise<PublicKeyCredentialCreationOptionsJSON>;

52

53

type GenerateRegistrationOptionsOpts = Parameters<typeof generateRegistrationOptions>[0];

54

```

55

56

**Usage Examples:**

57

58

```typescript

59

import { generateRegistrationOptions } from "@simplewebauthn/server";

60

61

// Basic registration options

62

const registrationOptions = await generateRegistrationOptions({

63

rpName: "My App",

64

rpID: "example.com",

65

userName: "user@example.com",

66

userDisplayName: "John Doe",

67

});

68

69

// Advanced registration with exclusions and authenticator selection

70

const advancedOptions = await generateRegistrationOptions({

71

rpName: "My App",

72

rpID: "example.com",

73

userName: "user@example.com",

74

userDisplayName: "John Doe",

75

attestationType: "direct",

76

excludeCredentials: existingCredentials.map(cred => ({

77

id: cred.id,

78

transports: cred.transports,

79

})),

80

authenticatorSelection: {

81

authenticatorAttachment: "platform",

82

requireResidentKey: true,

83

userVerification: "required",

84

},

85

timeout: 120000,

86

});

87

```

88

89

### Registration Response Verification

90

91

Verifies WebAuthn registration responses from the client.

92

93

```typescript { .api }

94

/**

95

* Verify that the user has legitimately completed the registration process

96

*/

97

function verifyRegistrationResponse(options: {

98

response: RegistrationResponseJSON;

99

expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>);

100

expectedOrigin: string | string[];

101

expectedRPID?: string | string[];

102

expectedType?: string | string[];

103

requireUserPresence?: boolean;

104

requireUserVerification?: boolean;

105

supportedAlgorithmIDs?: COSEAlgorithmIdentifier[];

106

}): Promise<VerifiedRegistrationResponse>;

107

108

interface VerifiedRegistrationResponse {

109

verified: boolean;

110

registrationInfo?: {

111

fmt: AttestationFormat;

112

counter: number;

113

aaguid: string;

114

credentialID: Uint8Array;

115

credentialPublicKey: Uint8Array;

116

userVerified: boolean;

117

credentialDeviceType: CredentialDeviceType;

118

credentialBackedUp: boolean;

119

};

120

}

121

```

122

123

**Usage Examples:**

124

125

```typescript

126

import { verifyRegistrationResponse } from "@simplewebauthn/server";

127

128

const verification = await verifyRegistrationResponse({

129

response: registrationResponseFromClient,

130

expectedChallenge: expectedChallenge,

131

expectedOrigin: "https://example.com",

132

expectedRPID: "example.com",

133

requireUserVerification: true,

134

});

135

136

if (verification.verified && verification.registrationInfo) {

137

// Store credential in database

138

await saveCredential({

139

id: verification.registrationInfo.credentialID,

140

publicKey: verification.registrationInfo.credentialPublicKey,

141

counter: verification.registrationInfo.counter,

142

deviceType: verification.registrationInfo.credentialDeviceType,

143

backedUp: verification.registrationInfo.credentialBackedUp,

144

});

145

}

146

```

147

148

### Authentication Options Generation

149

150

Generates options for WebAuthn authentication ceremonies.

151

152

```typescript { .api }

153

/**

154

* Prepare a value to pass into navigator.credentials.get(...) for authenticator authentication

155

*/

156

function generateAuthenticationOptions(options: {

157

rpID: string;

158

allowCredentials?: {

159

id: Base64URLString;

160

transports?: AuthenticatorTransportFuture[];

161

}[];

162

challenge?: string | Uint8Array;

163

timeout?: number;

164

userVerification?: 'required' | 'preferred' | 'discouraged';

165

extensions?: AuthenticationExtensionsClientInputs;

166

}): Promise<PublicKeyCredentialRequestOptionsJSON>;

167

168

type GenerateAuthenticationOptionsOpts = Parameters<typeof generateAuthenticationOptions>[0];

169

```

170

171

**Usage Examples:**

172

173

```typescript

174

import { generateAuthenticationOptions } from "@simplewebauthn/server";

175

176

// Basic authentication options (passwordless)

177

const authOptions = await generateAuthenticationOptions({

178

rpID: "example.com",

179

userVerification: "preferred",

180

});

181

182

// Authentication with specific credentials (second factor)

183

const specificAuthOptions = await generateAuthenticationOptions({

184

rpID: "example.com",

185

allowCredentials: userCredentials.map(cred => ({

186

id: cred.id,

187

transports: cred.transports,

188

})),

189

userVerification: "required",

190

timeout: 60000,

191

});

192

```

193

194

### Authentication Response Verification

195

196

Verifies WebAuthn authentication responses from the client.

197

198

```typescript { .api }

199

/**

200

* Verify that the user has legitimately completed the authentication process

201

*/

202

function verifyAuthenticationResponse(options: {

203

response: AuthenticationResponseJSON;

204

expectedChallenge: string | ((challenge: string) => boolean | Promise<boolean>);

205

expectedOrigin: string | string[];

206

expectedRPID?: string | string[];

207

credential: {

208

id: Base64URLString;

209

publicKey: Uint8Array;

210

counter: number;

211

transports?: AuthenticatorTransportFuture[];

212

};

213

requireUserPresence?: boolean;

214

requireUserVerification?: boolean;

215

advancedFIDOConfig?: {

216

userVerification?: 'required' | 'preferred' | 'discouraged';

217

};

218

}): Promise<VerifiedAuthenticationResponse>;

219

220

interface VerifiedAuthenticationResponse {

221

verified: boolean;

222

authenticationInfo?: {

223

newCounter: number;

224

userVerified: boolean;

225

credentialDeviceType: CredentialDeviceType;

226

credentialBackedUp: boolean;

227

};

228

}

229

```

230

231

**Usage Examples:**

232

233

```typescript

234

import { verifyAuthenticationResponse } from "@simplewebauthn/server";

235

236

const credential = await getCredentialFromDB(credentialID);

237

238

const verification = await verifyAuthenticationResponse({

239

response: authenticationResponseFromClient,

240

expectedChallenge: expectedChallenge,

241

expectedOrigin: "https://example.com",

242

expectedRPID: "example.com",

243

credential: {

244

id: credential.id,

245

publicKey: credential.publicKey,

246

counter: credential.counter,

247

transports: credential.transports,

248

},

249

requireUserVerification: true,

250

});

251

252

if (verification.verified && verification.authenticationInfo) {

253

// Update counter in database

254

await updateCredentialCounter(

255

credentialID,

256

verification.authenticationInfo.newCounter

257

);

258

259

// User is authenticated

260

return loginUser(userID);

261

}

262

```

263

264

### Metadata Service

265

266

Service for managing FIDO Metadata Service (MDS) data to validate authenticators.

267

268

```typescript { .api }

269

/**

270

* Global service for interacting with the FIDO Metadata Service

271

*/

272

interface MetadataService {

273

/**

274

* Prepare the service to handle remote MDS servers and/or cache local metadata statements

275

*/

276

initialize(options?: {

277

verificationMode?: VerificationMode;

278

mdsServers?: string[];

279

statements?: MetadataStatement[];

280

}): Promise<void>;

281

282

/**

283

* Get a metadata statement for a given AAGUID

284

*/

285

getStatement(aaguid: string): Promise<MetadataStatement | undefined>;

286

287

/**

288

* Get all cached metadata statements

289

*/

290

getStatements(): Promise<MetadataStatement[]>;

291

}

292

293

type VerificationMode = 'permissive' | 'strict';

294

295

// Exported singleton instance

296

const MetadataService: MetadataService;

297

```

298

299

**Usage Examples:**

300

301

```typescript

302

import { MetadataService } from "@simplewebauthn/server";

303

304

// Initialize with default FIDO MDS

305

await MetadataService.initialize();

306

307

// Initialize with custom verification mode

308

await MetadataService.initialize({

309

verificationMode: 'strict', // Only allow registered AAGUIDs

310

mdsServers: ['https://mds.fidoalliance.org/'],

311

});

312

313

// Get metadata for a specific authenticator

314

const statement = await MetadataService.getStatement(aaguid);

315

if (statement) {

316

console.log("Authenticator:", statement.description);

317

console.log("Attestation types:", statement.attestationTypes);

318

}

319

```

320

321

### Settings Service

322

323

Service for managing root certificates and attestation format settings.

324

325

```typescript { .api }

326

/**

327

* Global service for managing attestation format settings

328

*/

329

interface SettingsService {

330

/**

331

* Set potential root certificates for attestation formats that use them

332

*/

333

setRootCertificates(opts: {

334

identifier: RootCertIdentifier;

335

certificates: (Uint8Array | string)[];

336

}): void;

337

338

/**

339

* Get any registered root certificates for the specified attestation format

340

*/

341

getRootCertificates(opts: {

342

identifier: RootCertIdentifier;

343

}): string[];

344

}

345

346

type RootCertIdentifier = AttestationFormat | 'mds';

347

348

// Exported singleton instance

349

const SettingsService: SettingsService;

350

```

351

352

**Usage Examples:**

353

354

```typescript

355

import { SettingsService } from "@simplewebauthn/server";

356

357

// Add custom root certificates for Android attestation

358

SettingsService.setRootCertificates({

359

identifier: 'android-key',

360

certificates: [customRootCertPEM],

361

});

362

363

// Get root certificates for a format

364

const certs = SettingsService.getRootCertificates({

365

identifier: 'apple',

366

});

367

```

368

369

## Supported Algorithm Identifiers

370

371

```typescript { .api }

372

/**

373

* Supported crypto algo identifiers

374

* See https://w3c.github.io/webauthn/#sctn-alg-identifier

375

* and https://www.iana.org/assignments/cose/cose.xhtml#algorithms

376

*/

377

const supportedCOSEAlgorithmIdentifiers: COSEAlgorithmIdentifier[] = [

378

-8, // EdDSA

379

-7, // ECDSA w/ SHA-256

380

-36, // ECDSA w/ SHA-512

381

-37, // RSASSA-PSS w/ SHA-256

382

-38, // RSASSA-PSS w/ SHA-384

383

-39, // RSASSA-PSS w/ SHA-512

384

-257, // RSASSA-PKCS1-v1_5 w/ SHA-256

385

-258, // RSASSA-PKCS1-v1_5 w/ SHA-384

386

-259, // RSASSA-PKCS1-v1_5 w/ SHA-512

387

-65535 // RSASSA-PKCS1-v1_5 w/ SHA-1 (Deprecated)

388

];

389

```

390

391

## Complete Server Workflow

392

393

```typescript

394

import {

395

generateRegistrationOptions,

396

verifyRegistrationResponse,

397

generateAuthenticationOptions,

398

verifyAuthenticationResponse,

399

MetadataService,

400

} from "@simplewebauthn/server";

401

402

// Initialize metadata service

403

await MetadataService.initialize();

404

405

// Registration flow

406

app.post('/webauthn/register/begin', async (req, res) => {

407

const options = await generateRegistrationOptions({

408

rpName: "My App",

409

rpID: "example.com",

410

userName: req.user.email,

411

userDisplayName: req.user.name,

412

excludeCredentials: req.user.credentials?.map(cred => ({

413

id: cred.id,

414

transports: cred.transports,

415

})),

416

});

417

418

req.session.challenge = options.challenge;

419

res.json(options);

420

});

421

422

app.post('/webauthn/register/finish', async (req, res) => {

423

const verification = await verifyRegistrationResponse({

424

response: req.body,

425

expectedChallenge: req.session.challenge,

426

expectedOrigin: "https://example.com",

427

expectedRPID: "example.com",

428

});

429

430

if (verification.verified && verification.registrationInfo) {

431

// Save credential to database

432

await saveCredential(req.user.id, verification.registrationInfo);

433

res.json({ verified: true });

434

} else {

435

res.status(400).json({ error: "Registration failed" });

436

}

437

});

438

439

// Authentication flow

440

app.post('/webauthn/authenticate/begin', async (req, res) => {

441

const options = await generateAuthenticationOptions({

442

rpID: "example.com",

443

allowCredentials: req.user.credentials?.map(cred => ({

444

id: cred.id,

445

transports: cred.transports,

446

})),

447

});

448

449

req.session.challenge = options.challenge;

450

res.json(options);

451

});

452

453

app.post('/webauthn/authenticate/finish', async (req, res) => {

454

const credential = await getCredential(req.body.id);

455

456

const verification = await verifyAuthenticationResponse({

457

response: req.body,

458

expectedChallenge: req.session.challenge,

459

expectedOrigin: "https://example.com",

460

expectedRPID: "example.com",

461

credential: credential,

462

});

463

464

if (verification.verified) {

465

// Update counter and log in user

466

await updateCredentialCounter(credential.id, verification.authenticationInfo.newCounter);

467

req.session.loggedIn = true;

468

res.json({ verified: true });

469

} else {

470

res.status(400).json({ error: "Authentication failed" });

471

}

472

});

473

```