@better-auth/passkey 1.4.8 → 1.5.0-beta.1
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 +64 -2
- package/dist/client.mjs +4 -2
- package/dist/error-codes-VuR_tYBt.mjs +15 -0
- package/dist/{index-DneB0hsm.d.mts → index-C3Ju4ySN.d.mts} +29 -8
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +15 -27
- package/package.json +5 -5
package/dist/client.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as WebAuthnChallengeValue, n as Passkey, r as PasskeyOptions, t as passkey } from "./index-
|
|
1
|
+
import { i as WebAuthnChallengeValue, n as Passkey, r as PasskeyOptions, t as passkey } from "./index-C3Ju4ySN.mjs";
|
|
2
2
|
import * as better_auth_client0 from "better-auth/client";
|
|
3
3
|
import * as nanostores0 from "nanostores";
|
|
4
4
|
import { atom } from "nanostores";
|
|
@@ -7,6 +7,38 @@ import { BetterFetch } from "@better-fetch/fetch";
|
|
|
7
7
|
import { Session, User } from "better-auth/types";
|
|
8
8
|
export * from "@simplewebauthn/server";
|
|
9
9
|
|
|
10
|
+
//#region src/error-codes.d.ts
|
|
11
|
+
declare const PASSKEY_ERROR_CODES: {
|
|
12
|
+
readonly CHALLENGE_NOT_FOUND: {
|
|
13
|
+
code: "CHALLENGE_NOT_FOUND";
|
|
14
|
+
message: "Challenge not found";
|
|
15
|
+
};
|
|
16
|
+
readonly YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY: {
|
|
17
|
+
code: "YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY";
|
|
18
|
+
message: "You are not allowed to register this passkey";
|
|
19
|
+
};
|
|
20
|
+
readonly FAILED_TO_VERIFY_REGISTRATION: {
|
|
21
|
+
code: "FAILED_TO_VERIFY_REGISTRATION";
|
|
22
|
+
message: "Failed to verify registration";
|
|
23
|
+
};
|
|
24
|
+
readonly PASSKEY_NOT_FOUND: {
|
|
25
|
+
code: "PASSKEY_NOT_FOUND";
|
|
26
|
+
message: "Passkey not found";
|
|
27
|
+
};
|
|
28
|
+
readonly AUTHENTICATION_FAILED: {
|
|
29
|
+
code: "AUTHENTICATION_FAILED";
|
|
30
|
+
message: "Authentication failed";
|
|
31
|
+
};
|
|
32
|
+
readonly UNABLE_TO_CREATE_SESSION: {
|
|
33
|
+
code: "UNABLE_TO_CREATE_SESSION";
|
|
34
|
+
message: "Unable to create session";
|
|
35
|
+
};
|
|
36
|
+
readonly FAILED_TO_UPDATE_PASSKEY: {
|
|
37
|
+
code: "FAILED_TO_UPDATE_PASSKEY";
|
|
38
|
+
message: "Failed to update passkey";
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
//#endregion
|
|
10
42
|
//#region src/client.d.ts
|
|
11
43
|
declare const getPasskeyActions: ($fetch: BetterFetch, {
|
|
12
44
|
$listPasskeys,
|
|
@@ -192,6 +224,36 @@ declare const passkeyClient: () => {
|
|
|
192
224
|
matcher: (path: string) => path is "/passkey/verify-authentication";
|
|
193
225
|
signal: "$sessionSignal";
|
|
194
226
|
})[];
|
|
227
|
+
$ERROR_CODES: {
|
|
228
|
+
readonly CHALLENGE_NOT_FOUND: {
|
|
229
|
+
code: "CHALLENGE_NOT_FOUND";
|
|
230
|
+
message: "Challenge not found";
|
|
231
|
+
};
|
|
232
|
+
readonly YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY: {
|
|
233
|
+
code: "YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY";
|
|
234
|
+
message: "You are not allowed to register this passkey";
|
|
235
|
+
};
|
|
236
|
+
readonly FAILED_TO_VERIFY_REGISTRATION: {
|
|
237
|
+
code: "FAILED_TO_VERIFY_REGISTRATION";
|
|
238
|
+
message: "Failed to verify registration";
|
|
239
|
+
};
|
|
240
|
+
readonly PASSKEY_NOT_FOUND: {
|
|
241
|
+
code: "PASSKEY_NOT_FOUND";
|
|
242
|
+
message: "Passkey not found";
|
|
243
|
+
};
|
|
244
|
+
readonly AUTHENTICATION_FAILED: {
|
|
245
|
+
code: "AUTHENTICATION_FAILED";
|
|
246
|
+
message: "Authentication failed";
|
|
247
|
+
};
|
|
248
|
+
readonly UNABLE_TO_CREATE_SESSION: {
|
|
249
|
+
code: "UNABLE_TO_CREATE_SESSION";
|
|
250
|
+
message: "Unable to create session";
|
|
251
|
+
};
|
|
252
|
+
readonly FAILED_TO_UPDATE_PASSKEY: {
|
|
253
|
+
code: "FAILED_TO_UPDATE_PASSKEY";
|
|
254
|
+
message: "Failed to update passkey";
|
|
255
|
+
};
|
|
256
|
+
};
|
|
195
257
|
};
|
|
196
258
|
//#endregion
|
|
197
|
-
export { Passkey, PasskeyOptions, WebAuthnChallengeValue, getPasskeyActions, passkeyClient };
|
|
259
|
+
export { PASSKEY_ERROR_CODES, Passkey, PasskeyOptions, WebAuthnChallengeValue, getPasskeyActions, passkeyClient };
|
package/dist/client.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { t as PASSKEY_ERROR_CODES } from "./error-codes-VuR_tYBt.mjs";
|
|
1
2
|
import { WebAuthnError, startAuthentication, startRegistration } from "@simplewebauthn/browser";
|
|
2
3
|
import { useAuthQuery } from "better-auth/client";
|
|
3
4
|
import { atom } from "nanostores";
|
|
@@ -138,9 +139,10 @@ const passkeyClient = () => {
|
|
|
138
139
|
}, {
|
|
139
140
|
matcher: (path) => path === "/passkey/verify-authentication",
|
|
140
141
|
signal: "$sessionSignal"
|
|
141
|
-
}]
|
|
142
|
+
}],
|
|
143
|
+
$ERROR_CODES: PASSKEY_ERROR_CODES
|
|
142
144
|
};
|
|
143
145
|
};
|
|
144
146
|
|
|
145
147
|
//#endregion
|
|
146
|
-
export { getPasskeyActions, passkeyClient };
|
|
148
|
+
export { PASSKEY_ERROR_CODES, getPasskeyActions, passkeyClient };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineErrorCodes } from "@better-auth/core/utils";
|
|
2
|
+
|
|
3
|
+
//#region src/error-codes.ts
|
|
4
|
+
const PASSKEY_ERROR_CODES = defineErrorCodes({
|
|
5
|
+
CHALLENGE_NOT_FOUND: "Challenge not found",
|
|
6
|
+
YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY: "You are not allowed to register this passkey",
|
|
7
|
+
FAILED_TO_VERIFY_REGISTRATION: "Failed to verify registration",
|
|
8
|
+
PASSKEY_NOT_FOUND: "Passkey not found",
|
|
9
|
+
AUTHENTICATION_FAILED: "Authentication failed",
|
|
10
|
+
UNABLE_TO_CREATE_SESSION: "Unable to create session",
|
|
11
|
+
FAILED_TO_UPDATE_PASSKEY: "Failed to update passkey"
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { PASSKEY_ERROR_CODES as t };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as _simplewebauthn_server0 from "@simplewebauthn/server";
|
|
2
2
|
import { CredentialDeviceType } from "@simplewebauthn/server";
|
|
3
|
-
import * as better_call0 from "better-call";
|
|
4
3
|
import * as zod0 from "zod";
|
|
5
4
|
import { InferOptionSchema } from "better-auth/types";
|
|
5
|
+
import * as better_call0 from "better-call";
|
|
6
6
|
import * as better_auth0 from "better-auth";
|
|
7
7
|
|
|
8
8
|
//#region src/schema.d.ts
|
|
@@ -686,13 +686,34 @@ declare const passkey: (options?: PasskeyOptions | undefined) => {
|
|
|
686
686
|
};
|
|
687
687
|
};
|
|
688
688
|
$ERROR_CODES: {
|
|
689
|
-
readonly CHALLENGE_NOT_FOUND:
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
readonly
|
|
694
|
-
|
|
695
|
-
|
|
689
|
+
readonly CHALLENGE_NOT_FOUND: {
|
|
690
|
+
code: "CHALLENGE_NOT_FOUND";
|
|
691
|
+
message: "Challenge not found";
|
|
692
|
+
};
|
|
693
|
+
readonly YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY: {
|
|
694
|
+
code: "YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY";
|
|
695
|
+
message: "You are not allowed to register this passkey";
|
|
696
|
+
};
|
|
697
|
+
readonly FAILED_TO_VERIFY_REGISTRATION: {
|
|
698
|
+
code: "FAILED_TO_VERIFY_REGISTRATION";
|
|
699
|
+
message: "Failed to verify registration";
|
|
700
|
+
};
|
|
701
|
+
readonly PASSKEY_NOT_FOUND: {
|
|
702
|
+
code: "PASSKEY_NOT_FOUND";
|
|
703
|
+
message: "Passkey not found";
|
|
704
|
+
};
|
|
705
|
+
readonly AUTHENTICATION_FAILED: {
|
|
706
|
+
code: "AUTHENTICATION_FAILED";
|
|
707
|
+
message: "Authentication failed";
|
|
708
|
+
};
|
|
709
|
+
readonly UNABLE_TO_CREATE_SESSION: {
|
|
710
|
+
code: "UNABLE_TO_CREATE_SESSION";
|
|
711
|
+
message: "Unable to create session";
|
|
712
|
+
};
|
|
713
|
+
readonly FAILED_TO_UPDATE_PASSKEY: {
|
|
714
|
+
code: "FAILED_TO_UPDATE_PASSKEY";
|
|
715
|
+
message: "Failed to update passkey";
|
|
716
|
+
};
|
|
696
717
|
};
|
|
697
718
|
options: PasskeyOptions | undefined;
|
|
698
719
|
};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as Passkey, r as PasskeyOptions, t as passkey } from "./index-
|
|
1
|
+
import { n as Passkey, r as PasskeyOptions, t as passkey } from "./index-C3Ju4ySN.mjs";
|
|
2
2
|
export { Passkey, PasskeyOptions, passkey };
|
package/dist/index.mjs
CHANGED
|
@@ -1,26 +1,14 @@
|
|
|
1
|
+
import { t as PASSKEY_ERROR_CODES } from "./error-codes-VuR_tYBt.mjs";
|
|
1
2
|
import { mergeSchema } from "better-auth/db";
|
|
2
|
-
import { defineErrorCodes } from "@better-auth/core/utils";
|
|
3
3
|
import { createAuthEndpoint } from "@better-auth/core/api";
|
|
4
|
+
import { APIError } from "@better-auth/core/error";
|
|
4
5
|
import { base64 } from "@better-auth/utils/base64";
|
|
5
6
|
import { generateAuthenticationOptions, generateRegistrationOptions, verifyAuthenticationResponse, verifyRegistrationResponse } from "@simplewebauthn/server";
|
|
6
7
|
import { freshSessionMiddleware, getSessionFromCtx, sessionMiddleware } from "better-auth/api";
|
|
7
8
|
import { setSessionCookie } from "better-auth/cookies";
|
|
8
9
|
import { generateRandomString } from "better-auth/crypto";
|
|
9
|
-
import { APIError } from "better-call";
|
|
10
10
|
import * as z from "zod";
|
|
11
11
|
|
|
12
|
-
//#region src/error-codes.ts
|
|
13
|
-
const PASSKEY_ERROR_CODES = defineErrorCodes({
|
|
14
|
-
CHALLENGE_NOT_FOUND: "Challenge not found",
|
|
15
|
-
YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY: "You are not allowed to register this passkey",
|
|
16
|
-
FAILED_TO_VERIFY_REGISTRATION: "Failed to verify registration",
|
|
17
|
-
PASSKEY_NOT_FOUND: "Passkey not found",
|
|
18
|
-
AUTHENTICATION_FAILED: "Authentication failed",
|
|
19
|
-
UNABLE_TO_CREATE_SESSION: "Unable to create session",
|
|
20
|
-
FAILED_TO_UPDATE_PASSKEY: "Failed to update passkey"
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
//#endregion
|
|
24
12
|
//#region src/utils.ts
|
|
25
13
|
function getRpID(options, baseURL) {
|
|
26
14
|
return options.rpID || (baseURL ? new URL(baseURL).hostname : "localhost");
|
|
@@ -272,11 +260,11 @@ const verifyPasskeyRegistration = (options) => createAuthEndpoint("/passkey/veri
|
|
|
272
260
|
const resp = ctx.body.response;
|
|
273
261
|
const webAuthnCookie = ctx.context.createAuthCookie(options.advanced.webAuthnChallengeCookie);
|
|
274
262
|
const verificationToken = await ctx.getSignedCookie(webAuthnCookie.name, ctx.context.secret);
|
|
275
|
-
if (!verificationToken) throw
|
|
263
|
+
if (!verificationToken) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.CHALLENGE_NOT_FOUND);
|
|
276
264
|
const data = await ctx.context.internalAdapter.findVerificationValue(verificationToken);
|
|
277
265
|
if (!data) return ctx.json(null, { status: 400 });
|
|
278
266
|
const { expectedChallenge, userData } = JSON.parse(data.value);
|
|
279
|
-
if (userData.id !== ctx.context.session.user.id) throw
|
|
267
|
+
if (userData.id !== ctx.context.session.user.id) throw APIError.from("UNAUTHORIZED", PASSKEY_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY);
|
|
280
268
|
try {
|
|
281
269
|
const { verified, registrationInfo } = await verifyRegistrationResponse({
|
|
282
270
|
response: resp,
|
|
@@ -308,7 +296,7 @@ const verifyPasskeyRegistration = (options) => createAuthEndpoint("/passkey/veri
|
|
|
308
296
|
return ctx.json(newPasskeyRes, { status: 200 });
|
|
309
297
|
} catch (e) {
|
|
310
298
|
ctx.context.logger.error("Failed to verify registration", e);
|
|
311
|
-
throw
|
|
299
|
+
throw APIError.from("INTERNAL_SERVER_ERROR", PASSKEY_ERROR_CODES.FAILED_TO_VERIFY_REGISTRATION);
|
|
312
300
|
}
|
|
313
301
|
});
|
|
314
302
|
const verifyPasskeyAuthenticationBodySchema = z.object({ response: z.record(z.any(), z.any()) });
|
|
@@ -338,9 +326,9 @@ const verifyPasskeyAuthentication = (options) => createAuthEndpoint("/passkey/ve
|
|
|
338
326
|
const resp = ctx.body.response;
|
|
339
327
|
const webAuthnCookie = ctx.context.createAuthCookie(options.advanced.webAuthnChallengeCookie);
|
|
340
328
|
const verificationToken = await ctx.getSignedCookie(webAuthnCookie.name, ctx.context.secret);
|
|
341
|
-
if (!verificationToken) throw
|
|
329
|
+
if (!verificationToken) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.CHALLENGE_NOT_FOUND);
|
|
342
330
|
const data = await ctx.context.internalAdapter.findVerificationValue(verificationToken);
|
|
343
|
-
if (!data) throw
|
|
331
|
+
if (!data) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.CHALLENGE_NOT_FOUND);
|
|
344
332
|
const { expectedChallenge } = JSON.parse(data.value);
|
|
345
333
|
const passkey$1 = await ctx.context.adapter.findOne({
|
|
346
334
|
model: "passkey",
|
|
@@ -349,7 +337,7 @@ const verifyPasskeyAuthentication = (options) => createAuthEndpoint("/passkey/ve
|
|
|
349
337
|
value: resp.id
|
|
350
338
|
}]
|
|
351
339
|
});
|
|
352
|
-
if (!passkey$1) throw
|
|
340
|
+
if (!passkey$1) throw APIError.from("UNAUTHORIZED", PASSKEY_ERROR_CODES.PASSKEY_NOT_FOUND);
|
|
353
341
|
try {
|
|
354
342
|
const verification = await verifyAuthenticationResponse({
|
|
355
343
|
response: resp,
|
|
@@ -365,7 +353,7 @@ const verifyPasskeyAuthentication = (options) => createAuthEndpoint("/passkey/ve
|
|
|
365
353
|
requireUserVerification: false
|
|
366
354
|
});
|
|
367
355
|
const { verified } = verification;
|
|
368
|
-
if (!verified) throw
|
|
356
|
+
if (!verified) throw APIError.from("UNAUTHORIZED", PASSKEY_ERROR_CODES.AUTHENTICATION_FAILED);
|
|
369
357
|
await ctx.context.adapter.update({
|
|
370
358
|
model: "passkey",
|
|
371
359
|
where: [{
|
|
@@ -375,7 +363,7 @@ const verifyPasskeyAuthentication = (options) => createAuthEndpoint("/passkey/ve
|
|
|
375
363
|
update: { counter: verification.authenticationInfo.newCounter }
|
|
376
364
|
});
|
|
377
365
|
const s = await ctx.context.internalAdapter.createSession(passkey$1.userId);
|
|
378
|
-
if (!s) throw
|
|
366
|
+
if (!s) throw APIError.from("INTERNAL_SERVER_ERROR", PASSKEY_ERROR_CODES.UNABLE_TO_CREATE_SESSION);
|
|
379
367
|
const user = await ctx.context.internalAdapter.findUserById(passkey$1.userId);
|
|
380
368
|
if (!user) throw new APIError("INTERNAL_SERVER_ERROR", { message: "User not found" });
|
|
381
369
|
await setSessionCookie(ctx, {
|
|
@@ -386,7 +374,7 @@ const verifyPasskeyAuthentication = (options) => createAuthEndpoint("/passkey/ve
|
|
|
386
374
|
return ctx.json({ session: s }, { status: 200 });
|
|
387
375
|
} catch (e) {
|
|
388
376
|
ctx.context.logger.error("Failed to verify authentication", e);
|
|
389
|
-
throw
|
|
377
|
+
throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.AUTHENTICATION_FAILED);
|
|
390
378
|
}
|
|
391
379
|
});
|
|
392
380
|
/**
|
|
@@ -479,7 +467,7 @@ const deletePasskey = createAuthEndpoint("/passkey/delete-passkey", {
|
|
|
479
467
|
value: ctx.body.id
|
|
480
468
|
}]
|
|
481
469
|
});
|
|
482
|
-
if (!passkey$1) throw
|
|
470
|
+
if (!passkey$1) throw APIError.from("NOT_FOUND", PASSKEY_ERROR_CODES.PASSKEY_NOT_FOUND);
|
|
483
471
|
if (passkey$1.userId !== ctx.context.session.user.id) throw new APIError("UNAUTHORIZED");
|
|
484
472
|
await ctx.context.adapter.delete({
|
|
485
473
|
model: "passkey",
|
|
@@ -532,8 +520,8 @@ const updatePasskey = createAuthEndpoint("/passkey/update-passkey", {
|
|
|
532
520
|
value: ctx.body.id
|
|
533
521
|
}]
|
|
534
522
|
});
|
|
535
|
-
if (!passkey$1) throw
|
|
536
|
-
if (passkey$1.userId !== ctx.context.session.user.id) throw
|
|
523
|
+
if (!passkey$1) throw APIError.from("NOT_FOUND", PASSKEY_ERROR_CODES.PASSKEY_NOT_FOUND);
|
|
524
|
+
if (passkey$1.userId !== ctx.context.session.user.id) throw APIError.from("UNAUTHORIZED", PASSKEY_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY);
|
|
537
525
|
const updatedPasskey = await ctx.context.adapter.update({
|
|
538
526
|
model: "passkey",
|
|
539
527
|
where: [{
|
|
@@ -542,7 +530,7 @@ const updatePasskey = createAuthEndpoint("/passkey/update-passkey", {
|
|
|
542
530
|
}],
|
|
543
531
|
update: { name: ctx.body.name }
|
|
544
532
|
});
|
|
545
|
-
if (!updatedPasskey) throw
|
|
533
|
+
if (!updatedPasskey) throw APIError.from("INTERNAL_SERVER_ERROR", PASSKEY_ERROR_CODES.FAILED_TO_UPDATE_PASSKEY);
|
|
546
534
|
return ctx.json({ passkey: updatedPasskey }, { status: 200 });
|
|
547
535
|
});
|
|
548
536
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/passkey",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0-beta.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Passkey plugin for Better Auth",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -33,8 +33,8 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"tsdown": "^0.17.2",
|
|
36
|
-
"@better-auth/core": "1.
|
|
37
|
-
"better-auth": "1.
|
|
36
|
+
"@better-auth/core": "1.5.0-beta.1",
|
|
37
|
+
"better-auth": "1.5.0-beta.1"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@simplewebauthn/browser": "^13.1.2",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"@better-fetch/fetch": "1.1.21",
|
|
47
47
|
"better-call": "1.1.7",
|
|
48
48
|
"nanostores": "^1.0.1",
|
|
49
|
-
"@better-auth/core": "1.
|
|
50
|
-
"better-auth": "1.
|
|
49
|
+
"@better-auth/core": "1.5.0-beta.1",
|
|
50
|
+
"better-auth": "1.5.0-beta.1"
|
|
51
51
|
},
|
|
52
52
|
"files": [
|
|
53
53
|
"dist"
|