@@ -110,10 +110,7 @@ The client side involves:
110
110
passing the result from `RelyingParty.startRegistration(...)` or `.startAssertion(...)` as the argument.
111
111
2. Encode the result of the successfully resolved promise and return it to the server.
112
112
For this you need some way to encode `Uint8Array` values;
113
- this guide will assume use of link:https://github.com/beatgammit/base64-js[base64-js].
114
- However the built-in parser methods for
115
- link:https://developers.yubico.com/java-webauthn-server/JavaDoc/webauthn-server-core-minimal/latest/com/yubico/webauthn/data/PublicKeyCredential.html[`PublicKeyCredential`]
116
- expect URL-safe Base64 encoding, so the below examples will include this as an additional step.
113
+ this guide will use GitHub's link:https://github.com/github/webauthn-json[webauthn-json] library.
117
114
118
115
Example code is given below.
119
116
For more detailed example usage, see
@@ -163,6 +160,8 @@ A registration ceremony consists of 5 main steps:
163
160
4. Validate the response using `RelyingParty.finishRegistration(...)`.
164
161
5. Update your database using the `finishRegistration` output.
165
162
163
+ This example uses GitHub's link:https://github.com/github/webauthn-json[webauthn-json] library to do both (2) and (3) in one function call.
164
+
166
165
First, generate registration parameters and send them to the client:
167
166
168
167
[source,java]
@@ -196,62 +195,23 @@ Now call the WebAuthn API on the client side:
196
195
197
196
[source,javascript]
198
197
----------
199
- function base64urlToUint8array(base64Bytes) {
200
- const padding = '===='.substring(0, (4 - (base64Bytes.length % 4)) % 4);
201
- return base64js.toByteArray((base64Bytes + padding).replace(/\//g, "_").replace(/\+/g, "-"));
202
- }
203
- function uint8arrayToBase64url(bytes) {
204
- if (bytes instanceof Uint8Array) {
205
- return base64js.fromByteArray(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
206
- } else {
207
- return uint8arrayToBase64url(new Uint8Array(bytes));
208
- }
209
- }
210
-
211
- fetch(/* ... */) // Make the call that returns the credentialCreateJson above
212
- .then(credentialCreateJson => ({ // Decode byte arrays from base64url
213
- publicKey: {
214
- ...credentialCreateJson.publicKey,
215
-
216
- challenge: base64urlToUint8array(credentialCreateJson.publicKey.challenge),
217
- user: {
218
- ...credentialCreateJson.publicKey.user,
219
- id: base64urlToUint8array(credentialCreateJson.publicKey.user.id),
220
- },
221
- excludeCredentials: credentialCreateJson.publicKey.excludeCredentials.map(credential => ({
222
- ...credential,
223
- id: base64urlToUint8array(credential.id),
224
- })),
225
-
226
- // Warning: Extension inputs could also contain binary data that needs encoding
227
- extensions: credentialCreateJson.publicKey.extensions,
228
- },
229
- }))
230
- .then(credentialCreateOptions => // Call WebAuthn ceremony
231
- navigator.credentials.create(credentialCreateOptions))
232
- .then(publicKeyCredential => ({ // Encode PublicKeyCredential for transport to server (example)
233
- type: publicKeyCredential.type,
234
- id: publicKeyCredential.id,
235
- response: {
236
- attestationObject: uint8arrayToBase64url(publicKeyCredential.response.attestationObject),
237
- clientDataJSON: uint8arrayToBase64url(publicKeyCredential.response.clientDataJSON),
238
-
239
- // Attempt to read transports, but recover gracefully if not supported by the browser
240
- transports: publicKeyCredential.response.getTransports && publicKeyCredential.response.getTransports() || [],
241
- },
242
-
243
- // Warning: Client extension results could also contain binary data that needs encoding
244
- clientExtensionResults: publicKeyCredential.getClientExtensionResults(),
245
- }))
246
- .then(encodedResult =>
247
- fetch(/* ... */)); // Return encoded PublicKeyCredential to server
198
+ import * as webauthnJson from "@github/webauthn-json";
199
+
200
+ // Make the call that returns the credentialCreateJson above
201
+ const credentialCreateOptions = await fetch(/* ... */).then(resp => resp.json());
202
+
203
+ // Call WebAuthn ceremony using webauthn-json wrapper
204
+ const publicKeyCredential = await webauthnJson.create(credentialCreateOptions);
205
+
206
+ // Return encoded PublicKeyCredential to server
207
+ fetch(/* ... */, { body: JSON.stringify(publicKeyCredential) });
248
208
----------
249
209
250
210
Validate the response on the server side:
251
211
252
212
[source,java]
253
213
----------
254
- String publicKeyCredentialJson = /* ... */; // encodedResult from client
214
+ String publicKeyCredentialJson = /* ... */; // publicKeyCredential from client
255
215
PublicKeyCredential<AuthenticatorAttestationResponse, ClientRegistrationExtensionOutputs> pkc =
256
216
PublicKeyCredential.parseRegistrationResponseJson(publicKeyCredentialJson);
257
217
@@ -295,6 +255,8 @@ Like registration ceremonies, an authentication ceremony consists of 5 main step
295
255
4. Validate the response using `RelyingParty.finishAssertion(...)`.
296
256
5. Update your database using the `finishAssertion` output, and act upon the result (for example, grant login access).
297
257
258
+ This example uses GitHub's link:https://github.com/github/webauthn-json[webauthn-json] library to do both (2) and (3) in one function call.
259
+
298
260
First, generate authentication parameters and send them to the client:
299
261
300
262
[source,java]
@@ -313,58 +275,23 @@ Now call the WebAuthn API on the client side:
313
275
314
276
[source,javascript]
315
277
----------
316
- function base64urlToUint8array(base64Bytes) {
317
- const padding = '===='.substring(0, (4 - (base64Bytes.length % 4)) % 4);
318
- return base64js.toByteArray((base64Bytes + padding).replace(/\//g, "_").replace(/\+/g, "-"));
319
- }
320
- function uint8arrayToBase64url(bytes) {
321
- if (bytes instanceof Uint8Array) {
322
- return base64js.fromByteArray(bytes).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
323
- } else {
324
- return uint8arrayToBase64url(new Uint8Array(bytes));
325
- }
326
- }
327
-
328
- fetch(/* ... */) // Make the call that returns the credentialGetJson above
329
- .then(credentialGetJson => ({ // Decode byte arrays from base64url
330
- publicKey: {
331
- ...credentialGetJson.publicKey,
332
- allowCredentials: credentialGetJson.publicKey.allowCredentials
333
- && credentialGetJson.publicKey.allowCredentials.map(credential => ({
334
- ...credential,
335
- id: base64urlToUint8array(credential.id),
336
- })),
337
-
338
- challenge: base64urlToUint8array(credentialGetJson.publicKey.challenge),
339
-
340
- // Warning: Extension inputs could also contain binary data that needs encoding
341
- extensions: credentialGetJson.publicKey.extensions,
342
- },
343
- }))
344
- .then(credentialGetOptions => // Call WebAuthn ceremony
345
- navigator.credentials.get(credentialGetOptions))
346
- .then(publicKeyCredential => ({ // Encode PublicKeyCredential for transport to server (example)
347
- type: publicKeyCredential.type,
348
- id: publicKeyCredential.id,
349
- response: {
350
- authenticatorData: uint8arrayToBase64url(publicKeyCredential.response.authenticatorData),
351
- clientDataJSON: uint8arrayToBase64url(publicKeyCredential.response.clientDataJSON),
352
- signature: uint8arrayToBase64url(publicKeyCredential.response.signature),
353
- userHandle: publicKeyCredential.response.userHandle && uint8arrayToBase64url(publicKeyCredential.response.userHandle),
354
- },
355
-
356
- // Warning: Client extension results could also contain binary data that needs encoding
357
- clientExtensionResults: publicKeyCredential.getClientExtensionResults(),
358
- }))
359
- .then(encodedResult =>
360
- fetch(/* ... */)); // Return encoded PublicKeyCredential to server
278
+ import * as webauthnJson from "@github/webauthn-json";
279
+
280
+ // Make the call that returns the credentialGetJson above
281
+ const credentialGetOptions = await fetch(/* ... */).then(resp => resp.json());
282
+
283
+ // Call WebAuthn ceremony using webauthn-json wrapper
284
+ const publicKeyCredential = await webauthnJson.get(credentialGetOptions);
285
+
286
+ // Return encoded PublicKeyCredential to server
287
+ fetch(/* ... */, { body: JSON.stringify(publicKeyCredential) });
361
288
----------
362
289
363
290
Validate the response on the server side:
364
291
365
292
[source,java]
366
293
----------
367
- String publicKeyCredentialJson = /* ... */; // encodedResult from client
294
+ String publicKeyCredentialJson = /* ... */; // publicKeyCredential from client
368
295
PublicKeyCredential<AuthenticatorAssertionResponse, ClientAssertionExtensionOutputs> pkc =
369
296
PublicKeyCredential.parseAssertionResponseJson(publicKeyCredentialJson);
370
297
0 commit comments