ca4d7b5d8d
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>
48 lines
1.5 KiB
TypeScript
48 lines
1.5 KiB
TypeScript
import type { NextAuthOptions } from "next-auth";
|
|
import AuthentikProvider from "next-auth/providers/authentik";
|
|
|
|
export const authOptions: NextAuthOptions = {
|
|
providers: [
|
|
AuthentikProvider({
|
|
clientId: process.env.AUTHENTIK_CLIENT_ID || "",
|
|
clientSecret: process.env.AUTHENTIK_CLIENT_SECRET || "",
|
|
issuer: process.env.AUTHENTIK_ISSUER || "",
|
|
}),
|
|
],
|
|
callbacks: {
|
|
async jwt({ token, user, profile }) {
|
|
if (user) {
|
|
token.id = user.id;
|
|
}
|
|
if (profile) {
|
|
// Map Authentik groups/roles to our internal roles
|
|
const groups = (profile as any).groups || [];
|
|
let role = "user";
|
|
if (groups.includes("architools-admin")) role = "admin";
|
|
else if (groups.includes("architools-manager")) role = "manager";
|
|
|
|
token.role = role;
|
|
|
|
// Map company based on groups
|
|
let company = "group";
|
|
if (groups.includes("company-beletage")) company = "beletage";
|
|
else if (groups.includes("company-urban-switch"))
|
|
company = "urban-switch";
|
|
else if (groups.includes("company-studii-de-teren"))
|
|
company = "studii-de-teren";
|
|
|
|
token.company = company;
|
|
}
|
|
return token;
|
|
},
|
|
async session({ session, token }) {
|
|
if (session.user) {
|
|
(session.user as any).id = token.id;
|
|
(session.user as any).role = token.role || "user";
|
|
(session.user as any).company = token.company || "group";
|
|
}
|
|
return session;
|
|
},
|
|
},
|
|
};
|