@checkstack/auth-backend 0.4.21 → 0.4.23

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/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # @checkstack/auth-backend
2
2
 
3
+ ## 0.4.23
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [302cd3f]
8
+ - @checkstack/backend-api@0.14.1
9
+ - @checkstack/command-backend@0.1.23
10
+ - @checkstack/auth-common@0.6.4
11
+ - @checkstack/common@0.7.0
12
+ - @checkstack/notification-common@1.0.0
13
+
14
+ ## 0.4.22
15
+
16
+ ### Patch Changes
17
+
18
+ - 32d52c6: Fix and improve password reset flow + email branding:
19
+
20
+ - **Fix**: password reset emails were failing with "Malformed password reset URL: missing token parameter". Better-auth puts the reset token in the URL path (`/reset-password/{token}`), not as a `?token=` query param, so the previous URL-parsing logic always failed. Now uses the `token` argument better-auth passes to `sendResetPassword` directly.
21
+ - **UX**: the reset password page now validates the token on load via a new anonymous `validateResetToken` endpoint, so users see "Invalid Link" / "Link Expired" before typing a password rather than after submitting. Tokens are 24-char nanoid-style values (~143 bits of entropy), so exposing validity does not enable enumeration.
22
+ - **Fix**: transactional notifications were hardcoded to `importance: "critical"`, causing password reset emails to display a misleading "CRITICAL" badge. The `sendTransactional` contract now accepts an optional `importance` field that defaults to `"info"`.
23
+ - **Branding**: redesigned the email layout (`wrapInEmailLayout`) with a Checkstack-style engineering aesthetic — dark header with grid pattern, monospace importance badge, hardened CTA button (Outlook VML fallback + explicit text color), and force-light color scheme to prevent client auto-inversion from breaking text legibility.
24
+
25
+ - Updated dependencies [32d52c6]
26
+ - Updated dependencies [32d52c6]
27
+ - Updated dependencies [32d52c6]
28
+ - Updated dependencies [32d52c6]
29
+ - Updated dependencies [32d52c6]
30
+ - @checkstack/notification-common@1.0.0
31
+ - @checkstack/backend-api@0.14.0
32
+ - @checkstack/auth-common@0.6.4
33
+ - @checkstack/command-backend@0.1.22
34
+
3
35
  ## 0.4.21
4
36
 
5
37
  ### Patch Changes
package/package.json CHANGED
@@ -1,23 +1,23 @@
1
1
  {
2
2
  "name": "@checkstack/auth-backend",
3
- "version": "0.4.21",
3
+ "version": "0.4.23",
4
4
  "type": "module",
5
5
  "main": "src/index.ts",
6
6
  "checkstack": {
7
7
  "type": "backend"
8
8
  },
9
9
  "scripts": {
10
- "typecheck": "tsc --noEmit",
10
+ "typecheck": "tsgo -b",
11
11
  "generate": "drizzle-kit generate",
12
12
  "lint": "bun run lint:code",
13
13
  "lint:code": "eslint . --max-warnings 0",
14
14
  "test": "bun test"
15
15
  },
16
16
  "dependencies": {
17
- "@checkstack/auth-common": "0.6.3",
18
- "@checkstack/backend-api": "0.13.0",
19
- "@checkstack/notification-common": "0.2.9",
20
- "@checkstack/command-backend": "0.1.20",
17
+ "@checkstack/auth-common": "0.6.4",
18
+ "@checkstack/backend-api": "0.14.0",
19
+ "@checkstack/notification-common": "1.0.0",
20
+ "@checkstack/command-backend": "0.1.22",
21
21
  "better-auth": "^1.4.7",
22
22
  "drizzle-orm": "^0.45.0",
23
23
  "hono": "^4.12.14",
@@ -31,6 +31,7 @@
31
31
  "@checkstack/scripts": "0.1.2",
32
32
  "@checkstack/tsconfig": "0.0.5",
33
33
  "@types/node": "^20.0.0",
34
+ "drizzle-kit": "^0.31.10",
34
35
  "typescript": "^5.0.0"
35
36
  }
36
37
  }
package/src/index.ts CHANGED
@@ -651,22 +651,12 @@ export default createBackendPlugin({
651
651
  disableSignUp: !registrationAllowed,
652
652
  minPasswordLength: 8,
653
653
  maxPasswordLength: 128,
654
- sendResetPassword: async ({ user, url }) => {
654
+ sendResetPassword: async ({ user, token }) => {
655
655
  // Send password reset notification via all enabled strategies
656
656
  // Using void to prevent timing attacks revealing email existence
657
657
  const notificationClient = rpcClient.forPlugin(NotificationApi);
658
- const frontendUrl = baseUrl;
659
- // SECURITY: Use URL parsing instead of brittle string splitting
660
- const parsedUrl = new URL(url);
661
- const resetToken = parsedUrl.searchParams.get("token");
662
- if (!resetToken) {
663
- throw new APIError("BAD_REQUEST", {
664
- message:
665
- "Malformed password reset URL: missing token parameter",
666
- });
667
- }
668
- const resetUrl = `${frontendUrl}/auth/reset-password?token=${encodeURIComponent(
669
- resetToken,
658
+ const resetUrl = `${baseUrl}/auth/reset-password?token=${encodeURIComponent(
659
+ token,
670
660
  )}`;
671
661
 
672
662
  void notificationClient.sendTransactional({
package/src/router.ts CHANGED
@@ -665,6 +665,26 @@ export const createAuthRouter = (
665
665
  // ONBOARDING ENDPOINTS
666
666
  // ==========================================================================
667
667
 
668
+ const validateResetToken = os.validateResetToken.handler(
669
+ async ({ input }) => {
670
+ const [record] = await internalDb
671
+ .select({ expiresAt: schema.verification.expiresAt })
672
+ .from(schema.verification)
673
+ .where(
674
+ eq(schema.verification.identifier, `reset-password:${input.token}`),
675
+ )
676
+ .limit(1);
677
+
678
+ if (!record) {
679
+ return { valid: false, reason: "invalid" as const };
680
+ }
681
+ if (record.expiresAt.getTime() <= Date.now()) {
682
+ return { valid: false, reason: "expired" as const };
683
+ }
684
+ return { valid: true };
685
+ },
686
+ );
687
+
668
688
  const getOnboardingStatus = os.getOnboardingStatus.handler(async () => {
669
689
  // Check if any users exist in the database
670
690
  const users = await internalDb
@@ -1942,6 +1962,7 @@ export const createAuthRouter = (
1942
1962
  setRegistrationStatus,
1943
1963
  getOnboardingStatus,
1944
1964
  completeOnboarding,
1965
+ validateResetToken,
1945
1966
  getCurrentUserProfile,
1946
1967
  updateCurrentUser,
1947
1968
  getAnonymousAccessRules,
package/tsconfig.json CHANGED
@@ -2,5 +2,25 @@
2
2
  "extends": "@checkstack/tsconfig/backend.json",
3
3
  "include": [
4
4
  "src"
5
+ ],
6
+ "references": [
7
+ {
8
+ "path": "../auth-common"
9
+ },
10
+ {
11
+ "path": "../backend-api"
12
+ },
13
+ {
14
+ "path": "../command-backend"
15
+ },
16
+ {
17
+ "path": "../common"
18
+ },
19
+ {
20
+ "path": "../drizzle-helper"
21
+ },
22
+ {
23
+ "path": "../notification-common"
24
+ }
5
25
  ]
6
- }
26
+ }