Fix security issues in Better Auth migration

- Tighten login rate limit from 200/10s to 5/60s to prevent brute-force
- Encrypt OAuth tokens (access/refresh/id) in accounts table via databaseHooks
- Sync password changes to accounts.password so old passwords stop working
- Redact OAuth client secrets in server actions before returning to client
- Add trustHost config (default false) to prevent Host header poisoning
- Add audit logging for successful logins via session create hook
- Add audit logging to OAuth provider update/delete server actions
- Fix provider ID collision by appending name hash suffix to slug
- Fix nullable provider field causing incorrect hasOAuth detection
- Refuse to store plaintext secrets if encryption module fails to load

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
fuomag9
2026-04-12 21:50:48 +02:00
parent 3a16d6e9b1
commit 66f8e32df5
5 changed files with 100 additions and 14 deletions
+8 -4
View File
@@ -209,13 +209,17 @@ function runEnvProviderSync() {
let encryptSecret: (v: string) => string;
try {
encryptSecret = require("./secret").encryptSecret;
} catch {
encryptSecret = (v) => v;
} catch (e) {
console.error("CRITICAL: Failed to load encryption module, refusing to store plaintext secrets:", e);
return;
}
const name = config.oauth.providerName;
// Use a slug-based ID so the OAuth callback URL is predictable
const providerId = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "oauth";
// Use a slug-based ID so the OAuth callback URL is predictable, with hash suffix to avoid collisions
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "oauth";
// Append a short hash of the exact name to avoid collisions (e.g. "Google!" vs "Google?")
const nameHash = Buffer.from(name).toString("base64url").slice(0, 6);
const providerId = `${slug}-${nameHash}`;
const existing = db.select().from(oauthProviders).where(eq(oauthProviders.name, name)).get();
const now = new Date().toISOString();