audit: harden better-auth config, fix types, cleanup

- Fix email verification link using Better Auth's url parameter (was hardcoded to google.com)
- Make App.Locals session/user types nullable to match reality
- Add explicit rate limiting config (60s window, 100 max)
- Add trusted origins for localhost:5173 and production domain
- Add Forgot Password? and Register links to login page
- Remove unused dead code from auth-client.ts
- Remove outdated known-bug note from AGENTS.md (register redirect is fixed)
This commit is contained in:
NeilClack
2026-07-07 08:51:24 -05:00
parent 4d4b2a1497
commit a72b65be95
5 changed files with 22 additions and 12 deletions
-1
View File
@@ -31,7 +31,6 @@ Requires `.env` with at least `DATABASE_URL`, `BETTER_AUTH_SECRET`, `BETTER_AUTH
- **`expect: { requireAssertions: true }`** — every test must assert something.
- **All route tests mock `$lib/db`** (Prisma client) and `$lib/auth-client`/`$lib/auth` via `vi.mock()`. Stub factories in `src/lib/test-utils.ts`.
- **No `.env.test`** — mocking `$lib/db` makes real DB unnecessary.
- **Known bug**: register page `throw redirect()` is caught by try/catch and returns 400 instead of redirecting (documented in test).
## Architecture notes
+2 -2
View File
@@ -3,8 +3,8 @@ import type { Session, User } from "better-auth";
declare global {
namespace App {
interface Locals {
session: Session,
user: User,
session: Session | null;
user: User | null;
}
}
}
-6
View File
@@ -1,9 +1,3 @@
import { createAuthClient } from "better-auth/svelte"
export const authClient = createAuthClient({});
const signIn = async () => {
const data = await authClient.signIn.social({
provider: "google",
});
};
+11 -2
View File
@@ -11,13 +11,13 @@ export const auth = betterAuth({
provider: 'postgresql'
}),
emailVerification: {
sendVerificationEmail: async ({ user }) => {
sendVerificationEmail: async ({ user, url }) => {
void sendMail({
to: user.email,
templateId: 'email-verification-email',
data: {
target_email_address: user.email,
verification_link: 'https://google.com'
verification_link: url
}
});
}
@@ -43,5 +43,14 @@ export const auth = betterAuth({
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string
}
},
rateLimit: {
enabled: true,
window: 60,
max: 100
},
trustedOrigins: [
'http://localhost:5173',
'https://portal.rhemawavetech.com'
],
plugins: [sveltekitCookies(getRequestEvent)]
});
+8
View File
@@ -36,6 +36,14 @@
<input type="password" placeholder="Password" bind:value={password} required class="my-2" />
<button class="mt-4 rounded bg-blue-200 px-4 py-2" type="submit">Sign In</button>
</form>
<div class="mt-2 flex flex-col items-center gap-2">
<a href="/forgot-password" class="text-sm text-blue-600 hover:text-blue-800"
>Forgot Password?</a
>
<a href="/register" class="text-sm text-blue-600 hover:text-blue-800"
>Don't have an account? Register</a
>
</div>
<div class="mt-4 flex flex-col items-center justify-center">
<span>Or</span>
<button