feat(auth): force Authentik login on first visit, fix ManicTime sync

Auth:
- Add middleware.ts that redirects unauthenticated users to Authentik SSO
- Extract authOptions to shared auth-options.ts
- Add getAuthSession() helper for API route protection
- Add loading spinner during session validation
- Dev mode bypasses auth (stub user still works)

ManicTime:
- Fix hardcoded companyId="beletage" — now uses group context from Tags.txt
- Fix extended project format label parsing (extracts name after year)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
AI Assistant
2026-03-09 12:26:08 +02:00
parent 7ed653eaec
commit ca4d7b5d8d
7 changed files with 152 additions and 58 deletions
+47
View File
@@ -0,0 +1,47 @@
import { getToken } from "next-auth/jwt";
import { NextRequest, NextResponse } from "next/server";
export async function middleware(request: NextRequest) {
// In development, skip auth enforcement (dev stub user handles it)
if (process.env.NODE_ENV === "development") {
return NextResponse.next();
}
const token = await getToken({
req: request,
secret: process.env.NEXTAUTH_SECRET,
});
// Authenticated — allow through
if (token) {
return NextResponse.next();
}
const { pathname } = request.nextUrl;
// API routes: return 401 JSON instead of redirect
if (pathname.startsWith("/api/")) {
return NextResponse.json(
{ error: "Authentication required" },
{ status: 401 },
);
}
// Page routes: redirect to NextAuth sign-in with callbackUrl
const signInUrl = new URL("/api/auth/signin", request.url);
signInUrl.searchParams.set("callbackUrl", request.url);
return NextResponse.redirect(signInUrl);
}
export const config = {
matcher: [
/*
* Match all paths EXCEPT:
* - /api/auth/* (NextAuth endpoints — must be public for login flow)
* - /_next/* (Next.js internals: static files, HMR, chunks)
* - /favicon.ico, /robots.txt, /sitemap.xml
* - Files with extensions (images, fonts, etc.)
*/
"/((?!api/auth|_next|favicon\\.ico|robots\\.txt|sitemap\\.xml|.*\\..*).*)",
],
};