auth flow

This commit is contained in:
alma 2025-05-02 13:05:56 +02:00
parent ce09b18a6f
commit 1443d8d9b2
3 changed files with 97 additions and 14 deletions

View File

@ -1,7 +1,7 @@
import { notFound } from 'next/navigation'
import { getServerSession } from 'next-auth/next';
import { authOptions } from '@/app/api/auth/[...nextauth]/route';
import { ResponsiveIframe } from '@/app/components/responsive-iframe';
import ResponsiveIframe from '@/app/components/responsive-iframe';
import { redirect } from 'next/navigation';
// Use environment variables for real service URLs
@ -62,7 +62,7 @@ export default async function SectionPage(props: { params: { section: string } }
<ResponsiveIframe
src={proxyUrl}
className="w-full h-full border-none"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen={true}
/>
</div>
)

View File

@ -1,6 +1,57 @@
import NextAuth, { NextAuthOptions } from "next-auth";
import KeycloakProvider from "next-auth/providers/keycloak";
// Define Keycloak profile type
interface KeycloakProfile {
sub: string;
email?: string;
name?: string;
preferred_username?: string;
given_name?: string;
family_name?: string;
realm_access?: {
roles: string[];
};
}
// Define custom profile type
interface CustomProfile {
id: string;
name?: string | null;
email?: string | null;
username: string;
first_name: string;
last_name: string;
role: string[];
}
// Declare module augmentation for NextAuth types
declare module "next-auth" {
interface Session {
user: {
id: string;
name?: string | null;
email?: string | null;
image?: string | null;
username: string;
first_name: string;
last_name: string;
role: string[];
};
accessToken?: string;
}
interface JWT {
sub?: string;
accessToken?: string;
refreshToken?: string;
role?: string[];
username?: string;
first_name?: string;
last_name?: string;
}
}
// Simple, minimal implementation - NO REFRESH TOKEN LOGIC
export const authOptions: NextAuthOptions = {
providers: [
@ -8,37 +59,69 @@ export const authOptions: NextAuthOptions = {
clientId: process.env.KEYCLOAK_CLIENT_ID || "",
clientSecret: process.env.KEYCLOAK_CLIENT_SECRET || "",
issuer: process.env.KEYCLOAK_ISSUER || "",
profile(profile: any) {
// Extract roles from the profile
const roles = profile.realm_access?.roles || [];
return {
id: profile.sub,
name: profile.name || profile.preferred_username,
email: profile.email,
image: null,
role: roles.map((role: string) => role.replace(/^ROLE_/, '').toLowerCase()),
first_name: profile.given_name || '',
last_name: profile.family_name || '',
username: profile.preferred_username || profile.email?.split('@')[0] || '',
};
}
}),
],
session: {
strategy: "jwt",
maxAge: 8 * 60 * 60, // 8 hours only
maxAge: 8 * 60 * 60, // 8 hours
},
callbacks: {
// Simple JWT callback - no refresh logic
async jwt({ token, account }) {
if (account) {
// Initial sign-in, store tokens
async jwt({ token, account, profile }: any) {
if (account && profile) {
// Just store access token and critical fields
token.accessToken = account.access_token;
token.sub = account.providerAccountId;
// Make sure roles are available
if (profile.role) {
token.role = profile.role;
token.username = profile.username || '';
token.first_name = profile.first_name || '';
token.last_name = profile.last_name || '';
}
}
return token;
},
// Simple session callback
async session({ session, token }) {
async session({ session, token }: any) {
// Pass necessary info to the session
session.accessToken = token.accessToken;
if (session.user) {
session.user.id = token.sub || "";
// Ensure roles are passed to the session
if (token.role) {
session.user.role = token.role;
session.user.username = token.username || '';
session.user.first_name = token.first_name || '';
session.user.last_name = token.last_name || '';
} else {
// Fallback roles
session.user.role = ["user"];
session.user.username = '';
session.user.first_name = '';
session.user.last_name = '';
}
}
return session;
}
},
// Redirect to signin page for any errors
pages: {
signIn: '/signin',
error: '/signin',
},
// Set reasonable cookie options
cookies: {
sessionToken: {
name: 'next-auth.session-token',

View File

@ -1,7 +1,7 @@
import { getServerSession } from "next-auth/next";
import { authOptions } from "@/app/api/auth/[...nextauth]/route";
import { redirect } from "next/navigation";
import { ResponsiveIframe } from "@/app/components/responsive-iframe";
import ResponsiveIframe from "@/app/components/responsive-iframe";
export default async function Page() {
const session = await getServerSession(authOptions);
@ -15,12 +15,12 @@ export default async function Page() {
<div className="w-full h-full px-4 pt-12 pb-4">
<ResponsiveIframe
src={process.env.NEXT_PUBLIC_IFRAME_DRIVE_URL || ''}
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
className="relative"
style={{
marginTop: '-50px', // Adjust this value based on the Nextcloud navbar height
height: 'calc(100% + 50px)' // Compensate for the negative margin
}}
allowFullScreen={true}
/>
</div>
</main>