@better-auth/passkey 1.5.6 → 1.6.0-beta.0
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 +91 -35
- package/dist/client.mjs +45 -15
- package/dist/index-BzKpmgHh.d.mts +771 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +260 -187
- package/dist/{error-codes-DJf-1Ecu.mjs → version-B7zkjZSd.mjs} +8 -5
- package/package.json +10 -9
- package/dist/client.mjs.map +0 -1
- package/dist/error-codes-DJf-1Ecu.mjs.map +0 -1
- package/dist/index-B6ZC0I-g.d.mts +0 -727
- package/dist/index.mjs.map +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as PASSKEY_ERROR_CODES, o as PasskeyOptions, r as Passkey, t as passkey } from "./index-BzKpmgHh.mjs";
|
|
2
2
|
export { PASSKEY_ERROR_CODES, Passkey, PasskeyOptions, passkey };
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { n as PASSKEY_ERROR_CODES, t as PACKAGE_VERSION } from "./version-B7zkjZSd.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";
|
|
@@ -8,144 +8,189 @@ import { freshSessionMiddleware, getSessionFromCtx, sessionMiddleware } from "be
|
|
|
8
8
|
import { setSessionCookie } from "better-auth/cookies";
|
|
9
9
|
import { generateRandomString } from "better-auth/crypto";
|
|
10
10
|
import * as z from "zod";
|
|
11
|
-
|
|
12
11
|
//#region src/utils.ts
|
|
13
12
|
function getRpID(options, baseURL) {
|
|
14
13
|
return options.rpID || (baseURL ? new URL(baseURL).hostname : "localhost");
|
|
15
14
|
}
|
|
16
|
-
|
|
17
15
|
//#endregion
|
|
18
16
|
//#region src/routes.ts
|
|
17
|
+
const resolveExtensions = async (extensions, ctx) => {
|
|
18
|
+
if (!extensions) return;
|
|
19
|
+
if (typeof extensions === "function") return await extensions({ ctx });
|
|
20
|
+
return extensions;
|
|
21
|
+
};
|
|
22
|
+
const resolveRegistrationUser = async (opts, ctx) => {
|
|
23
|
+
if (opts.registration?.requireSession ?? true) {
|
|
24
|
+
const session = ctx.context?.session;
|
|
25
|
+
if (!session?.user?.id) throw APIError.from("UNAUTHORIZED", PASSKEY_ERROR_CODES.SESSION_REQUIRED);
|
|
26
|
+
const sessionName = session.user.email || session.user.id;
|
|
27
|
+
return {
|
|
28
|
+
id: session.user.id,
|
|
29
|
+
name: sessionName,
|
|
30
|
+
displayName: sessionName
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const session = await getSessionFromCtx(ctx);
|
|
34
|
+
if (session?.user?.id) {
|
|
35
|
+
const sessionName = session.user.email || session.user.id;
|
|
36
|
+
return {
|
|
37
|
+
id: session.user.id,
|
|
38
|
+
name: sessionName,
|
|
39
|
+
displayName: sessionName
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (!opts.registration?.resolveUser) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.RESOLVE_USER_REQUIRED);
|
|
43
|
+
const resolvedUser = await opts.registration.resolveUser({
|
|
44
|
+
ctx,
|
|
45
|
+
context: ctx.query?.context ?? null
|
|
46
|
+
});
|
|
47
|
+
if (!resolvedUser?.id || !resolvedUser?.name) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.RESOLVED_USER_INVALID);
|
|
48
|
+
return resolvedUser;
|
|
49
|
+
};
|
|
19
50
|
const generatePasskeyQuerySchema = z.object({
|
|
20
51
|
authenticatorAttachment: z.enum(["platform", "cross-platform"]).optional(),
|
|
21
|
-
name: z.string().optional()
|
|
52
|
+
name: z.string().optional(),
|
|
53
|
+
context: z.string().optional()
|
|
22
54
|
}).optional();
|
|
23
|
-
const generatePasskeyRegistrationOptions = (opts, { maxAgeInSeconds }) =>
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
55
|
+
const generatePasskeyRegistrationOptions = (opts, { maxAgeInSeconds }) => {
|
|
56
|
+
return createAuthEndpoint("/passkey/generate-register-options", {
|
|
57
|
+
method: "GET",
|
|
58
|
+
use: opts.registration?.requireSession ?? true ? [freshSessionMiddleware] : void 0,
|
|
59
|
+
query: generatePasskeyQuerySchema,
|
|
60
|
+
metadata: { openapi: {
|
|
61
|
+
operationId: "generatePasskeyRegistrationOptions",
|
|
62
|
+
description: "Generate registration options for a new passkey",
|
|
63
|
+
responses: { 200: {
|
|
64
|
+
description: "Success",
|
|
65
|
+
parameters: { query: {
|
|
66
|
+
authenticatorAttachment: {
|
|
67
|
+
description: `Type of authenticator to use for registration.
|
|
35
68
|
"platform" for device-specific authenticators,
|
|
36
69
|
"cross-platform" for authenticators that can be used across devices.`,
|
|
37
|
-
|
|
38
|
-
},
|
|
39
|
-
name: {
|
|
40
|
-
description: `Optional custom name for the passkey.
|
|
41
|
-
This can help identify the passkey when managing multiple credentials.`,
|
|
42
|
-
required: false
|
|
43
|
-
}
|
|
44
|
-
} },
|
|
45
|
-
content: { "application/json": { schema: {
|
|
46
|
-
type: "object",
|
|
47
|
-
properties: {
|
|
48
|
-
challenge: { type: "string" },
|
|
49
|
-
rp: {
|
|
50
|
-
type: "object",
|
|
51
|
-
properties: {
|
|
52
|
-
name: { type: "string" },
|
|
53
|
-
id: { type: "string" }
|
|
54
|
-
}
|
|
70
|
+
required: false
|
|
55
71
|
},
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
name: { type: "string" },
|
|
61
|
-
displayName: { type: "string" }
|
|
62
|
-
}
|
|
72
|
+
name: {
|
|
73
|
+
description: `Optional custom name for the passkey.
|
|
74
|
+
This can help identify the passkey when managing multiple credentials.`,
|
|
75
|
+
required: false
|
|
63
76
|
},
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
77
|
+
context: {
|
|
78
|
+
description: "Optional context for passkey-first registration flows.",
|
|
79
|
+
required: false
|
|
80
|
+
}
|
|
81
|
+
} },
|
|
82
|
+
content: { "application/json": { schema: {
|
|
83
|
+
type: "object",
|
|
84
|
+
properties: {
|
|
85
|
+
challenge: { type: "string" },
|
|
86
|
+
rp: {
|
|
67
87
|
type: "object",
|
|
68
88
|
properties: {
|
|
69
|
-
|
|
70
|
-
|
|
89
|
+
name: { type: "string" },
|
|
90
|
+
id: { type: "string" }
|
|
71
91
|
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
timeout: { type: "number" },
|
|
75
|
-
excludeCredentials: {
|
|
76
|
-
type: "array",
|
|
77
|
-
items: {
|
|
92
|
+
},
|
|
93
|
+
user: {
|
|
78
94
|
type: "object",
|
|
79
95
|
properties: {
|
|
80
96
|
id: { type: "string" },
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
97
|
+
name: { type: "string" },
|
|
98
|
+
displayName: { type: "string" }
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
pubKeyCredParams: {
|
|
102
|
+
type: "array",
|
|
103
|
+
items: {
|
|
104
|
+
type: "object",
|
|
105
|
+
properties: {
|
|
106
|
+
type: { type: "string" },
|
|
107
|
+
alg: { type: "number" }
|
|
85
108
|
}
|
|
86
109
|
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
110
|
+
},
|
|
111
|
+
timeout: { type: "number" },
|
|
112
|
+
excludeCredentials: {
|
|
113
|
+
type: "array",
|
|
114
|
+
items: {
|
|
115
|
+
type: "object",
|
|
116
|
+
properties: {
|
|
117
|
+
id: { type: "string" },
|
|
118
|
+
type: { type: "string" },
|
|
119
|
+
transports: {
|
|
120
|
+
type: "array",
|
|
121
|
+
items: { type: "string" }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
authenticatorSelection: {
|
|
127
|
+
type: "object",
|
|
128
|
+
properties: {
|
|
129
|
+
authenticatorAttachment: { type: "string" },
|
|
130
|
+
requireResidentKey: { type: "boolean" },
|
|
131
|
+
userVerification: { type: "string" }
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
attestation: { type: "string" },
|
|
135
|
+
extensions: { type: "object" }
|
|
136
|
+
}
|
|
137
|
+
} } }
|
|
138
|
+
} }
|
|
101
139
|
} }
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
140
|
+
}, async (ctx) => {
|
|
141
|
+
const user = await resolveRegistrationUser(opts, ctx);
|
|
142
|
+
const userPasskeys = await ctx.context.adapter.findMany({
|
|
143
|
+
model: "passkey",
|
|
144
|
+
where: [{
|
|
145
|
+
field: "userId",
|
|
146
|
+
value: user.id
|
|
147
|
+
}]
|
|
148
|
+
});
|
|
149
|
+
const registrationExtensions = await resolveExtensions(opts.registration?.extensions, ctx);
|
|
150
|
+
const userID = new TextEncoder().encode(generateRandomString(32, "a-z", "0-9"));
|
|
151
|
+
const baseURLString = typeof ctx.context.options.baseURL === "string" ? ctx.context.options.baseURL : void 0;
|
|
152
|
+
const options = await generateRegistrationOptions({
|
|
153
|
+
rpName: opts.rpName || ctx.context.appName,
|
|
154
|
+
rpID: getRpID(opts, baseURLString),
|
|
155
|
+
userID,
|
|
156
|
+
userName: ctx.query?.name || user.name || user.id,
|
|
157
|
+
userDisplayName: user.displayName || user.name || user.id,
|
|
158
|
+
attestationType: "none",
|
|
159
|
+
excludeCredentials: userPasskeys.map((passkey) => ({
|
|
160
|
+
id: passkey.credentialID,
|
|
161
|
+
transports: passkey.transports?.split(",")
|
|
162
|
+
})),
|
|
163
|
+
authenticatorSelection: {
|
|
164
|
+
residentKey: "preferred",
|
|
165
|
+
userVerification: "preferred",
|
|
166
|
+
...opts.authenticatorSelection || {},
|
|
167
|
+
...ctx.query?.authenticatorAttachment ? { authenticatorAttachment: ctx.query.authenticatorAttachment } : {}
|
|
168
|
+
},
|
|
169
|
+
extensions: registrationExtensions
|
|
170
|
+
});
|
|
171
|
+
const verificationToken = generateRandomString(32);
|
|
172
|
+
const webAuthnCookie = ctx.context.createAuthCookie(opts.advanced.webAuthnChallengeCookie);
|
|
173
|
+
await ctx.setSignedCookie(webAuthnCookie.name, verificationToken, ctx.context.secret, {
|
|
174
|
+
...webAuthnCookie.attributes,
|
|
175
|
+
maxAge: maxAgeInSeconds
|
|
176
|
+
});
|
|
177
|
+
const expirationTime = new Date(Date.now() + maxAgeInSeconds * 1e3);
|
|
178
|
+
await ctx.context.internalAdapter.createVerificationValue({
|
|
179
|
+
identifier: verificationToken,
|
|
180
|
+
value: JSON.stringify({
|
|
181
|
+
expectedChallenge: options.challenge,
|
|
182
|
+
userData: {
|
|
183
|
+
id: user.id,
|
|
184
|
+
name: user.name,
|
|
185
|
+
displayName: user.displayName
|
|
186
|
+
},
|
|
187
|
+
context: ctx.query?.context ?? null
|
|
188
|
+
}),
|
|
189
|
+
expiresAt: expirationTime
|
|
190
|
+
});
|
|
191
|
+
return ctx.json(options, { status: 200 });
|
|
146
192
|
});
|
|
147
|
-
|
|
148
|
-
});
|
|
193
|
+
};
|
|
149
194
|
const generatePasskeyAuthenticationOptions = (opts, { maxAgeInSeconds }) => createAuthEndpoint("/passkey/generate-authenticate-options", {
|
|
150
195
|
method: "GET",
|
|
151
196
|
metadata: { openapi: {
|
|
@@ -211,9 +256,12 @@ const generatePasskeyAuthenticationOptions = (opts, { maxAgeInSeconds }) => crea
|
|
|
211
256
|
value: session.user.id
|
|
212
257
|
}]
|
|
213
258
|
});
|
|
259
|
+
const baseURLString = typeof ctx.context.options.baseURL === "string" ? ctx.context.options.baseURL : void 0;
|
|
260
|
+
const authenticationExtensions = await resolveExtensions(opts.authentication?.extensions, ctx);
|
|
214
261
|
const options = await generateAuthenticationOptions({
|
|
215
|
-
rpID: getRpID(opts,
|
|
262
|
+
rpID: getRpID(opts, baseURLString),
|
|
216
263
|
userVerification: "preferred",
|
|
264
|
+
extensions: authenticationExtensions,
|
|
217
265
|
...userPasskeys.length ? { allowCredentials: userPasskeys.map((passkey) => ({
|
|
218
266
|
id: passkey.credentialID,
|
|
219
267
|
transports: passkey.transports?.split(",")
|
|
@@ -241,66 +289,91 @@ const verifyPasskeyRegistrationBodySchema = z.object({
|
|
|
241
289
|
response: z.any(),
|
|
242
290
|
name: z.string().meta({ description: "Name of the passkey" }).optional()
|
|
243
291
|
});
|
|
244
|
-
const verifyPasskeyRegistration = (options) =>
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
292
|
+
const verifyPasskeyRegistration = (options) => {
|
|
293
|
+
const requireSession = options.registration?.requireSession ?? true;
|
|
294
|
+
return createAuthEndpoint("/passkey/verify-registration", {
|
|
295
|
+
method: "POST",
|
|
296
|
+
body: verifyPasskeyRegistrationBodySchema,
|
|
297
|
+
use: requireSession ? [freshSessionMiddleware] : void 0,
|
|
298
|
+
metadata: { openapi: {
|
|
299
|
+
operationId: "passkeyVerifyRegistration",
|
|
300
|
+
description: "Verify registration of a new passkey",
|
|
301
|
+
responses: {
|
|
302
|
+
200: {
|
|
303
|
+
description: "Success",
|
|
304
|
+
content: { "application/json": { schema: { $ref: "#/components/schemas/Passkey" } } }
|
|
305
|
+
},
|
|
306
|
+
400: { description: "Bad request" }
|
|
307
|
+
}
|
|
308
|
+
} }
|
|
309
|
+
}, async (ctx) => {
|
|
310
|
+
const origin = options?.origin || ctx.headers?.get("origin") || "";
|
|
311
|
+
if (!origin) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.FAILED_TO_VERIFY_REGISTRATION);
|
|
312
|
+
const resp = ctx.body.response;
|
|
313
|
+
const webAuthnCookie = ctx.context.createAuthCookie(options.advanced.webAuthnChallengeCookie);
|
|
314
|
+
const verificationToken = await ctx.getSignedCookie(webAuthnCookie.name, ctx.context.secret);
|
|
315
|
+
if (!verificationToken) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.CHALLENGE_NOT_FOUND);
|
|
316
|
+
const data = await ctx.context.internalAdapter.findVerificationValue(verificationToken);
|
|
317
|
+
if (!data) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.CHALLENGE_NOT_FOUND);
|
|
318
|
+
const { expectedChallenge, userData, context } = JSON.parse(data.value);
|
|
319
|
+
const session = requireSession ? ctx.context.session : await getSessionFromCtx(ctx);
|
|
320
|
+
if (session?.user?.id && userData.id !== session.user.id) throw APIError.from("UNAUTHORIZED", PASSKEY_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY);
|
|
321
|
+
try {
|
|
322
|
+
const verification = await verifyRegistrationResponse({
|
|
323
|
+
response: resp,
|
|
324
|
+
expectedChallenge,
|
|
325
|
+
expectedOrigin: origin,
|
|
326
|
+
expectedRPID: getRpID(options, typeof ctx.context.options.baseURL === "string" ? ctx.context.options.baseURL : void 0),
|
|
327
|
+
requireUserVerification: false
|
|
328
|
+
});
|
|
329
|
+
const { verified, registrationInfo } = verification;
|
|
330
|
+
if (!verified || !registrationInfo) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.FAILED_TO_VERIFY_REGISTRATION);
|
|
331
|
+
const { aaguid, credentialDeviceType, credentialBackedUp, credential } = registrationInfo;
|
|
332
|
+
const resolvedUser = {
|
|
333
|
+
id: userData.id,
|
|
334
|
+
name: userData.name || userData.id,
|
|
335
|
+
displayName: userData.displayName
|
|
336
|
+
};
|
|
337
|
+
let targetUserId = resolvedUser.id;
|
|
338
|
+
if (options.registration?.afterVerification) {
|
|
339
|
+
const result = await options.registration.afterVerification({
|
|
340
|
+
ctx,
|
|
341
|
+
verification,
|
|
342
|
+
user: resolvedUser,
|
|
343
|
+
clientData: resp,
|
|
344
|
+
context
|
|
345
|
+
});
|
|
346
|
+
if (result?.userId) {
|
|
347
|
+
if (typeof result.userId !== "string" || !result.userId) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.RESOLVED_USER_INVALID);
|
|
348
|
+
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
|
+
targetUserId = result.userId;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const pubKey = base64.encode(credential.publicKey);
|
|
353
|
+
const newPasskey = {
|
|
354
|
+
name: ctx.body.name,
|
|
355
|
+
userId: targetUserId,
|
|
356
|
+
credentialID: credential.id,
|
|
357
|
+
publicKey: pubKey,
|
|
358
|
+
counter: credential.counter,
|
|
359
|
+
deviceType: credentialDeviceType,
|
|
360
|
+
transports: resp.response.transports.join(","),
|
|
361
|
+
backedUp: credentialBackedUp,
|
|
362
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
363
|
+
aaguid
|
|
364
|
+
};
|
|
365
|
+
const newPasskeyRes = await ctx.context.adapter.create({
|
|
366
|
+
model: "passkey",
|
|
367
|
+
data: newPasskey
|
|
368
|
+
});
|
|
369
|
+
await ctx.context.internalAdapter.deleteVerificationByIdentifier(verificationToken);
|
|
370
|
+
return ctx.json(newPasskeyRes, { status: 200 });
|
|
371
|
+
} catch (e) {
|
|
372
|
+
ctx.context.logger.error("Failed to verify registration", e);
|
|
373
|
+
throw APIError.from("INTERNAL_SERVER_ERROR", PASSKEY_ERROR_CODES.FAILED_TO_VERIFY_REGISTRATION);
|
|
257
374
|
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
const origin = options?.origin || ctx.headers?.get("origin") || "";
|
|
261
|
-
if (!origin) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.FAILED_TO_VERIFY_REGISTRATION);
|
|
262
|
-
const resp = ctx.body.response;
|
|
263
|
-
const webAuthnCookie = ctx.context.createAuthCookie(options.advanced.webAuthnChallengeCookie);
|
|
264
|
-
const verificationToken = await ctx.getSignedCookie(webAuthnCookie.name, ctx.context.secret);
|
|
265
|
-
if (!verificationToken) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.CHALLENGE_NOT_FOUND);
|
|
266
|
-
const data = await ctx.context.internalAdapter.findVerificationValue(verificationToken);
|
|
267
|
-
if (!data) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.CHALLENGE_NOT_FOUND);
|
|
268
|
-
const { expectedChallenge, userData } = JSON.parse(data.value);
|
|
269
|
-
if (userData.id !== ctx.context.session.user.id) throw APIError.from("UNAUTHORIZED", PASSKEY_ERROR_CODES.YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY);
|
|
270
|
-
try {
|
|
271
|
-
const { verified, registrationInfo } = await verifyRegistrationResponse({
|
|
272
|
-
response: resp,
|
|
273
|
-
expectedChallenge,
|
|
274
|
-
expectedOrigin: origin,
|
|
275
|
-
expectedRPID: getRpID(options, typeof ctx.context.options.baseURL === "string" ? ctx.context.options.baseURL : void 0),
|
|
276
|
-
requireUserVerification: false
|
|
277
|
-
});
|
|
278
|
-
if (!verified || !registrationInfo) throw APIError.from("BAD_REQUEST", PASSKEY_ERROR_CODES.FAILED_TO_VERIFY_REGISTRATION);
|
|
279
|
-
const { aaguid, credentialDeviceType, credentialBackedUp, credential } = registrationInfo;
|
|
280
|
-
const pubKey = base64.encode(credential.publicKey);
|
|
281
|
-
const newPasskey = {
|
|
282
|
-
name: ctx.body.name,
|
|
283
|
-
userId: userData.id,
|
|
284
|
-
credentialID: credential.id,
|
|
285
|
-
publicKey: pubKey,
|
|
286
|
-
counter: credential.counter,
|
|
287
|
-
deviceType: credentialDeviceType,
|
|
288
|
-
transports: resp.response.transports.join(","),
|
|
289
|
-
backedUp: credentialBackedUp,
|
|
290
|
-
createdAt: /* @__PURE__ */ new Date(),
|
|
291
|
-
aaguid
|
|
292
|
-
};
|
|
293
|
-
const newPasskeyRes = await ctx.context.adapter.create({
|
|
294
|
-
model: "passkey",
|
|
295
|
-
data: newPasskey
|
|
296
|
-
});
|
|
297
|
-
await ctx.context.internalAdapter.deleteVerificationByIdentifier(verificationToken);
|
|
298
|
-
return ctx.json(newPasskeyRes, { status: 200 });
|
|
299
|
-
} catch (e) {
|
|
300
|
-
ctx.context.logger.error("Failed to verify registration", e);
|
|
301
|
-
throw APIError.from("INTERNAL_SERVER_ERROR", PASSKEY_ERROR_CODES.FAILED_TO_VERIFY_REGISTRATION);
|
|
302
|
-
}
|
|
303
|
-
});
|
|
375
|
+
});
|
|
376
|
+
};
|
|
304
377
|
const verifyPasskeyAuthenticationBodySchema = z.object({ response: z.record(z.any(), z.any()) });
|
|
305
378
|
const verifyPasskeyAuthentication = (options) => createAuthEndpoint("/passkey/verify-authentication", {
|
|
306
379
|
method: "POST",
|
|
@@ -356,6 +429,11 @@ const verifyPasskeyAuthentication = (options) => createAuthEndpoint("/passkey/ve
|
|
|
356
429
|
});
|
|
357
430
|
const { verified } = verification;
|
|
358
431
|
if (!verified) throw APIError.from("UNAUTHORIZED", PASSKEY_ERROR_CODES.AUTHENTICATION_FAILED);
|
|
432
|
+
if (options.authentication?.afterVerification) await options.authentication.afterVerification({
|
|
433
|
+
ctx,
|
|
434
|
+
verification,
|
|
435
|
+
clientData: resp
|
|
436
|
+
});
|
|
359
437
|
await ctx.context.adapter.update({
|
|
360
438
|
model: "passkey",
|
|
361
439
|
where: [{
|
|
@@ -427,7 +505,6 @@ const listPasskeys = createAuthEndpoint("/passkey/list-user-passkeys", {
|
|
|
427
505
|
});
|
|
428
506
|
return ctx.json(passkeys, { status: 200 });
|
|
429
507
|
});
|
|
430
|
-
const deletePasskeyBodySchema = z.object({ id: z.string().meta({ description: "The ID of the passkey to delete. Eg: \"some-passkey-id\"" }) });
|
|
431
508
|
/**
|
|
432
509
|
* ### Endpoint
|
|
433
510
|
*
|
|
@@ -445,7 +522,7 @@ const deletePasskeyBodySchema = z.object({ id: z.string().meta({ description: "T
|
|
|
445
522
|
*/
|
|
446
523
|
const deletePasskey = createAuthEndpoint("/passkey/delete-passkey", {
|
|
447
524
|
method: "POST",
|
|
448
|
-
body:
|
|
525
|
+
body: z.object({ id: z.string().meta({ description: "The ID of the passkey to delete. Eg: \"some-passkey-id\"" }) }),
|
|
449
526
|
use: [sessionMiddleware],
|
|
450
527
|
metadata: { openapi: {
|
|
451
528
|
description: "Delete a specific passkey",
|
|
@@ -480,10 +557,6 @@ const deletePasskey = createAuthEndpoint("/passkey/delete-passkey", {
|
|
|
480
557
|
});
|
|
481
558
|
return ctx.json({ status: true });
|
|
482
559
|
});
|
|
483
|
-
const updatePassKeyBodySchema = z.object({
|
|
484
|
-
id: z.string().meta({ description: `The ID of the passkey which will be updated. Eg: \"passkey-id\"` }),
|
|
485
|
-
name: z.string().meta({ description: `The new name which the passkey will be updated to. Eg: \"my-new-passkey-name\"` })
|
|
486
|
-
});
|
|
487
560
|
/**
|
|
488
561
|
* ### Endpoint
|
|
489
562
|
*
|
|
@@ -501,7 +574,10 @@ const updatePassKeyBodySchema = z.object({
|
|
|
501
574
|
*/
|
|
502
575
|
const updatePasskey = createAuthEndpoint("/passkey/update-passkey", {
|
|
503
576
|
method: "POST",
|
|
504
|
-
body:
|
|
577
|
+
body: z.object({
|
|
578
|
+
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\"` })
|
|
580
|
+
}),
|
|
505
581
|
use: [sessionMiddleware],
|
|
506
582
|
metadata: { openapi: {
|
|
507
583
|
description: "Update a specific passkey's name",
|
|
@@ -535,7 +611,6 @@ const updatePasskey = createAuthEndpoint("/passkey/update-passkey", {
|
|
|
535
611
|
if (!updatedPasskey) throw APIError.from("INTERNAL_SERVER_ERROR", PASSKEY_ERROR_CODES.FAILED_TO_UPDATE_PASSKEY);
|
|
536
612
|
return ctx.json({ passkey: updatedPasskey }, { status: 200 });
|
|
537
613
|
});
|
|
538
|
-
|
|
539
614
|
//#endregion
|
|
540
615
|
//#region src/schema.ts
|
|
541
616
|
const schema = { passkey: { fields: {
|
|
@@ -586,7 +661,6 @@ const schema = { passkey: { fields: {
|
|
|
586
661
|
required: false
|
|
587
662
|
}
|
|
588
663
|
} } };
|
|
589
|
-
|
|
590
664
|
//#endregion
|
|
591
665
|
//#region src/index.ts
|
|
592
666
|
const MAX_AGE_IN_SECONDS = 300;
|
|
@@ -601,6 +675,7 @@ const passkey = (options) => {
|
|
|
601
675
|
};
|
|
602
676
|
return {
|
|
603
677
|
id: "passkey",
|
|
678
|
+
version: PACKAGE_VERSION,
|
|
604
679
|
endpoints: {
|
|
605
680
|
generatePasskeyRegistrationOptions: generatePasskeyRegistrationOptions(opts, { maxAgeInSeconds: MAX_AGE_IN_SECONDS }),
|
|
606
681
|
generatePasskeyAuthenticationOptions: generatePasskeyAuthenticationOptions(opts, { maxAgeInSeconds: MAX_AGE_IN_SECONDS }),
|
|
@@ -615,7 +690,5 @@ const passkey = (options) => {
|
|
|
615
690
|
options
|
|
616
691
|
};
|
|
617
692
|
};
|
|
618
|
-
|
|
619
693
|
//#endregion
|
|
620
694
|
export { PASSKEY_ERROR_CODES, passkey };
|
|
621
|
-
//# sourceMappingURL=index.mjs.map
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { defineErrorCodes } from "@better-auth/core/utils/error-codes";
|
|
2
|
-
|
|
3
2
|
//#region src/error-codes.ts
|
|
4
3
|
const PASSKEY_ERROR_CODES = defineErrorCodes({
|
|
5
4
|
CHALLENGE_NOT_FOUND: "Challenge not found",
|
|
@@ -12,9 +11,13 @@ const PASSKEY_ERROR_CODES = defineErrorCodes({
|
|
|
12
11
|
PREVIOUSLY_REGISTERED: "Previously registered",
|
|
13
12
|
REGISTRATION_CANCELLED: "Registration cancelled",
|
|
14
13
|
AUTH_CANCELLED: "Auth cancelled",
|
|
15
|
-
UNKNOWN_ERROR: "Unknown error"
|
|
14
|
+
UNKNOWN_ERROR: "Unknown error",
|
|
15
|
+
SESSION_REQUIRED: "Passkey registration requires an authenticated session",
|
|
16
|
+
RESOLVE_USER_REQUIRED: "Passkey registration requires either an authenticated session or a resolveUser callback when requireSession is false",
|
|
17
|
+
RESOLVED_USER_INVALID: "Resolved user is invalid"
|
|
16
18
|
});
|
|
17
|
-
|
|
18
19
|
//#endregion
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
//#region src/version.ts
|
|
21
|
+
const PACKAGE_VERSION = "1.6.0-beta.0";
|
|
22
|
+
//#endregion
|
|
23
|
+
export { PASSKEY_ERROR_CODES as n, PACKAGE_VERSION as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/passkey",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0-beta.0",
|
|
4
4
|
"description": "Passkey plugin for Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"publishConfig": {
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
|
+
"sideEffects": false,
|
|
22
23
|
"files": [
|
|
23
24
|
"dist"
|
|
24
25
|
],
|
|
@@ -53,22 +54,22 @@
|
|
|
53
54
|
"zod": "^4.3.6"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
56
|
-
"tsdown": "0.21.
|
|
57
|
-
"@better-auth/core": "1.
|
|
58
|
-
"better-auth": "1.
|
|
57
|
+
"tsdown": "0.21.1",
|
|
58
|
+
"@better-auth/core": "1.6.0-beta.0",
|
|
59
|
+
"better-auth": "1.6.0-beta.0"
|
|
59
60
|
},
|
|
60
61
|
"peerDependencies": {
|
|
61
|
-
"@better-auth/utils": "0.
|
|
62
|
+
"@better-auth/utils": "0.4.0",
|
|
62
63
|
"@better-fetch/fetch": "1.1.21",
|
|
63
|
-
"better-call": "
|
|
64
|
+
"better-call": "2.0.3",
|
|
64
65
|
"nanostores": "^1.0.1",
|
|
65
|
-
"@better-auth/core": "1.
|
|
66
|
-
"better-auth": "1.
|
|
66
|
+
"@better-auth/core": "^1.6.0-beta.0",
|
|
67
|
+
"better-auth": "^1.6.0-beta.0"
|
|
67
68
|
},
|
|
68
69
|
"scripts": {
|
|
69
70
|
"build": "tsdown",
|
|
70
71
|
"dev": "tsdown --watch",
|
|
71
|
-
"lint:package": "publint run --strict",
|
|
72
|
+
"lint:package": "publint run --strict --pack false",
|
|
72
73
|
"lint:types": "attw --profile esm-only --pack .",
|
|
73
74
|
"typecheck": "tsc --project tsconfig.json",
|
|
74
75
|
"test": "vitest",
|
package/dist/client.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import type {\n\tBetterAuthClientPlugin,\n\tClientFetchOption,\n\tClientStore,\n} from \"@better-auth/core\";\nimport type { BetterFetch } from \"@better-fetch/fetch\";\nimport type {\n\tPublicKeyCredentialCreationOptionsJSON,\n\tPublicKeyCredentialRequestOptionsJSON,\n} from \"@simplewebauthn/browser\";\nimport {\n\tstartAuthentication,\n\tstartRegistration,\n\tWebAuthnError,\n} from \"@simplewebauthn/browser\";\nimport { useAuthQuery } from \"better-auth/client\";\nimport type { Session, User } from \"better-auth/types\";\nimport { atom } from \"nanostores\";\nimport type { passkey } from \".\";\nimport { PASSKEY_ERROR_CODES } from \"./error-codes\";\nimport type { Passkey } from \"./types\";\n\nexport const getPasskeyActions = (\n\t$fetch: BetterFetch,\n\t{\n\t\t$listPasskeys,\n\t\t$store,\n\t}: {\n\t\t$listPasskeys: ReturnType<typeof atom<any>>;\n\t\t$store: ClientStore;\n\t},\n) => {\n\tconst signInPasskey = async (\n\t\topts?:\n\t\t\t| {\n\t\t\t\t\tautoFill?: boolean;\n\t\t\t\t\tfetchOptions?: ClientFetchOption;\n\t\t\t }\n\t\t\t| undefined,\n\t\toptions?: ClientFetchOption | undefined,\n\t) => {\n\t\tconst response = await $fetch<PublicKeyCredentialRequestOptionsJSON>(\n\t\t\t\"/passkey/generate-authenticate-options\",\n\t\t\t{\n\t\t\t\tmethod: \"GET\",\n\t\t\t\tthrow: false,\n\t\t\t},\n\t\t);\n\t\tif (!response.data) {\n\t\t\treturn response;\n\t\t}\n\t\ttry {\n\t\t\tconst res = await startAuthentication({\n\t\t\t\toptionsJSON: response.data,\n\t\t\t\tuseBrowserAutofill: opts?.autoFill,\n\t\t\t});\n\t\t\tconst verified = await $fetch<{\n\t\t\t\tsession: Session;\n\t\t\t\tuser: User;\n\t\t\t}>(\"/passkey/verify-authentication\", {\n\t\t\t\tbody: {\n\t\t\t\t\tresponse: res,\n\t\t\t\t},\n\t\t\t\t...opts?.fetchOptions,\n\t\t\t\t...options,\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tthrow: false,\n\t\t\t});\n\t\t\t$listPasskeys.set(Math.random());\n\t\t\t$store.notify(\"$sessionSignal\");\n\n\t\t\treturn verified;\n\t\t} catch (err) {\n\t\t\t// Error logs ran on the front-end\n\t\t\tconsole.error(`[Better Auth] Error verifying passkey`, err);\n\t\t\treturn {\n\t\t\t\tdata: null,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"AUTH_CANCELLED\",\n\t\t\t\t\tmessage: PASSKEY_ERROR_CODES.AUTH_CANCELLED,\n\t\t\t\t\tstatus: 400,\n\t\t\t\t\tstatusText: \"BAD_REQUEST\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t};\n\n\tconst registerPasskey = async (\n\t\topts?:\n\t\t\t| {\n\t\t\t\t\tfetchOptions?: ClientFetchOption;\n\t\t\t\t\t/**\n\t\t\t\t\t * The name of the passkey. This is used to\n\t\t\t\t\t * identify the passkey in the UI.\n\t\t\t\t\t */\n\t\t\t\t\tname?: string;\n\n\t\t\t\t\t/**\n\t\t\t\t\t * The type of attachment for the passkey. Defaults to both\n\t\t\t\t\t * platform and cross-platform allowed, with platform preferred.\n\t\t\t\t\t */\n\t\t\t\t\tauthenticatorAttachment?: \"platform\" | \"cross-platform\";\n\n\t\t\t\t\t/**\n\t\t\t\t\t * Try to silently create a passkey with the password manager that the user just signed\n\t\t\t\t\t * in with.\n\t\t\t\t\t * @default false\n\t\t\t\t\t */\n\t\t\t\t\tuseAutoRegister?: boolean;\n\t\t\t }\n\t\t\t| undefined,\n\t\tfetchOpts?: ClientFetchOption | undefined,\n\t) => {\n\t\tconst options = await $fetch<PublicKeyCredentialCreationOptionsJSON>(\n\t\t\t\"/passkey/generate-register-options\",\n\t\t\t{\n\t\t\t\tmethod: \"GET\",\n\t\t\t\tquery: {\n\t\t\t\t\t...(opts?.authenticatorAttachment && {\n\t\t\t\t\t\tauthenticatorAttachment: opts.authenticatorAttachment,\n\t\t\t\t\t}),\n\t\t\t\t\t...(opts?.name && {\n\t\t\t\t\t\tname: opts.name,\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\tthrow: false,\n\t\t\t},\n\t\t);\n\n\t\tif (!options.data) {\n\t\t\treturn options;\n\t\t}\n\t\ttry {\n\t\t\tconst res = await startRegistration({\n\t\t\t\toptionsJSON: options.data,\n\t\t\t\tuseAutoRegister: opts?.useAutoRegister,\n\t\t\t});\n\t\t\tconst verified = await $fetch<Passkey>(\"/passkey/verify-registration\", {\n\t\t\t\t...opts?.fetchOptions,\n\t\t\t\t...fetchOpts,\n\t\t\t\tbody: {\n\t\t\t\t\tresponse: res,\n\t\t\t\t\tname: opts?.name,\n\t\t\t\t},\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tthrow: false,\n\t\t\t});\n\n\t\t\tif (!verified.data) {\n\t\t\t\treturn verified;\n\t\t\t}\n\t\t\t$listPasskeys.set(Math.random());\n\t\t\treturn verified;\n\t\t} catch (e) {\n\t\t\tif (e instanceof WebAuthnError) {\n\t\t\t\tif (e.code === \"ERROR_AUTHENTICATOR_PREVIOUSLY_REGISTERED\") {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdata: null,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: e.code,\n\t\t\t\t\t\t\tmessage: PASSKEY_ERROR_CODES.PREVIOUSLY_REGISTERED,\n\t\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t\t\tstatusText: \"BAD_REQUEST\",\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (e.code === \"ERROR_CEREMONY_ABORTED\") {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdata: null,\n\t\t\t\t\t\terror: {\n\t\t\t\t\t\t\tcode: e.code,\n\t\t\t\t\t\t\tmessage: PASSKEY_ERROR_CODES.REGISTRATION_CANCELLED,\n\t\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t\t\tstatusText: \"BAD_REQUEST\",\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tdata: null,\n\t\t\t\t\terror: {\n\t\t\t\t\t\tcode: e.code,\n\t\t\t\t\t\tmessage: e.message,\n\t\t\t\t\t\tstatus: 400,\n\t\t\t\t\t\tstatusText: \"BAD_REQUEST\",\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tdata: null,\n\t\t\t\terror: {\n\t\t\t\t\tcode: \"UNKNOWN_ERROR\",\n\t\t\t\t\tmessage:\n\t\t\t\t\t\te instanceof Error ? e.message : PASSKEY_ERROR_CODES.UNKNOWN_ERROR,\n\t\t\t\t\tstatus: 500,\n\t\t\t\t\tstatusText: \"INTERNAL_SERVER_ERROR\",\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t};\n\n\treturn {\n\t\tsignIn: {\n\t\t\t/**\n\t\t\t * Sign in with a registered passkey\n\t\t\t */\n\t\t\tpasskey: signInPasskey,\n\t\t},\n\t\tpasskey: {\n\t\t\t/**\n\t\t\t * Add a passkey to the user account\n\t\t\t */\n\t\t\taddPasskey: registerPasskey,\n\t\t},\n\t\t/**\n\t\t * Inferred Internal Types\n\t\t */\n\t\t$Infer: {} as {\n\t\t\tPasskey: Passkey;\n\t\t},\n\t};\n};\n\nexport const passkeyClient = () => {\n\tconst $listPasskeys = atom<any>();\n\treturn {\n\t\tid: \"passkey\",\n\t\t$InferServerPlugin: {} as ReturnType<typeof passkey>,\n\t\tgetActions: ($fetch, $store) =>\n\t\t\tgetPasskeyActions($fetch, {\n\t\t\t\t$listPasskeys,\n\t\t\t\t$store,\n\t\t\t}),\n\t\tgetAtoms($fetch) {\n\t\t\tconst listPasskeys = useAuthQuery<Passkey[]>(\n\t\t\t\t$listPasskeys,\n\t\t\t\t\"/passkey/list-user-passkeys\",\n\t\t\t\t$fetch,\n\t\t\t\t{\n\t\t\t\t\tmethod: \"GET\",\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tlistPasskeys,\n\t\t\t\t$listPasskeys,\n\t\t\t};\n\t\t},\n\t\tpathMethods: {\n\t\t\t\"/passkey/register\": \"POST\",\n\t\t\t\"/passkey/authenticate\": \"POST\",\n\t\t},\n\t\tatomListeners: [\n\t\t\t{\n\t\t\t\tmatcher(path) {\n\t\t\t\t\treturn (\n\t\t\t\t\t\tpath === \"/passkey/verify-registration\" ||\n\t\t\t\t\t\tpath === \"/passkey/delete-passkey\" ||\n\t\t\t\t\t\tpath === \"/passkey/update-passkey\" ||\n\t\t\t\t\t\tpath === \"/sign-out\"\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\tsignal: \"$listPasskeys\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tmatcher: (path) => path === \"/passkey/verify-authentication\",\n\t\t\t\tsignal: \"$sessionSignal\",\n\t\t\t},\n\t\t],\n\t\t$ERROR_CODES: PASSKEY_ERROR_CODES,\n\t} satisfies BetterAuthClientPlugin;\n};\n\nexport type * from \"@simplewebauthn/server\";\nexport * from \"./error-codes\";\nexport type * from \"./types\";\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"error-codes-DJf-1Ecu.mjs","names":[],"sources":["../src/error-codes.ts"],"sourcesContent":["import { defineErrorCodes } from \"@better-auth/core/utils/error-codes\";\n\nexport const PASSKEY_ERROR_CODES = defineErrorCodes({\n\tCHALLENGE_NOT_FOUND: \"Challenge not found\",\n\tYOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY:\n\t\t\"You are not allowed to register this passkey\",\n\tFAILED_TO_VERIFY_REGISTRATION: \"Failed to verify registration\",\n\tPASSKEY_NOT_FOUND: \"Passkey not found\",\n\tAUTHENTICATION_FAILED: \"Authentication failed\",\n\tUNABLE_TO_CREATE_SESSION: \"Unable to create session\",\n\tFAILED_TO_UPDATE_PASSKEY: \"Failed to update passkey\",\n\tPREVIOUSLY_REGISTERED: \"Previously registered\",\n\tREGISTRATION_CANCELLED: \"Registration cancelled\",\n\tAUTH_CANCELLED: \"Auth cancelled\",\n\tUNKNOWN_ERROR: \"Unknown error\",\n});\n"],"mappings":";;;AAEA,MAAa,sBAAsB,iBAAiB;CACnD,qBAAqB;CACrB,8CACC;CACD,+BAA+B;CAC/B,mBAAmB;CACnB,uBAAuB;CACvB,0BAA0B;CAC1B,0BAA0B;CAC1B,uBAAuB;CACvB,wBAAwB;CACxB,gBAAgB;CAChB,eAAe;CACf,CAAC"}
|