better-auth-studio 1.0.47-beta.2 → 1.0.47-beta.4
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/routes.d.ts.map +1 -1
- package/dist/routes.js +210 -0
- package/dist/routes.js.map +1 -1
- package/package.json +1 -1
- package/public/assets/main-DApPwhKH.js +699 -0
- package/public/assets/main-DUUS18c6.css +1 -0
- package/public/index.html +2 -2
- package/public/assets/main-B0A1h6za.css +0 -1
- package/public/assets/main-CkD7P57H.js +0 -694
package/dist/routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAOA,OAAO,EAA+B,MAAM,EAAE,MAAM,SAAS,CAAC;AAS9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA8D9C,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CA8I/E;AAwBD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../src/routes.ts"],"names":[],"mappings":"AAOA,OAAO,EAA+B,MAAM,EAAE,MAAM,SAAS,CAAC;AAS9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AA8D9C,wBAAsB,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CA8I/E;AAwBD,wBAAgB,YAAY,CAC1B,UAAU,EAAE,UAAU,EACtB,UAAU,CAAC,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAsiJR"}
|
package/dist/routes.js
CHANGED
|
@@ -1344,6 +1344,216 @@ export function createRoutes(authConfig, configPath, geoDbPath) {
|
|
|
1344
1344
|
});
|
|
1345
1345
|
}
|
|
1346
1346
|
});
|
|
1347
|
+
router.post('/api/tools/validate-config', async (_req, res) => {
|
|
1348
|
+
try {
|
|
1349
|
+
const results = [];
|
|
1350
|
+
// Helper to add validation result
|
|
1351
|
+
const addResult = (category, check, status, message, suggestion, severity = status === 'fail' ? 'error' : status === 'warning' ? 'warning' : 'info') => {
|
|
1352
|
+
results.push({ category, check, status, message, suggestion, severity });
|
|
1353
|
+
};
|
|
1354
|
+
// 1. Core Configuration Checks
|
|
1355
|
+
const secret = process.env.BETTER_AUTH_SECRET || process.env.AUTH_SECRET;
|
|
1356
|
+
if (!secret) {
|
|
1357
|
+
addResult('Core Config', 'Secret Key', 'fail', 'BETTER_AUTH_SECRET or AUTH_SECRET environment variable is not set', 'Set BETTER_AUTH_SECRET in your .env file with a strong random string (minimum 32 characters)', 'error');
|
|
1358
|
+
}
|
|
1359
|
+
else if (secret.length < 32) {
|
|
1360
|
+
addResult('Core Config', 'Secret Key', 'warning', `Secret key is only ${secret.length} characters. Recommended minimum is 32 characters`, 'Generate a longer secret key for better security', 'warning');
|
|
1361
|
+
}
|
|
1362
|
+
else {
|
|
1363
|
+
addResult('Core Config', 'Secret Key', 'pass', 'Secret key is configured and meets length requirements');
|
|
1364
|
+
}
|
|
1365
|
+
const baseURL = authConfig.baseURL || process.env.BETTER_AUTH_URL;
|
|
1366
|
+
if (!baseURL) {
|
|
1367
|
+
addResult('Core Config', 'Base URL', 'warning', 'baseURL is not configured. Using default localhost:3000', 'Set baseURL in your auth config or BETTER_AUTH_URL environment variable', 'warning');
|
|
1368
|
+
}
|
|
1369
|
+
else {
|
|
1370
|
+
try {
|
|
1371
|
+
new URL(baseURL);
|
|
1372
|
+
addResult('Core Config', 'Base URL', 'pass', `Base URL is valid: ${baseURL}`);
|
|
1373
|
+
}
|
|
1374
|
+
catch {
|
|
1375
|
+
addResult('Core Config', 'Base URL', 'fail', `Base URL format is invalid: ${baseURL}`, 'Ensure baseURL is a valid URL (e.g., https://example.com)', 'error');
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
const basePath = authConfig.basePath || '/api/auth';
|
|
1379
|
+
if (!basePath.startsWith('/')) {
|
|
1380
|
+
addResult('Core Config', 'Base Path', 'fail', `Base path must start with '/': ${basePath}`, 'Change basePath to start with a forward slash (e.g., /api/auth)', 'error');
|
|
1381
|
+
}
|
|
1382
|
+
else {
|
|
1383
|
+
addResult('Core Config', 'Base Path', 'pass', `Base path is valid: ${basePath}`);
|
|
1384
|
+
}
|
|
1385
|
+
// 2. Database Configuration
|
|
1386
|
+
const adapter = await getAuthAdapterWithConfig();
|
|
1387
|
+
if (!adapter) {
|
|
1388
|
+
addResult('Database', 'Adapter', 'fail', 'Database adapter is not available or not configured', 'Ensure your database adapter is properly configured in your auth config', 'error');
|
|
1389
|
+
}
|
|
1390
|
+
else {
|
|
1391
|
+
addResult('Database', 'Adapter', 'pass', 'Database adapter is configured');
|
|
1392
|
+
// Test database connection
|
|
1393
|
+
try {
|
|
1394
|
+
if (adapter.findMany) {
|
|
1395
|
+
await adapter.findMany({
|
|
1396
|
+
model: 'user',
|
|
1397
|
+
limit: 1,
|
|
1398
|
+
});
|
|
1399
|
+
addResult('Database', 'Connection', 'pass', 'Database connection is working');
|
|
1400
|
+
}
|
|
1401
|
+
else {
|
|
1402
|
+
addResult('Database', 'Connection', 'warning', 'Cannot test database connection (findMany method not available)', undefined, 'warning');
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
catch (error) {
|
|
1406
|
+
addResult('Database', 'Connection', 'fail', `Database connection failed: ${error instanceof Error ? error.message : 'Unknown error'}`, 'Check your database connection string and ensure the database is accessible', 'error');
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
const dbUrl = process.env.DATABASE_URL || process.env.POSTGRES_URL || process.env.MYSQL_URL;
|
|
1410
|
+
if (!dbUrl && !authConfig.database?.url) {
|
|
1411
|
+
addResult('Database', 'Connection String', 'warning', 'No database connection string found in environment variables', 'Set DATABASE_URL, POSTGRES_URL, or MYSQL_URL in your .env file', 'warning');
|
|
1412
|
+
}
|
|
1413
|
+
else {
|
|
1414
|
+
addResult('Database', 'Connection String', 'pass', 'Database connection string is configured');
|
|
1415
|
+
}
|
|
1416
|
+
// 3. OAuth/Social Providers
|
|
1417
|
+
const socialProviders = authConfig.socialProviders || [];
|
|
1418
|
+
if (socialProviders.length === 0) {
|
|
1419
|
+
addResult('OAuth Providers', 'Providers', 'warning', 'No OAuth providers configured', 'This is optional. Add social providers if you need OAuth authentication', 'info');
|
|
1420
|
+
}
|
|
1421
|
+
else {
|
|
1422
|
+
addResult('OAuth Providers', 'Providers', 'pass', `${socialProviders.length} OAuth provider(s) configured`);
|
|
1423
|
+
socialProviders.forEach((provider) => {
|
|
1424
|
+
if (provider.enabled) {
|
|
1425
|
+
if (!provider.clientId) {
|
|
1426
|
+
addResult('OAuth Providers', `${provider.name} - Client ID`, 'fail', `${provider.name} is enabled but clientId is missing`, `Add clientId for ${provider.name} in your auth config`, 'error');
|
|
1427
|
+
}
|
|
1428
|
+
else {
|
|
1429
|
+
addResult('OAuth Providers', `${provider.name} - Client ID`, 'pass', 'Client ID is configured');
|
|
1430
|
+
}
|
|
1431
|
+
if (!provider.clientSecret) {
|
|
1432
|
+
addResult('OAuth Providers', `${provider.name} - Client Secret`, 'fail', `${provider.name} is enabled but clientSecret is missing`, `Add clientSecret for ${provider.name} in your auth config`, 'error');
|
|
1433
|
+
}
|
|
1434
|
+
else {
|
|
1435
|
+
addResult('OAuth Providers', `${provider.name} - Client Secret`, 'pass', 'Client Secret is configured');
|
|
1436
|
+
}
|
|
1437
|
+
if (provider.redirectURI) {
|
|
1438
|
+
const baseUrl = authConfig.baseURL || process.env.BETTER_AUTH_URL || 'http://localhost:3000';
|
|
1439
|
+
const expectedRedirect = `${baseUrl}${authConfig.basePath || '/api/auth'}/callback/${provider.id}`;
|
|
1440
|
+
if (!provider.redirectURI.includes(baseUrl)) {
|
|
1441
|
+
addResult('OAuth Providers', `${provider.name} - Redirect URI`, 'warning', `Redirect URI may not match baseURL: ${provider.redirectURI}`, `Expected format: ${expectedRedirect}. Ensure this matches your OAuth provider settings`, 'warning');
|
|
1442
|
+
}
|
|
1443
|
+
else {
|
|
1444
|
+
addResult('OAuth Providers', `${provider.name} - Redirect URI`, 'pass', 'Redirect URI is configured');
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
else {
|
|
1448
|
+
addResult('OAuth Providers', `${provider.name} - Redirect URI`, 'warning', 'Redirect URI is not explicitly set (will use default)', undefined, 'warning');
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
});
|
|
1452
|
+
}
|
|
1453
|
+
// 4. Email & Password
|
|
1454
|
+
const emailAndPassword = authConfig.emailAndPassword;
|
|
1455
|
+
if (emailAndPassword?.enabled) {
|
|
1456
|
+
addResult('Email & Password', 'Enabled', 'pass', 'Email and password authentication is enabled');
|
|
1457
|
+
if (emailAndPassword.minPasswordLength && emailAndPassword.minPasswordLength < 8) {
|
|
1458
|
+
addResult('Email & Password', 'Password Policy', 'warning', `Minimum password length is ${emailAndPassword.minPasswordLength}. Recommended minimum is 8`, 'Consider increasing minPasswordLength to 8 or higher', 'warning');
|
|
1459
|
+
}
|
|
1460
|
+
else {
|
|
1461
|
+
addResult('Email & Password', 'Password Policy', 'pass', 'Password policy is configured');
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
else {
|
|
1465
|
+
addResult('Email & Password', 'Enabled', 'warning', 'Email and password authentication is disabled', 'Enable emailAndPassword in your config if you need email/password auth', 'info');
|
|
1466
|
+
}
|
|
1467
|
+
// 5. Security Settings
|
|
1468
|
+
const advanced = authConfig.advanced || {};
|
|
1469
|
+
const cookieAttrs = advanced.defaultCookieAttributes || {};
|
|
1470
|
+
if (process.env.NODE_ENV === 'production') {
|
|
1471
|
+
if (cookieAttrs.secure !== true) {
|
|
1472
|
+
addResult('Security', 'Cookie Security', 'fail', 'Cookie secure flag is not set to true in production', 'Set secure: true in defaultCookieAttributes for production', 'error');
|
|
1473
|
+
}
|
|
1474
|
+
else {
|
|
1475
|
+
addResult('Security', 'Cookie Security', 'pass', 'Cookie secure flag is enabled');
|
|
1476
|
+
}
|
|
1477
|
+
if (cookieAttrs.sameSite === 'none' && !cookieAttrs.secure) {
|
|
1478
|
+
addResult('Security', 'Cookie SameSite', 'fail', 'sameSite: "none" requires secure: true', 'Set secure: true when using sameSite: "none"', 'error');
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
else {
|
|
1482
|
+
if (cookieAttrs.secure === false) {
|
|
1483
|
+
addResult('Security', 'Cookie Security', 'warning', 'Cookie secure flag is false (acceptable for development)', 'Ensure secure: true in production', 'warning');
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
if (cookieAttrs.httpOnly !== false) {
|
|
1487
|
+
addResult('Security', 'Cookie HttpOnly', 'pass', 'HttpOnly flag is enabled (recommended)');
|
|
1488
|
+
}
|
|
1489
|
+
else {
|
|
1490
|
+
addResult('Security', 'Cookie HttpOnly', 'warning', 'HttpOnly flag is disabled', 'Enable httpOnly: true for better security', 'warning');
|
|
1491
|
+
}
|
|
1492
|
+
// 6. Trusted Origins
|
|
1493
|
+
const trustedOriginsRaw = authConfig.trustedOrigins || [];
|
|
1494
|
+
const trustedOrigins = Array.isArray(trustedOriginsRaw) ? trustedOriginsRaw : [];
|
|
1495
|
+
if (trustedOrigins.length === 0) {
|
|
1496
|
+
addResult('Security', 'Trusted Origins', 'warning', 'No trusted origins configured', 'Configure trustedOrigins to restrict CORS to specific domains', 'warning');
|
|
1497
|
+
}
|
|
1498
|
+
else {
|
|
1499
|
+
const invalidOrigins = trustedOrigins.filter((origin) => {
|
|
1500
|
+
try {
|
|
1501
|
+
new URL(origin);
|
|
1502
|
+
return false;
|
|
1503
|
+
}
|
|
1504
|
+
catch {
|
|
1505
|
+
return true;
|
|
1506
|
+
}
|
|
1507
|
+
});
|
|
1508
|
+
if (invalidOrigins.length > 0) {
|
|
1509
|
+
addResult('Security', 'Trusted Origins', 'fail', `Invalid trusted origin(s): ${invalidOrigins.join(', ')}`, 'Ensure all trusted origins are valid URLs', 'error');
|
|
1510
|
+
}
|
|
1511
|
+
else {
|
|
1512
|
+
addResult('Security', 'Trusted Origins', 'pass', `${trustedOrigins.length} trusted origin(s) configured`);
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
// 7. Plugins
|
|
1516
|
+
const plugins = authConfig.plugins || [];
|
|
1517
|
+
if (plugins.length === 0) {
|
|
1518
|
+
addResult('Plugins', 'Plugins', 'warning', 'No plugins configured', undefined, 'info');
|
|
1519
|
+
}
|
|
1520
|
+
else {
|
|
1521
|
+
addResult('Plugins', 'Plugins', 'pass', `${plugins.length} plugin(s) configured`);
|
|
1522
|
+
}
|
|
1523
|
+
// 8. Environment Variables
|
|
1524
|
+
const requiredEnvVars = ['BETTER_AUTH_SECRET', 'AUTH_SECRET'];
|
|
1525
|
+
const missingEnvVars = requiredEnvVars.filter((varName) => !process.env[varName]);
|
|
1526
|
+
if (missingEnvVars.length > 0) {
|
|
1527
|
+
addResult('Environment', 'Required Variables', 'fail', `Missing required environment variables: ${missingEnvVars.join(', ')}`, 'Set the required environment variables in your .env file', 'error');
|
|
1528
|
+
}
|
|
1529
|
+
else {
|
|
1530
|
+
addResult('Environment', 'Required Variables', 'pass', 'All required environment variables are set');
|
|
1531
|
+
}
|
|
1532
|
+
// Summary
|
|
1533
|
+
const errors = results.filter((r) => r.severity === 'error').length;
|
|
1534
|
+
const warnings = results.filter((r) => r.severity === 'warning').length;
|
|
1535
|
+
const passes = results.filter((r) => r.status === 'pass').length;
|
|
1536
|
+
const infos = results.filter((r) => r.severity === 'info').length;
|
|
1537
|
+
res.json({
|
|
1538
|
+
success: errors === 0,
|
|
1539
|
+
summary: {
|
|
1540
|
+
total: results.length,
|
|
1541
|
+
passes,
|
|
1542
|
+
errors,
|
|
1543
|
+
warnings,
|
|
1544
|
+
infos,
|
|
1545
|
+
},
|
|
1546
|
+
results,
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
catch (error) {
|
|
1550
|
+
res.status(500).json({
|
|
1551
|
+
success: false,
|
|
1552
|
+
error: 'Failed to validate configuration',
|
|
1553
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
1556
|
+
});
|
|
1347
1557
|
// Database Detection endpoint - Auto-detect database from installed packages
|
|
1348
1558
|
router.get('/api/database/detect', async (_req, res) => {
|
|
1349
1559
|
try {
|