A passkey can be an identity’s recovery credential. The user then gets their identity back on a new device with a
fingerprint or a PIN, with no recovery code to keep. @dxos/halo writes and checks the credential; the WebAuthn ceremony
that creates and uses the passkey runs in the app, because only the app knows its site and its UI.
This guide uses the browser’s WebAuthn API. Recovery goes through EDGE, so the client needs a network connection.
navigator.credentials.create makes the passkey. Put a random lookup key in its user handle: the browser returns the
handle when the passkey signs, and HALO finds the credential by it. Then pass the passkey’s public key, the lookup key and
the algorithm to Identity.createRecoveryCredential as externalKey. The identity’s group gains the passkey as a member.
1
import*as
import Effect
Effectfrom'effect/Effect';
2
import*as
import Option
Optionfrom'effect/Option';
3
import {
import Identity
Identity } from'@dxos/halo';
4
import {
classPublicKey
The purpose of this class is to assure consistent use of keys throughout the project.
Keys should be maintained as buffers in objects and proto definitions, and converted to hex
strings as late as possible (eg, to log/display).
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
await Effect.runPromise(program) // => "Final amount to charge: 96"
@stability ― stable
@category ― constructors
@since ― 2.0.0
gen(function* () {
7
const
const identity: {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}
identity =
import Option
Option.
constgetOrThrow: <{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>(self: Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>) => {
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}
Extracts the value from a Some, or throws a default Error for None.
When to use
Use when you need quick fail-fast unwrapping of an Option and a generic
error is acceptable.
Details
Some → returns the inner value
None → throws new Error("getOrThrow called on a None")
Example (Throwing a default error)
import { Option, Result } from"effect"
Option.getOrThrow(Option.some(1)) // => 1
const failure = Result.try({
try: () => Option.getOrThrow(Option.none()),
catch: (error) => (error asError).message
})
Result.getFailure(failure).pipe(Option.getOrElse(() =>"no error")) // => "getOrThrow called on a None"
@see ― getOrThrowWith for a custom error
@see ― getOrElse for a non-throwing alternative
@stability ― stable
@category ― converting
@since ― 2.0.0
getOrThrow(yield*
import Identity
Identity.
const getSnapshot: Effect.Effect<Option.Option<{
readonly did: IdentityDid;
readonly identityKey?: string | undefined;
readonly displayName?: string | undefined;
readonly data?: {
readonly [x: string]: any;
} | undefined;
}>, never, Identity.Service>
Synchronous snapshot of the local identity (requires
Service
).
getSnapshot);
8
9
// The lookup key names the passkey. It goes in the user handle, so the
10
// assertion returns it.
11
const
const lookupKey: PublicKey
lookupKey =
classPublicKey
The purpose of this class is to assure consistent use of keys throughout the project.
Keys should be maintained as buffers in objects and proto definitions, and converted to hex
strings as late as possible (eg, to log/display).
@see ― tryPromise for a version that can handle failures.
@stability ― stable
@category ― constructors
@since ― 2.0.0
promise(() =>
14
var navigator: Navigator
The Window.navigator read-only property returns a reference to the Navigator object, which has methods and properties about the application running the script.
The credentials read-only property of the Navigator interface returns the CredentialsContainer object associated with the current document, which exposes methods to request credentials. The CredentialsContainer interface also notifies the user agent when an interesting event occurs, such as a successful sign-in or sign-out. This interface can be used for feature detection.
Available only in secure contexts.
The create() method of the CredentialsContainer interface creates a new credential, which can then be stored and later retrieved using the navigator.credentials.get() method. The retrieved credential can then be used by a website to authenticate a user.
The PublicKeyCredential interface provides information about a public key / private key pair, which is a credential for logging in to a service using an un-phishable and data-breach resistant asymmetric key pair instead of a password. It inherits from Credential, and is part of the Web Authentication API extension to the Credential Management API.
Available only in secure contexts.
The response read-only property of the PublicKeyCredential interface is an AuthenticatorResponse object which is sent from the authenticator to the user agent for the creation/fetching of credentials. The information contained in this response will be used by the relying party's server to verify the demand is legitimate.
The AuthenticatorAttestationResponse interface of the Web Authentication API is the result of a WebAuthn credential registration. It contains information about the credential that the server needs to perform WebAuthn assertions, such as its credential ID and public key.
Available only in secure contexts.
Creates an effect that terminates a fiber with a specified error.
When to use
Use when you need an Effect to report an unrecoverable defect instead of a
typed error.
Details
The die function is used to signal a defect, which represents a critical
and unexpected error in the code. When invoked, it produces an effect that
does not handle the error and instead terminates the fiber.
The error channel of the resulting effect is of type never, indicating that
it cannot recover from this failure.
The response read-only property of the PublicKeyCredential interface is an AuthenticatorResponse object which is sent from the authenticator to the user agent for the creation/fetching of credentials. The information contained in this response will be used by the relying party's server to verify the demand is legitimate.
The getPublicKey() method of the AuthenticatorAttestationResponse interface returns an ArrayBuffer containing the DER SubjectPublicKeyInfo of the new credential (see Subject Public Key Info), or null if this is not available.
Creates an effect that terminates a fiber with a specified error.
When to use
Use when you need an Effect to report an unrecoverable defect instead of a
typed error.
Details
The die function is used to signal a defect, which represents a critical
and unexpected error in the code. When invoked, it produces an effect that
does not handle the error and instead terminates the fiber.
The error channel of the resulting effect is of type never, indicating that
it cannot recover from this failure.
Hex-encoded public key that will sign the recovery challenge.
recoveryKey:
classPublicKey
The purpose of this class is to assure consistent use of keys throughout the project.
Keys should be maintained as buffers in objects and proto definitions, and converted to hex
strings as late as possible (eg, to log/display).
PublicKey.
PublicKey.from(source: PublicKeyLike): PublicKey
Creates new instance of PublicKey automatically determining the input format.
@param ― source A Buffer, or Uint8Array, or hex encoded string, or something with an asUint8Array method on it
@returns ― PublicKey
from(new
var Uint8Array: Uint8ArrayConstructor
new <ArrayBuffer>(buffer: ArrayBuffer, byteOffset?: number, length?: number) =>Uint8Array<ArrayBuffer> (+6 overloads)
Uint8Array(
const publicKey: ArrayBuffer
publicKey)).
PublicKey.toHex(): string
toHex(),
47
lookupKey: string
Hex-encoded public handle used to look up (and revoke) this credential.
lookupKey:
const lookupKey: PublicKey
lookupKey.
PublicKey.toHex(): string
toHex(),
48
algorithm: string
Signature algorithm of recoveryKey (e.g. ES256, ED25519).
The getPublicKeyAlgorithm() method of the AuthenticatorAttestationResponse interface returns a number that is equal to a COSE Algorithm Identifier, representing the cryptographic algorithm used for the new credential.
Identity.requestRecoveryChallenge gets a challenge from EDGE for this device.
navigator.credentials.get asks the user to sign it with the passkey.
Identity.recover sends the signature, the challenge and the lookup key from the user handle. EDGE checks them against
the identity’s recovery credentials and admits the device.
1
import*as
import Effect
Effectfrom'effect/Effect';
2
import {
import Identity
Identity } from'@dxos/halo';
3
import {
classPublicKey
The purpose of this class is to assure consistent use of keys throughout the project.
Keys should be maintained as buffers in objects and proto definitions, and converted to hex
strings as late as possible (eg, to log/display).
A typed array of 8-bit unsigned integer values. The contents are initialized to 0. If the
requested number of bytes could not be allocated an exception is raised.
Creates an array from an array-like or iterable object.
@param ― elements An iterable object to convert to an array.
@param ― mapfn A mapping function to call on every element of the array.
@param ― thisArg Value of 'this' used to invoke the mapfn.
from(
functionatob(data: string): string (+1overload)
Decodes a string of Base64-encoded data into bytes, and encodes those bytes
into a string using Latin-1 (ISO-8859-1).
The data may be any JavaScript-value that can be coerced into a string.
This function is only provided for compatibility with legacy web platform APIsand should never be used in new code, because they use strings to representbinary data and predate the introduction of typed arrays in JavaScript.For code running using Node.js APIs, converting between base64-encoded stringsand binary data should be performed using Buffer.from(str, 'base64') and buf.toString('base64').
@since ― v15.13.0, v14.17.0
@legacy ― Use Buffer.from(data, 'base64') instead.
@param ― data The Base64-encoded input string.
atob(
value: string
value), (
char: string
char) =>
char: string
char.
String.charCodeAt(index: number): number
Returns the Unicode value of the character at the specified location.
@param ― index The zero-based index of the desired character. If there is no character at the specified index, NaN is returned.
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.
@see ― tryPromise for a version that can handle failures.
@stability ― stable
@category ― constructors
@since ― 2.0.0
promise(() =>
12
var navigator: Navigator
The Window.navigator read-only property returns a reference to the Navigator object, which has methods and properties about the application running the script.
The credentials read-only property of the Navigator interface returns the CredentialsContainer object associated with the current document, which exposes methods to request credentials. The CredentialsContainer interface also notifies the user agent when an interesting event occurs, such as a successful sign-in or sign-out. This interface can be used for feature detection.
Available only in secure contexts.
The get() method of the CredentialsContainer interface returns a Promise that fulfills with a single credential, which can then be used to authenticate a user to a website.
The PublicKeyCredential interface provides information about a public key / private key pair, which is a credential for logging in to a service using an un-phishable and data-breach resistant asymmetric key pair instead of a password. It inherits from Credential, and is part of the Web Authentication API extension to the Credential Management API.
Available only in secure contexts.
The response read-only property of the PublicKeyCredential interface is an AuthenticatorResponse object which is sent from the authenticator to the user agent for the creation/fetching of credentials. The information contained in this response will be used by the relying party's server to verify the demand is legitimate.
The AuthenticatorAssertionResponse interface of the Web Authentication API contains a digital signature from the private key of a particular WebAuthn credential. The relying party's server can verify this signature to authenticate a user, for example when they sign in.
Available only in secure contexts.
Creates an effect that terminates a fiber with a specified error.
When to use
Use when you need an Effect to report an unrecoverable defect instead of a
typed error.
Details
The die function is used to signal a defect, which represents a critical
and unexpected error in the code. When invoked, it produces an effect that
does not handle the error and instead terminates the fiber.
The error channel of the resulting effect is of type never, indicating that
it cannot recover from this failure.
The response read-only property of the PublicKeyCredential interface is an AuthenticatorResponse object which is sent from the authenticator to the user agent for the creation/fetching of credentials. The information contained in this response will be used by the relying party's server to verify the demand is legitimate.
The userHandle read-only property of the AuthenticatorAssertionResponse interface is an ArrayBuffer object providing an opaque identifier for the given user. Such an identifier can be used by the relying party's server to link the user account with its corresponding credentials and other data.
Creates an effect that terminates a fiber with a specified error.
When to use
Use when you need an Effect to report an unrecoverable defect instead of a
typed error.
Details
The die function is used to signal a defect, which represents a critical
and unexpected error in the code. When invoked, it produces an effect that
does not handle the error and instead terminates the fiber.
The error channel of the resulting effect is of type never, indicating that
it cannot recover from this failure.
Re-admit this device via a recovery credential (requires
Service
).
recover({
35
passkey: {
readonly challenge: Identity.RecoveryChallenge;
readonly lookupKey: string;
readonly signature: Uint8Array;
readonly clientDataJson?: Uint8Array;
readonly authenticatorData?: Uint8Array;
}
passkey: {
36
challenge: {
readonly deviceKey: string;
readonly controlFeedKey: string;
readonly challenge: string;
}
challenge,
37
lookupKey: string
Hex-encoded lookup key of the credential being presented.
lookupKey:
classPublicKey
The purpose of this class is to assure consistent use of keys throughout the project.
Keys should be maintained as buffers in objects and proto definitions, and converted to hex
strings as late as possible (eg, to log/display).
PublicKey.
PublicKey.from(source: PublicKeyLike): PublicKey
Creates new instance of PublicKey automatically determining the input format.
@param ― source A Buffer, or Uint8Array, or hex encoded string, or something with an asUint8Array method on it
@returns ― PublicKey
from(new
var Uint8Array: Uint8ArrayConstructor
new <ArrayBuffer>(buffer: ArrayBuffer, byteOffset?: number, length?: number) =>Uint8Array<ArrayBuffer> (+6 overloads)
Uint8Array(
const userHandle: ArrayBuffer
userHandle)).
PublicKey.toHex(): string
toHex(),
38
signature: Uint8Array<ArrayBufferLike>
signature: new
var Uint8Array: Uint8ArrayConstructor
new <ArrayBuffer>(buffer: ArrayBuffer, byteOffset?: number, length?: number) =>Uint8Array<ArrayBuffer> (+6 overloads)
The signature read-only property of the AuthenticatorAssertionResponse interface is an ArrayBuffer object which is the signature of the authenticator for both AuthenticatorAssertionResponse.authenticatorData and a SHA-256 hash of the client data (AuthenticatorAssertionResponse.clientDataJSON).
new <ArrayBuffer>(buffer: ArrayBuffer, byteOffset?: number, length?: number) =>Uint8Array<ArrayBuffer> (+6 overloads)
Uint8Array(
const response: AuthenticatorAssertionResponse
response.
AuthenticatorResponse.clientDataJSON: ArrayBuffer
The clientDataJSON property of the AuthenticatorResponse interface stores a JSON string in an ArrayBuffer, representing the client data that was passed to navigator.credentials.create() or navigator.credentials.get(). This property is only accessed on one of the child objects of AuthenticatorResponse, specifically AuthenticatorAttestationResponse or AuthenticatorAssertionResponse.
The authenticatorData property of the AuthenticatorAssertionResponse interface returns an ArrayBuffer containing information from the authenticator such as the Relying Party ID Hash (rpIdHash), a signature counter, test of user presence, user verification flags, and any extensions processed by the authenticator.
Identity.credentials lists the recovery credentials, each with its kind and lookup key. revokeRecoveryCredential
removes one. HALO refuses to revoke the last active recovery credential, so register the replacement first.
Provides a way to write effectful code using generator functions, simplifying
control flow and error handling.
When to use
Use when you want to write effectful code that looks and behaves like
synchronous code, while still handling asynchronous tasks, errors, and complex
control flow such as loops and conditions.
Generator functions work similarly to async/await but keep errors,
requirements, and interruption in the Effect type. You can yield* values
from effects and return the final result at the end.