Browser: Registration
Register a Passkey with the Service and attest the knowledge of a KeyPair.
Who is this for?
- Browser Wallets that want to communicate with the service and other clients
Client
Creating a passkey and registering it with the service using an instance of the SignalClient
.
attestation
is a convenience method that handles the entire process of creating a passkey and registering it with the service.
The caller must provide a callback that will be called when a challenge is received from the service.
import * as nacl from 'tweetnacl'import {toBase64URL} from '@algorandfoundation/liquid-client/encoding'
// Sign in to the service with a new credential and walletawait client.attestation( // Callback when a challenge is received, return a signed challenge async (challenge: Uint8Array) => ({ // The type of signature and public key type: 'algorand', // The address of the account address: address, // The signature of the challenge, signed by the account signature: toBase64URL(nacl.sign.detached(challenge, seceretKey)), // Optionally authenticate a remote peer requestId: "<UUID_FROM_QR_CODE>", // Optional device name device: 'Demo Web Wallet' }))
Stateless
Using the attestation
method to create a passkey without using the SignalClient
import * as nacl from 'tweetnacl'import {attestation} from '@algorandfoundation/liquid-client/attestation'import {toBase64URL} from '@algorandfoundation/liquid-client/encoding'
await attestation( "https://my-liquid-service.com", // Callback when a challenge is received, return a signed challenge async (challenge: Uint8Array) => ({ // The type of signature and public key type: 'algorand', // The address of the account address: address, // The signature of the challenge, signed by the account signature: toBase64URL(nacl.sign.detached(challenge, seceretKey)), // Optionally authenticate a remote peer requestId: 12345, // Optional device name device: 'Demo Web Wallet' }))
Manual
If you want to manually handle the process of creating a passkey, you can use the following methods and preforming the three steps of the process.
🧮 Options
Manually fetching the PublicKeyCredentialCreationOptions from the service.
import {fetchAttestationRequest} from '@algorandfoundation/liquid-client/attestation'
const encodedOptions = await fetchAttestationRequest("https://my-liquid-service.com")
✨ Creating
Decode the options and create a new passkey.
import {decodeAddress, fromBase64Url} from "@algorandfoundation/liquid-client/encoding";const options = { ...encodedOptions }; // Uint8Array of the user's id, is set as the encoded address for this type of key options.user.id = decodeAddress(address); // Must be string that is equal to the id bytes using the appropriate encoding options.user.name = address; // Friendly name to display for the user options.user.displayName = "Hello World"; // Challenge from the service options.challenge = fromBase64Url(options.challenge);
// Decode any known credentials if (options.excludeCredentials) { for (const cred of options.excludeCredentials) { cred.id = fromBase64Url(cred.id); }}const credential = navigator.credentials.create({ publicKey: options})
🔐 Liquid Extension
Sign the challenge with an additional KeyPair.
import * as nacl from 'tweetnacl'import {toBase64URL} from '@algorandfoundation/liquid-client/encoding'
credential.clientExtensionResults = { // The type of signature and public key, this is also used // to determine the type of encoding for the user.id type: 'algorand', // The address of the account address: address, // The signature of the challenge, signed by the account signature: toBase64URL(nacl.sign.detached(options.challenge, seceretKey)), // Optionally authenticate a remote peer requestId: "<UUID_FROM_QR_CODE>", // Optional device name device: 'Demo Web Wallet'}
🚚 Response
Encode and submit the passkey to the service.
import {fetchAttestationResponse} from '@algorandfoundation/liquid-client/attestation'import {toBase64URL} from '@algorandfoundation/liquid-client/encoding'
const result = await fetchAttestationResponse("https://my-liquid-service.com", { id: credential.id, rawId: toBase64URL(credential.rawId), type: credential.type, response: { clientDataJSON: toBase64URL(response.clientDataJSON), attestationObject: toBase64URL(response.attestationObject), }, clientExtensionResults: credential.clientExtensionResults })