@better-auth/passkey 1.7.0-beta.4 → 1.7.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as
|
|
1
|
+
import { a as Passkey, c as PasskeyOptions, d as WebAuthnChallengeValue, l as PasskeyRegistrationOptions, n as PASSKEY_ERROR_CODES, o as PasskeyAuthenticationOptions, s as PasskeyExtensionsResolver, t as passkey, u as PasskeyRegistrationUser } from "./index-Ci52vhOT.mjs";
|
|
2
2
|
import { AuthenticationExtensionsClientInputs, AuthenticationExtensionsClientOutputs, AuthenticationResponseJSON, RegistrationResponseJSON } from "@simplewebauthn/server";
|
|
3
3
|
import * as better_auth_client0 from "better-auth/client";
|
|
4
4
|
import * as nanostores from "nanostores";
|
package/dist/client.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as PASSKEY_ERROR_CODES, t as PACKAGE_VERSION } from "./version-
|
|
1
|
+
import { n as PASSKEY_ERROR_CODES, t as PACKAGE_VERSION } from "./version-tMqL0F6x.mjs";
|
|
2
2
|
import { WebAuthnError, startAuthentication, startRegistration } from "@simplewebauthn/browser";
|
|
3
3
|
import { useAuthQuery } from "better-auth/client";
|
|
4
4
|
import { atom } from "nanostores";
|
|
@@ -100,7 +100,13 @@ interface PasskeyRegistrationOptions {
|
|
|
100
100
|
}) => Awaitable<PasskeyRegistrationUser>) | undefined;
|
|
101
101
|
/**
|
|
102
102
|
* Callback after a successful registration verification.
|
|
103
|
-
* Useful for user linking or
|
|
103
|
+
* Useful for user linking, auditing, or labeling the passkey.
|
|
104
|
+
*
|
|
105
|
+
* Return `userId` to attribute the passkey to a different user. Return `name`
|
|
106
|
+
* to set the stored label when the client did not provide one; the AAGUID is
|
|
107
|
+
* available via `verification.registrationInfo?.aaguid`. A non-empty
|
|
108
|
+
* client-supplied name always takes precedence over the returned `name`;
|
|
109
|
+
* whitespace-only input is treated as absent.
|
|
104
110
|
*/
|
|
105
111
|
afterVerification?: ((args: {
|
|
106
112
|
ctx: GenericEndpointContext;
|
|
@@ -110,6 +116,7 @@ interface PasskeyRegistrationOptions {
|
|
|
110
116
|
context?: string | null | undefined;
|
|
111
117
|
}) => Awaitable<{
|
|
112
118
|
userId?: string;
|
|
119
|
+
name?: string;
|
|
113
120
|
} | void>) | undefined;
|
|
114
121
|
/**
|
|
115
122
|
* Optional WebAuthn extensions to include in registration options.
|
|
@@ -196,6 +203,30 @@ type Passkey = {
|
|
|
196
203
|
aaguid?: string | undefined;
|
|
197
204
|
};
|
|
198
205
|
//#endregion
|
|
206
|
+
//#region src/authenticator-metadata.d.ts
|
|
207
|
+
/**
|
|
208
|
+
* Best-effort map of common authenticator AAGUIDs to a human-readable provider
|
|
209
|
+
* name, for labeling passkeys in management UIs.
|
|
210
|
+
*
|
|
211
|
+
* An AAGUID identifies an authenticator *model* (not a device or a user) and is
|
|
212
|
+
* present only in the registration response. Better Auth stores it on every
|
|
213
|
+
* passkey row and returns it from `listPasskeys`, so a display label can be
|
|
214
|
+
* resolved wherever passkeys are rendered.
|
|
215
|
+
*
|
|
216
|
+
* This list is intentionally small and not authoritative. Many authenticators
|
|
217
|
+
* are missing, and privacy-preserving platforms report an all-zero AAGUID
|
|
218
|
+
* (`00000000-0000-0000-0000-000000000000`) that matches nothing here. Notably,
|
|
219
|
+
* Apple devices zero the AAGUID under the default `attestation: "none"` flow, so
|
|
220
|
+
* the Apple entries below only appear in attested or managed contexts. For full
|
|
221
|
+
* coverage, resolve against the community-maintained source instead:
|
|
222
|
+
*
|
|
223
|
+
* - https://github.com/passkeydeveloper/passkey-authenticator-aaguids
|
|
224
|
+
*
|
|
225
|
+
* Names mirror that source verbatim.
|
|
226
|
+
*/
|
|
227
|
+
declare const commonAuthenticatorNames: Record<string, string>;
|
|
228
|
+
declare const getAuthenticatorName: (aaguid: string | null | undefined) => string | undefined;
|
|
229
|
+
//#endregion
|
|
199
230
|
//#region src/error-codes.d.ts
|
|
200
231
|
declare const PASSKEY_ERROR_CODES: {
|
|
201
232
|
CHALLENGE_NOT_FOUND: better_auth0.RawError<"CHALLENGE_NOT_FOUND">;
|
|
@@ -817,4 +848,4 @@ declare const passkey: (options?: PasskeyOptions | undefined) => {
|
|
|
817
848
|
options: PasskeyOptions | undefined;
|
|
818
849
|
};
|
|
819
850
|
//#endregion
|
|
820
|
-
export {
|
|
851
|
+
export { Passkey as a, PasskeyOptions as c, WebAuthnChallengeValue as d, getAuthenticatorName as i, PasskeyRegistrationOptions as l, PASSKEY_ERROR_CODES as n, PasskeyAuthenticationOptions as o, commonAuthenticatorNames as r, PasskeyExtensionsResolver as s, passkey as t, PasskeyRegistrationUser as u };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { PASSKEY_ERROR_CODES, Passkey, PasskeyOptions, passkey };
|
|
1
|
+
import { a as Passkey, c as PasskeyOptions, i as getAuthenticatorName, n as PASSKEY_ERROR_CODES, r as commonAuthenticatorNames, t as passkey } from "./index-Ci52vhOT.mjs";
|
|
2
|
+
export { PASSKEY_ERROR_CODES, Passkey, PasskeyOptions, commonAuthenticatorNames, getAuthenticatorName, passkey };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as PASSKEY_ERROR_CODES, t as PACKAGE_VERSION } from "./version-
|
|
1
|
+
import { n as PASSKEY_ERROR_CODES, t as PACKAGE_VERSION } from "./version-tMqL0F6x.mjs";
|
|
2
2
|
import { mergeSchema } from "better-auth/db";
|
|
3
3
|
import { createAuthEndpoint } from "@better-auth/core/api";
|
|
4
4
|
import { APIError } from "@better-auth/core/error";
|
|
@@ -287,7 +287,7 @@ const generatePasskeyAuthenticationOptions = (opts, { maxAgeInSeconds }) => crea
|
|
|
287
287
|
});
|
|
288
288
|
const verifyPasskeyRegistrationBodySchema = z.object({
|
|
289
289
|
response: z.any(),
|
|
290
|
-
name: z.string().meta({ description: "Name of the passkey" }).optional()
|
|
290
|
+
name: z.string().trim().meta({ description: "Name of the passkey" }).optional()
|
|
291
291
|
});
|
|
292
292
|
const verifyPasskeyRegistration = (options) => {
|
|
293
293
|
const requireSession = options.registration?.requireSession ?? true;
|
|
@@ -335,6 +335,7 @@ const verifyPasskeyRegistration = (options) => {
|
|
|
335
335
|
displayName: userData.displayName
|
|
336
336
|
};
|
|
337
337
|
let targetUserId = resolvedUser.id;
|
|
338
|
+
let resolvedName = ctx.body.name || void 0;
|
|
338
339
|
if (options.registration?.afterVerification) {
|
|
339
340
|
const result = await options.registration.afterVerification({
|
|
340
341
|
ctx,
|
|
@@ -348,10 +349,11 @@ const verifyPasskeyRegistration = (options) => {
|
|
|
348
349
|
if (session?.user?.id && result.userId !== session.user.id) throw APIError.from("UNAUTHORIZED", PASSKEY_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY);
|
|
349
350
|
targetUserId = result.userId;
|
|
350
351
|
}
|
|
352
|
+
if (!resolvedName) resolvedName = result?.name?.trim() || void 0;
|
|
351
353
|
}
|
|
352
354
|
const pubKey = base64.encode(credential.publicKey);
|
|
353
355
|
const newPasskey = {
|
|
354
|
-
name:
|
|
356
|
+
name: resolvedName,
|
|
355
357
|
userId: targetUserId,
|
|
356
358
|
credentialID: credential.id,
|
|
357
359
|
publicKey: pubKey,
|
|
@@ -576,7 +578,7 @@ const updatePasskey = createAuthEndpoint("/passkey/update-passkey", {
|
|
|
576
578
|
method: "POST",
|
|
577
579
|
body: z.object({
|
|
578
580
|
id: z.string().meta({ description: `The ID of the passkey which will be updated. Eg: \"passkey-id\"` }),
|
|
579
|
-
name: z.string().meta({ description: `The new name which the passkey will be updated to. Eg: \"my-new-passkey-name\"` })
|
|
581
|
+
name: z.string().trim().min(1).meta({ description: `The new name which the passkey will be updated to. Eg: \"my-new-passkey-name\"` })
|
|
580
582
|
}),
|
|
581
583
|
use: [sessionMiddleware, requireResourceOwnership({
|
|
582
584
|
model: "passkey",
|
|
@@ -660,6 +662,63 @@ const schema = { passkey: { fields: {
|
|
|
660
662
|
}
|
|
661
663
|
} } };
|
|
662
664
|
//#endregion
|
|
665
|
+
//#region src/authenticator-metadata.ts
|
|
666
|
+
/**
|
|
667
|
+
* Best-effort map of common authenticator AAGUIDs to a human-readable provider
|
|
668
|
+
* name, for labeling passkeys in management UIs.
|
|
669
|
+
*
|
|
670
|
+
* An AAGUID identifies an authenticator *model* (not a device or a user) and is
|
|
671
|
+
* present only in the registration response. Better Auth stores it on every
|
|
672
|
+
* passkey row and returns it from `listPasskeys`, so a display label can be
|
|
673
|
+
* resolved wherever passkeys are rendered.
|
|
674
|
+
*
|
|
675
|
+
* This list is intentionally small and not authoritative. Many authenticators
|
|
676
|
+
* are missing, and privacy-preserving platforms report an all-zero AAGUID
|
|
677
|
+
* (`00000000-0000-0000-0000-000000000000`) that matches nothing here. Notably,
|
|
678
|
+
* Apple devices zero the AAGUID under the default `attestation: "none"` flow, so
|
|
679
|
+
* the Apple entries below only appear in attested or managed contexts. For full
|
|
680
|
+
* coverage, resolve against the community-maintained source instead:
|
|
681
|
+
*
|
|
682
|
+
* - https://github.com/passkeydeveloper/passkey-authenticator-aaguids
|
|
683
|
+
*
|
|
684
|
+
* Names mirror that source verbatim.
|
|
685
|
+
*/
|
|
686
|
+
const commonAuthenticatorNames = {
|
|
687
|
+
"ea9b8d66-4d01-1d21-3ce4-b6b48cb575d4": "Google Password Manager",
|
|
688
|
+
"fbfc3007-154e-4ecc-8c0b-6e020557d7bd": "Apple Passwords",
|
|
689
|
+
"dd4ec289-e01d-41c9-bb89-70fa845d4bf2": "iCloud Keychain (Managed)",
|
|
690
|
+
"08987058-cadc-4b81-b6e1-30de50dcbe96": "Windows Hello",
|
|
691
|
+
"9ddd1817-af5a-4672-a2b9-3e3dd95000a9": "Windows Hello",
|
|
692
|
+
"6028b017-b1d4-4c02-b4b3-afcdafc96bb2": "Windows Hello",
|
|
693
|
+
"bada5566-a7aa-401f-bd96-45619a55120d": "1Password",
|
|
694
|
+
"d548826e-79b4-db40-a3d8-11116f7e8349": "Bitwarden",
|
|
695
|
+
"531126d6-e717-415c-9320-3d9aa6981239": "Dashlane",
|
|
696
|
+
"b78a0a55-6ef8-d246-a042-ba0f6d55050c": "LastPass",
|
|
697
|
+
"b84e4048-15dc-4dd0-8640-f4f60813c8af": "NordPass",
|
|
698
|
+
"50726f74-6f6e-5061-7373-50726f746f6e": "Proton Pass",
|
|
699
|
+
"0ea242b4-43c4-4a1b-8b17-dd6d0b6baec6": "Keeper",
|
|
700
|
+
"53414d53-554e-4700-0000-000000000000": "Samsung Pass"
|
|
701
|
+
};
|
|
702
|
+
/**
|
|
703
|
+
* Resolve a best-effort provider name for an authenticator AAGUID.
|
|
704
|
+
*
|
|
705
|
+
* Returns `undefined` when the AAGUID is unknown, empty, or the all-zero value
|
|
706
|
+
* reported by privacy-preserving platforms. Casing and surrounding whitespace
|
|
707
|
+
* are normalized before lookup.
|
|
708
|
+
*
|
|
709
|
+
* @example
|
|
710
|
+
* ```ts
|
|
711
|
+
* const label = passkey.name || getAuthenticatorName(passkey.aaguid) || "Passkey";
|
|
712
|
+
* ```
|
|
713
|
+
*/
|
|
714
|
+
const ANONYMOUS_AAGUID = "00000000-0000-0000-0000-000000000000";
|
|
715
|
+
const getAuthenticatorName = (aaguid) => {
|
|
716
|
+
const normalized = aaguid?.trim().toLowerCase();
|
|
717
|
+
if (!normalized || normalized === ANONYMOUS_AAGUID) return void 0;
|
|
718
|
+
const name = commonAuthenticatorNames[normalized];
|
|
719
|
+
return typeof name === "string" ? name : void 0;
|
|
720
|
+
};
|
|
721
|
+
//#endregion
|
|
663
722
|
//#region src/index.ts
|
|
664
723
|
const MAX_AGE_IN_SECONDS = 300;
|
|
665
724
|
const passkey = (options) => {
|
|
@@ -689,4 +748,4 @@ const passkey = (options) => {
|
|
|
689
748
|
};
|
|
690
749
|
};
|
|
691
750
|
//#endregion
|
|
692
|
-
export { PASSKEY_ERROR_CODES, passkey };
|
|
751
|
+
export { PASSKEY_ERROR_CODES, commonAuthenticatorNames, getAuthenticatorName, passkey };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/passkey",
|
|
3
|
-
"version": "1.7.0-beta.
|
|
3
|
+
"version": "1.7.0-beta.5",
|
|
4
4
|
"description": "Passkey plugin for Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -55,16 +55,16 @@
|
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"tsdown": "0.21.1",
|
|
58
|
-
"@better-auth/core": "1.7.0-beta.
|
|
59
|
-
"better-auth": "1.7.0-beta.
|
|
58
|
+
"@better-auth/core": "1.7.0-beta.5",
|
|
59
|
+
"better-auth": "1.7.0-beta.5"
|
|
60
60
|
},
|
|
61
61
|
"peerDependencies": {
|
|
62
62
|
"@better-auth/utils": "0.4.1",
|
|
63
|
-
"@better-fetch/fetch": "1.
|
|
64
|
-
"better-call": "1.3.
|
|
63
|
+
"@better-fetch/fetch": "1.2.2",
|
|
64
|
+
"better-call": "1.3.6",
|
|
65
65
|
"nanostores": "^1.0.1",
|
|
66
|
-
"@better-auth/core": "^1.7.0-beta.
|
|
67
|
-
"better-auth": "^1.7.0-beta.
|
|
66
|
+
"@better-auth/core": "^1.7.0-beta.5",
|
|
67
|
+
"better-auth": "^1.7.0-beta.5"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"build": "tsdown",
|