feat: auth system (middleware + login) + remove .env from git + fix hardcoded token
CRITICAL SECURITY FIXES: - src/middleware.ts: protects all routes except public ones (health, license check, seed-prod) Redirects unauthenticated users to /login, returns 401 for API routes - src/app/login/page.tsx: login page with password input - src/app/api/auth/login: HMAC-signed session cookie (7-day expiry) - src/app/api/auth/logout: clears session cookie - Top bar: Abmelden (logout) button now functional - .env removed from git tracking (secrets no longer in repo) - seed-prod: hardcoded admin token replaced with env MCP_API_TOKEN or random UUID - ADMIN_PASSWORD env var required for login (set in Dokploy env) Public routes (no auth needed): /api/health, /api/aos/seed-prod, /api/aos/licenses/check, /api/aos/licenses/validate /api/v1/* (token-auth'd), /api/mcp (token-auth'd), /login
This commit is contained in:
1 parent
e7185103f5
commit
17ceefe32a
8 files changed
+277
-100
No files matched your search
@@ -206,18 +206,20 @@ export async function POST(req: Request) {
|
||||
const existingTokens = await db.apiToken.count()
|
||||
if (existingTokens === 0) {
|
||||
const adminScopes = ['mcp:read', 'mcp:write', 'crm.company:read', 'crm.deal:read', 'finance.invoice:read', 'leads:read', 'leads:write', 'support:read', 'support:write', 'licenses.license:read', 'licenses.license:write']
|
||||
const token = 'aos_admin_seed_token_for_claude_code_2026'
|
||||
const hash = crypto.createHash('sha256').update(token).digest('hex')
|
||||
// Use MCP_API_TOKEN env var if set, otherwise generate a random one
|
||||
const tokenValue = process.env.MCP_API_TOKEN || ('aos_' + crypto.randomUUID())
|
||||
const hash = crypto.createHash('sha256').update(tokenValue).digest('hex')
|
||||
await db.apiToken.create({
|
||||
data: {
|
||||
name: 'Claude Code Admin (seeded)',
|
||||
name: 'MCP Admin Token (seeded)',
|
||||
tokenHash: hash,
|
||||
tokenPrefix: token.slice(0, 12) + '…',
|
||||
tokenPrefix: tokenValue.slice(0, 12) + '…',
|
||||
scopes: adminScopes.join(','),
|
||||
expiresAt: null,
|
||||
},
|
||||
})
|
||||
stats.apiTokens = 1
|
||||
stats.mcpToken = tokenValue === process.env.MCP_API_TOKEN ? '(from env)' : tokenValue
|
||||
} else {
|
||||
stats.apiTokens = 0
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user