P256 signature utilities for WebAuthn.
npm i webauthn-p256
pnpm i webauthn-p256
bun i webauthn-p256
import { createCredential, sign, verify } from 'webauthn-p256'
// Register a WebAuthn credential (ie. passkey).
const credential = createCredential({
name: 'Example',
})
// Sign hash with credential.
const { signature, webauthn } = await sign({
credentialId: credential.id,
hash: '0x...'
})
// Verify signature with hash, public key, and WebAuthn data.
const verified = await verify({
hash: '0x...',
publicKey: credential.publicKey,
signature,
webauthn,
})
We can also verify WebAuthn signatures onchain via contracts that expose a WebAuthn verifier interface.
The example below uses Viem to call the verify
function on the WebAuthn.sol
contract. However, in a real world scenario, a contract implementing the WebAuthn verifier interface will call the verify
function (e.g. a isValidSignature
interface on an ERC-4337 Smart Wallet).
Note: Bytecode for the
code
variable can be obtained here.
import { createCredential, parsePublicKey, parseSignature, sign } from 'webauthn-p256'
import { createPublicClient, http } from 'viem'
import { mainnet } from 'viem/chains'
const abi = parseAbi([
'struct WebAuthnAuth { bytes authenticatorData; string clientDataJSON; uint256 challengeIndex; uint256 typeIndex; uint256 r; uint256 s; }',
'function verify(bytes, bool, WebAuthnAuth, uint256, uint256)'
])
const code = '0x...'
const credential = createCredential({
name: 'Example',
})
const hash = '0x...'
const { signature, webauthn } = await sign({
credentialId: credential.id,
hash
})
const { x, y } = parsePublicKey(credential.publicKey)
const { r, s } = parseSignature(signature)
const verified = await client.readContract({
abi,
code,
functionName: 'verify',
args: [
hash,
webauthn.userVerificationRequired,
{ ...webauthn, r, s },
x,
y,
],
})
Creates a P256 WebAuthn credential with a Passkey authenticator.
import { createCredential } from 'webauthn-p256'
const credential = createCredential({
name: 'Example',
})
Name | Description | Type |
---|---|---|
name |
Name for the credential. | string |
attestation |
Attestation type for the credential. | 'none' |
authenticatorSelection |
An object whose properties are criteria used to filter out the potential authenticators for the credential creation operation. | AuthenticatorSelection |
challenge |
Custom creation challenge for the credential. | BufferSource |
createFn |
Credential creation function. Useful for environments that do not support the WebAuthn API natively (i.e. React Native or testing environments). | (options: CredentialCreationOptions) => Promise<Credential | null> |
excludeCredentialIds |
List of credential IDs to exclude from the creation. This property can be used to prevent creation of a credential if it already exists. | string[] |
rp |
An object describing the relying party that requested the credential creation. | { id: string; name: string } |
timeout |
Timeout for the credential creation. | number |
user |
An object describing the user account for which the credential is generated. | { displayName: string; id: string; name: string } |
returns | P256 Credential | P256Credential |
Signs a hash using a stored credential. If no credential is provided, a prompt will be displayed for the user to select an existing credential that was previously registered.
import { sign } from 'webauthn-p256'
const credential = { /* ... */ }
const { signature, webauthn } = await sign({
credentialId: credential.id,
hash: '0x...',
})
Name | Description | Type |
---|---|---|
credentialId |
Credential ID to use for signing. | string |
getFn |
Credential retrieval function. | (options: CredentialRequestOptions) => Promise<Credential | null> |
hash |
Hash to sign. | 0x${string} |
rpId |
Relying party identifier. | string |
returns | Signature + WebAuthn response. | { signature: Hex; webauthn: WebAuthnData } |
Verifies a signature using the credential public key and the hash which was signed.
Warning
The verify
implementation mimics Daimo's audited WebAuthn.sol
– however, this TypeScript implementation is unaudited.
import { verify } from 'webauthn-p256'
const credential = { /* ... */ }
const signature = '0x...'
const webauthn = { /* ... */ }
const valid = await verify({
hash: '0x...',
publicKey: credential.publicKey,
signature,
webauthn,
})
Name | Description | Type |
---|---|---|
hash |
Hash to verify. | 0x${string} |
publicKey |
P256 Credential public key. | Hex |
signature |
P256 Signature. | Hex |
webauthn |
WebAuthn response. | WebAuthnData |
returns | Signature verification result. | boolean |
Returns the credential creation options for a P256-flavoured WebAuthn credential.
import { getCredentialCreationOptions } from 'webauthn-p256'
const options = getCredentialCreationOptions({
name: 'Example',
})
Name | Description | Type |
---|---|---|
name |
Name for the credential. | string |
challenge |
Custom creation challenge for the credential. | BufferSource |
excludeCredentialIds |
List of credential IDs to exclude from the creation. This property can be used to prevent creation of a credential if it already exists. | string[] |
rp |
An object describing the relying party that requested the credential creation. | { id: string; name: string } |
timeout |
Timeout for the credential creation. | number |
user |
An object describing the user account for which the credential is generated. | { displayName: string; id: string; name: string } |
returns | Public key credential | PublicKeyCredential |
Returns the credential sign request options for a P256-flavoured WebAuthn credential.
import { getCredentialSignRequestOptions } from 'webauthn-p256'
const options = getCredentialSignRequestOptions({
credentialId: '...',
hash: '0x...',
})
Name | Description | Type |
---|---|---|
credentialId |
Credential ID to use for signing. | string |
hash |
Hash to sign. | 0x${string} |
rpId |
Relying party identifier. | string |
returns | Credential | Credential |
Parses a serialized public key into x and y coordinates.
import { parsePublicKey } from 'webauthn-p256'
const publicKey = parsePublicKey('0x...')
console.log(publicKey)
// { x: 1231..., y: 12412... }
Name | Description | Type |
---|---|---|
publicKey |
Serialized P256 Credential public key. | 0x${string} |
returns | Parsed public key. | PublicKey |
Parses a serialized signature into r and s coordinates.
import { parseSignature } from 'webauthn-p256'
const signature = parseSignature('0x...')
console.log(signature)
// { r: 1231..., s: 12412... }
Name | Description | Type |
---|---|---|
signature |
Serialized P256 signature. | 0x${string} |
returns | Parsed P256 signature. | Signature |
Serializes a public key into a hex string or bytes.
import { serializePublicKey } from 'webauthn-p256'
const publicKey = serializePublicKey({
x: 12341...,
y: 12341...,
})
console.log(publicKey)
// '0x...'
Name | Description | Type |
---|---|---|
publicKey |
P256 Credential public key. | PublicKey |
returns | Serialized public key. | string |
Serializes a signature into a hex string or bytes.
import { serializeSignature } from 'webauthn-p256'
const signature = serializeSignature({
r: 12341...,
s: 12341...,
})
console.log(signature)
// '0x...'
Name | Description | Type |
---|---|---|
signature |
P256 signature. | Signature |
returns | Serialized signature. | string |
MIT License