@objectstack/plugin-auth 6.3.0 → 6.5.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/index.d.mts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +70 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +70 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +6 -5
package/dist/index.d.mts
CHANGED
|
@@ -304,6 +304,16 @@ declare class AuthManager {
|
|
|
304
304
|
* Use this for server-side operations (e.g., creating users, checking sessions)
|
|
305
305
|
*/
|
|
306
306
|
getApi(): Promise<Auth<any>['api']>;
|
|
307
|
+
/**
|
|
308
|
+
* Get the underlying better-auth context for low-level operations such as
|
|
309
|
+
* `internalAdapter.createAccount` / `password.hash`.
|
|
310
|
+
*
|
|
311
|
+
* Used by routes that need to write to better-auth's tables outside the
|
|
312
|
+
* normal endpoint surface — currently only `set-initial-password`, which
|
|
313
|
+
* provisions a credential account for SSO-onboarded users so they can
|
|
314
|
+
* sign in with email/password going forward.
|
|
315
|
+
*/
|
|
316
|
+
getAuthContext(): Promise<any>;
|
|
307
317
|
getPublicConfig(): {
|
|
308
318
|
emailPassword: {
|
|
309
319
|
enabled: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -304,6 +304,16 @@ declare class AuthManager {
|
|
|
304
304
|
* Use this for server-side operations (e.g., creating users, checking sessions)
|
|
305
305
|
*/
|
|
306
306
|
getApi(): Promise<Auth<any>['api']>;
|
|
307
|
+
/**
|
|
308
|
+
* Get the underlying better-auth context for low-level operations such as
|
|
309
|
+
* `internalAdapter.createAccount` / `password.hash`.
|
|
310
|
+
*
|
|
311
|
+
* Used by routes that need to write to better-auth's tables outside the
|
|
312
|
+
* normal endpoint surface — currently only `set-initial-password`, which
|
|
313
|
+
* provisions a credential account for SSO-onboarded users so they can
|
|
314
|
+
* sign in with email/password going forward.
|
|
315
|
+
*/
|
|
316
|
+
getAuthContext(): Promise<any>;
|
|
307
317
|
getPublicConfig(): {
|
|
308
318
|
emailPassword: {
|
|
309
319
|
enabled: boolean;
|
package/dist/index.js
CHANGED
|
@@ -1145,7 +1145,8 @@ var AuthManager = class {
|
|
|
1145
1145
|
*/
|
|
1146
1146
|
async handleRequest(request) {
|
|
1147
1147
|
const auth = await this.getOrCreateAuth();
|
|
1148
|
-
const
|
|
1148
|
+
const { runWithRequestState } = await import("@better-auth/core/context");
|
|
1149
|
+
const response = await runWithRequestState(/* @__PURE__ */ new WeakMap(), () => auth.handler(request));
|
|
1149
1150
|
if (response.status >= 500) {
|
|
1150
1151
|
try {
|
|
1151
1152
|
const body = await response.clone().text();
|
|
@@ -1164,6 +1165,19 @@ var AuthManager = class {
|
|
|
1164
1165
|
const auth = await this.getOrCreateAuth();
|
|
1165
1166
|
return auth.api;
|
|
1166
1167
|
}
|
|
1168
|
+
/**
|
|
1169
|
+
* Get the underlying better-auth context for low-level operations such as
|
|
1170
|
+
* `internalAdapter.createAccount` / `password.hash`.
|
|
1171
|
+
*
|
|
1172
|
+
* Used by routes that need to write to better-auth's tables outside the
|
|
1173
|
+
* normal endpoint surface — currently only `set-initial-password`, which
|
|
1174
|
+
* provisions a credential account for SSO-onboarded users so they can
|
|
1175
|
+
* sign in with email/password going forward.
|
|
1176
|
+
*/
|
|
1177
|
+
async getAuthContext() {
|
|
1178
|
+
const auth = await this.getOrCreateAuth();
|
|
1179
|
+
return auth.$context;
|
|
1180
|
+
}
|
|
1167
1181
|
// ---------------------------------------------------------------------------
|
|
1168
1182
|
// Device Flow (CLI browser-based login)
|
|
1169
1183
|
//
|
|
@@ -1461,6 +1475,61 @@ var AuthPlugin = class {
|
|
|
1461
1475
|
return c.json({ hasOwner: true });
|
|
1462
1476
|
}
|
|
1463
1477
|
});
|
|
1478
|
+
rawApp.post(`${basePath}/set-initial-password`, async (c) => {
|
|
1479
|
+
try {
|
|
1480
|
+
let body = {};
|
|
1481
|
+
try {
|
|
1482
|
+
body = await c.req.json();
|
|
1483
|
+
} catch {
|
|
1484
|
+
body = {};
|
|
1485
|
+
}
|
|
1486
|
+
const newPassword = body?.newPassword;
|
|
1487
|
+
if (typeof newPassword !== "string" || newPassword.length === 0) {
|
|
1488
|
+
return c.json({ success: false, error: { code: "invalid_request", message: "newPassword is required" } }, 400);
|
|
1489
|
+
}
|
|
1490
|
+
const authApi = await this.authManager.getApi();
|
|
1491
|
+
const session = await authApi.getSession({ headers: c.req.raw.headers });
|
|
1492
|
+
if (!session?.user?.id) {
|
|
1493
|
+
return c.json({ success: false, error: { code: "unauthorized", message: "Sign in first" } }, 401);
|
|
1494
|
+
}
|
|
1495
|
+
const userId = session.user.id;
|
|
1496
|
+
const authCtx = await this.authManager.getAuthContext();
|
|
1497
|
+
if (!authCtx?.internalAdapter || !authCtx?.password) {
|
|
1498
|
+
return c.json({ success: false, error: { code: "unavailable", message: "Auth context unavailable" } }, 503);
|
|
1499
|
+
}
|
|
1500
|
+
const minLen = authCtx.password?.config?.minPasswordLength ?? 8;
|
|
1501
|
+
const maxLen = authCtx.password?.config?.maxPasswordLength ?? 128;
|
|
1502
|
+
if (newPassword.length < minLen) {
|
|
1503
|
+
return c.json({ success: false, error: { code: "password_too_short", message: `Password must be at least ${minLen} characters` } }, 400);
|
|
1504
|
+
}
|
|
1505
|
+
if (newPassword.length > maxLen) {
|
|
1506
|
+
return c.json({ success: false, error: { code: "password_too_long", message: `Password must be at most ${maxLen} characters` } }, 400);
|
|
1507
|
+
}
|
|
1508
|
+
const accounts = await authCtx.internalAdapter.findAccounts(userId);
|
|
1509
|
+
const existingCredential = accounts?.find?.((a) => a.providerId === "credential" && a.password);
|
|
1510
|
+
if (existingCredential) {
|
|
1511
|
+
return c.json({
|
|
1512
|
+
success: false,
|
|
1513
|
+
error: {
|
|
1514
|
+
code: "credential_account_exists",
|
|
1515
|
+
message: "A local password is already set for this account. Use change-password instead."
|
|
1516
|
+
}
|
|
1517
|
+
}, 409);
|
|
1518
|
+
}
|
|
1519
|
+
const passwordHash = await authCtx.password.hash(newPassword);
|
|
1520
|
+
await authCtx.internalAdapter.createAccount({
|
|
1521
|
+
userId,
|
|
1522
|
+
providerId: "credential",
|
|
1523
|
+
accountId: userId,
|
|
1524
|
+
password: passwordHash
|
|
1525
|
+
});
|
|
1526
|
+
return c.json({ success: true });
|
|
1527
|
+
} catch (error) {
|
|
1528
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
1529
|
+
ctx.logger.error("[AuthPlugin] set-initial-password failed", err);
|
|
1530
|
+
return c.json({ success: false, error: { code: "internal", message: err.message } }, 500);
|
|
1531
|
+
}
|
|
1532
|
+
});
|
|
1464
1533
|
rawApp.all(`${basePath}/*`, async (c) => {
|
|
1465
1534
|
try {
|
|
1466
1535
|
const response = await this.authManager.handleRequest(c.req.raw);
|