Skip to content

Extend authorizeEntry signing callbacks: payload argument and custom signature ScVals - #1549

Merged
Ryang-21 merged 12 commits into
mainfrom
webauthn-auth-helpers
Jul 24, 2026
Merged

Extend authorizeEntry signing callbacks: payload argument and custom signature ScVals#1549
Ryang-21 merged 12 commits into
mainfrom
webauthn-auth-helpers

Conversation

@Ryang-21

@Ryang-21 Ryang-21 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

What

Extends authorizeEntry / authorizeInvocation signing callbacks in two ways:

  • The callback now receives the 32-byte signing payload (hash(preimage.toXDR())) as a second argument alongside the preimage, so signers that only accept a digest — HSMs, remote signers — never have to re-derive it. Existing single-argument callbacks are unaffected (#1532).
  • The callback may return { signatureScVal: xdr.ScVal, address?: string } instead of a raw 64-byte signature. The given ScVal is written verbatim as the credentials' signature — no Ed25519 verification, no {public_key, signature} map, no scvVec wrapping. The optional address routes the signature to a specific credential node, like forAddress (#1530).

Why

Custom account contracts (smart wallets, passkey/WebAuthn signers) define their own signature structure in __check_auth, so the SDK's Ed25519-only callback contract forced them to hand-roll preimage construction and credential assembly. With these two changes, authorizeEntry handles the preimage, expiration, and credential plumbing while the caller supplies whatever signature ScVal their contract expects.

The concrete WebAuthn helpers (buildWebAuthnSignatureScVal, normalizeSecp256r1Signature) were originally part of this PR but have been reverted; this PR now ships only the generic callback extensions.

Copilot AI review requested due to automatic review settings July 16, 2026 18:28
@github-project-automation github-project-automation Bot moved this to Backlog (Not Ready) in DevX Jul 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds WebAuthn/passkey authorization support for Soroban entries.

Changes:

  • Extends signing callbacks with payload and custom ScVal support.
  • Adds secp256r1 normalization and WebAuthn signature builders.
  • Adds tests, exports, dependencies, and documentation.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/base/auth.ts Extends authorization callbacks and custom signatures.
src/base/webauthn.ts Implements WebAuthn signature helpers.
src/base/index.ts Exports the new APIs.
test/unit/base/auth.test.ts Tests callback and custom-signature behavior.
test/unit/base/webauthn.test.ts Tests normalization and ScVal construction.
package.json Adds the test dependency.
pnpm-lock.yaml Locks the dependency versions.
docs/reference/core-transactions.md Documents WebAuthn APIs.
docs/reference/core-soroban-primitives.md Updates authorization API reference.
CHANGELOG.md Records the new functionality.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/base/webauthn.ts Outdated
Comment on lines +103 to +107
return nativeToScVal(
{
authenticator_data: toBytes(parts.authenticatorData),
client_data_json: toBytes(parts.clientDataJSON),
signature,
Comment thread src/base/auth.ts Outdated
) {
signature = toBuffer(sigResult.signature);
publicKey = sigResult.publicKey;
sigResult = await signer(preimage, payload);
Comment thread src/base/webauthn.ts Outdated
Comment on lines +145 to +150
if (sig.length === 64) {
let der: [bigint, bigint] | null = null;
if (sig[0] === 0x30) {
try {
der = parseDerSignature(sig);
} catch {
Ryang-21 and others added 2 commits July 22, 2026 14:04
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@socket-security

socket-security Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​noble/​curves@​2.2.010010010085100

View full report

Comment on lines +679 to 683
function signPayloadCallback(preimage, payload) {
// `payload` is hash(preimage.toXDR()) — inspect `preimage` if you want
// to display/verify what is being authorized before signing.
return signer.sign(payload);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this example, do we need to pass in preimage if we don't use it? It's only mentioned in the comment.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Callbacks to functions can be omitted. In the case of the preimage param you would need to pass an _ if you still needed access to payload.

Comment thread src/base/auth.ts
export type SigningCallback = (
preimage: xdr.HashIdPreimage,
) => Promise<BufferLike | { signature: BufferLike; publicKey: string }>;
payload: Buffer,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
payload: Buffer,
payload?: Buffer,

Can we make this optional so the signature is non-breaking?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did further digging since our convo. The params of a function callback can be omitted

await expect(
authorizeEntry(
authEntry,
() =>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you try actually assigning the callback like let callback: SigningCallback = () { ... } and see if it compiles? If it does then we don't need the optional.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also verified locally that this works

Comment thread src/base/webauthn.ts Outdated

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we sure this hand-rolled cryptography belongs in the SDK? Can we use a library or have it live elsewhere?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I would agree that it does not belong. Thats been reverted

Comment thread test/unit/base/webauthn.test.ts Outdated

// Differential check against @noble/curves (a well-reviewed reference
// implementation): for many real P-256 signatures, our DER parsing +
// low-S normalization must agree byte-for-byte with noble's.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If noble does this, lets use noble?

@Ryang-21 Ryang-21 changed the title Add WebAuthn/passkey auth helpers: signature ScVal builder and secp256r1 normalizer Extend authorizeEntry signing callbacks: payload argument and custom signature ScVals Jul 24, 2026
@Ryang-21
Ryang-21 merged commit 9526bd3 into main Jul 24, 2026
12 checks passed
@Ryang-21
Ryang-21 deleted the webauthn-auth-helpers branch July 24, 2026 21:07
@github-project-automation github-project-automation Bot moved this from Backlog (Not Ready) to Done in DevX Jul 24, 2026
@Ryang-21 Ryang-21 linked an issue Jul 27, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Expose auth-entry signing primitives as public APIs

4 participants