feat(auth): implement migration script for auth secret and refactor secret handling

- Added a new script `migrate-auth-secret.ts` to facilitate the migration of 2FA secrets when changing the BETTER_AUTH_SECRET.
- Updated `package.json` to include a command for running the migration script.
- Refactored the handling of BETTER_AUTH_SECRET to improve security by removing the hardcoded default and introducing a fallback mechanism using environment variables or Docker secrets.
- Updated the authentication logic to utilize the new `betterAuthSecret` function for retrieving the secret.
This commit is contained in:
Mauricio Siu
2026-05-09 02:08:04 -06:00
parent 547ba2d04b
commit 9c71458eff
6 changed files with 131 additions and 8 deletions
-5
View File
@@ -83,11 +83,6 @@ const getDockerConfig = (): Docker => {
export const docker = getDockerConfig();
// When not set, use the legacy default so 2FA remains working for users who
// enabled it before BETTER_AUTH_SECRET was introduced.
export const BETTER_AUTH_SECRET =
process.env.BETTER_AUTH_SECRET || "better-auth-secret-123456789";
export const paths = (isServer = false) => {
const BASE_PATH =
isServer || process.env.NODE_ENV === "production"
+1 -1
View File
@@ -9,7 +9,7 @@ export const {
POSTGRES_PORT = "5432",
} = process.env;
function readSecret(path: string): string {
export function readSecret(path: string): string {
try {
return fs.readFileSync(path, "utf8").trim();
} catch {
+28
View File
@@ -0,0 +1,28 @@
import { readSecret } from "../db/constants";
const HARDCODED_LEGACY_SECRET = "better-auth-secret-123456789";
const { BETTER_AUTH_SECRET, BETTER_AUTH_SECRET_FILE } = process.env;
function resolveBetterAuthSecret(): string {
if (BETTER_AUTH_SECRET) {
return BETTER_AUTH_SECRET;
}
if (BETTER_AUTH_SECRET_FILE) {
return readSecret(BETTER_AUTH_SECRET_FILE);
}
if (process.env.NODE_ENV !== "test") {
console.warn(`
⚠️ [DEPRECATED AUTH CONFIG]
BETTER_AUTH_SECRET is not set via environment variable or Docker secret.
Falling back to the insecure hardcoded default — this is a CRITICAL SECURITY RISK.
This mode WILL BE REMOVED in a future release.
Please migrate to Docker Secrets:
curl -sSL https://dokploy.com/security/0.29.3.sh | bash
`);
}
return HARDCODED_LEGACY_SECRET;
}
export const betterAuthSecret = resolveBetterAuthSecret();
+4 -2
View File
@@ -7,7 +7,7 @@ import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { APIError } from "better-auth/api";
import { admin, organization, twoFactor } from "better-auth/plugins";
import { and, desc, eq } from "drizzle-orm";
import { BETTER_AUTH_SECRET, IS_CLOUD } from "../constants";
import { IS_CLOUD } from "../constants";
import { db } from "../db";
import * as schema from "../db/schema";
import {
@@ -27,6 +27,7 @@ import {
} from "../verification/send-verification-email";
import { getPublicIpWithFallback } from "../wss/utils";
import { ac, adminRole, memberRole, ownerRole } from "./access-control";
import { betterAuthSecret } from "./auth-secret";
const { handler, api } = betterAuth({
database: drizzleAdapter(db, {
@@ -38,8 +39,9 @@ const { handler, api } = betterAuth({
"/organization/create",
"/organization/update",
"/organization/delete",
...(!IS_CLOUD ? ["/verify-email"] : []),
],
secret: BETTER_AUTH_SECRET,
secret: betterAuthSecret,
...(!IS_CLOUD
? {
advanced: {