text: class WebAuthn {
  	// Decode a base64 string into a Uint8Array.
  	static _decodeBuffer(value) {
  		return Uint8Array.from(atob(value), c => c.charCodeAt(0));
  	}
  
  	// Encode an ArrayBuffer into a base64 string.
  	static _encodeBuffer(value) {
  		return btoa(new Uint8Array(value).reduce((s, byte) => s + String.fromCharCode(byte), ''));
  	}
  
  	// Checks whether the status returned matches the status given.
  	static _checkStatus(status) {
  		return res => {
  			if (res.status === status) {
  				return res;
  			}
  			throw new Error(res.statusText);
  		};
  	}
  
  	register() {
  		return fetch('/webauthn/registration/start', {
  				method: 'POST'
  			})
  			.then(WebAuthn._checkStatus(200))
  			.then(res => res.json())
  			.then(res => {
  				res.publicKey.challenge = WebAuthn._decodeBuffer(res.publicKey.challenge);
  				res.publicKey.user.id = WebAuthn._decodeBuffer(res.publicKey.user.id);
  				if (res.publicKey.excludeCredentials) {
  					for (var i = 0; i < res.publicKey.excludeCredentials.length; i++) {
  						res.publicKey.excludeCredentials[i].id = WebAuthn._decodeBuffer(res.publicKey.excludeCredentials[i].id);
  					}
  				}
  				return res;
  			})
  			.then(res => navigator.credentials.create(res))
  			.then(credential => {
  				return fetch('/webauthn/registration/finish', {
  					method: 'POST',
  					headers: {
  						'Accept': 'application/json',
  						'Content-Type': 'application/json'
  					},
  					body: JSON.stringify({
  						id: credential.id,
  						rawId: WebAuthn._encodeBuffer(credential.rawId),
  						response: {
  							attestationObject: WebAuthn._encodeBuffer(credential.response.attestationObject),
  							clientDataJSON: WebAuthn._encodeBuffer(credential.response.clientDataJSON)
  						},
  						type: credential.type
  					}),
  				})
  			})
  			.then(WebAuthn._checkStatus(201));
  	}
  
  	login() {
  		return fetch('/webauthn/login/start', {
  				method: 'POST'
  			})
  			.then(WebAuthn._checkStatus(200))
  			.then(res => res.json())
  			.then(res => {
  				res.publicKey.challenge = WebAuthn._decodeBuffer(res.publicKey.challenge);
  				if (res.publicKey.allowCredentials) {
  					for (let i = 0; i < res.publicKey.allowCredentials.length; i++) {
  						res.publicKey.allowCredentials[i].id = WebAuthn._decodeBuffer(res.publicKey.allowCredentials[i].id);
  					}
  				}
  				return res;
  			})
  			.then(res => navigator.credentials.get(res))
  			.then(credential => {
  				return fetch('/webauthn/login/finish', {
  					method: 'POST',
  					headers: {
  						'Accept': 'application/json',
  						'Content-Type': 'application/json'
  					},
  					body: JSON.stringify({
  						id: credential.id,
  						rawId: WebAuthn._encodeBuffer(credential.rawId),
  						response: {
  							clientDataJSON: WebAuthn._encodeBuffer(credential.response.clientDataJSON),
  							authenticatorData: WebAuthn._encodeBuffer(credential.response.authenticatorData),
  							signature: WebAuthn._encodeBuffer(credential.response.signature),
  							userHandle: WebAuthn._encodeBuffer(credential.response.userHandle),
  						},
  						type: credential.type
  					}),
  				})
  			})
  			.then(WebAuthn._checkStatus(200));
  	}
  }