import { authentikFetch, clearAuthentikCache } from '../../utils/authentik'; import { requireAuth } from '../../utils/auth'; // Simplified /api/applications endpoint export default defineEventHandler(async (event) => { const method = getMethod(event); switch (method) { case 'GET': // Public endpoint for listing applications try { const response = await authentikFetch('/core/applications/'); return response; } catch (error) { console.error('❌ Failed to fetch applications:', error.message); throw error; } case 'POST': // TODO: Add authentication later - for now make it public for testing await requireAuth(event); try { const body = await readBody(event); console.log(`🔨 Creating application: ${body.name} (${body.providerType})`); // Simplified application creation - just the essentials // Create application first const applicationData = { name: body.name, slug: body.slug || body.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''), meta_description: body.meta_description || body.description, meta_publisher: body.meta_publisher || 'CorradAF RBAC', meta_launch_url: body.meta_launch_url || body.launchUrl }; let application; try { application = await authentikFetch('/core/applications/', { method: 'POST', body: applicationData }); console.log('✅ Application created successfully'); } catch (appError) { console.error('❌ Application creation failed:', appError.message); if (appError.data) { console.error('Details:', JSON.stringify(appError.data, null, 2)); } throw appError; } // Create provider based on type (simplified presets) if (body.providerType && application.pk) { try { console.log(`🔨 Creating ${body.providerType.toUpperCase()} provider...`); // Get required flows for all providers const flows = await authentikFetch('/flows/instances/'); // Find required flows const authFlows = flows.results.filter(flow => flow.designation === 'authentication'); const invalidationFlows = flows.results.filter(flow => flow.designation === 'invalidation'); const defaultAuthFlow = authFlows.find(flow => flow.slug === 'default-authentication-flow') || authFlows[0]; const defaultInvalidationFlow = invalidationFlows.find(flow => flow.slug === 'default-invalidation-flow') || invalidationFlows[0]; if (!defaultAuthFlow) { throw new Error('No authentication flow found - required for all providers'); } let provider = null; switch (body.providerType) { case 'oauth2': // OAuth2/OIDC provider preset const oauth2Data = { name: `${body.name} OAuth2`, client_type: 'confidential', authorization_flow: defaultAuthFlow.pk, invalidation_flow: defaultInvalidationFlow?.pk, redirect_uris: [ { matching_mode: 'strict', url: `${body.meta_launch_url || body.launchUrl}/auth/callback` } ] }; try { provider = await authentikFetch('/providers/oauth2/', { method: 'POST', body: oauth2Data }); console.log('✅ OAuth2 provider created'); } catch (oauth2Error) { console.error('❌ OAuth2 provider failed:', oauth2Error.message); if (oauth2Error.data) { console.error('Details:', JSON.stringify(oauth2Error.data, null, 2)); } throw oauth2Error; } break; case 'saml': // SAML provider preset const samlData = { name: `${body.name} SAML`, acs_url: `${body.meta_launch_url || body.launchUrl}/saml/acs`, audience: body.slug, issuer: `corradaf-${body.slug}`, sp_binding: 'post', authorization_flow: defaultAuthFlow.pk, invalidation_flow: defaultInvalidationFlow?.pk }; try { provider = await authentikFetch('/providers/saml/', { method: 'POST', body: samlData }); console.log('✅ SAML provider created'); } catch (samlError) { console.error('❌ SAML provider failed:', samlError.message); if (samlError.data) { console.error('Details:', JSON.stringify(samlError.data, null, 2)); } throw samlError; } break; case 'ldap': // LDAP provider preset const ldapData = { name: `${body.name} LDAP`, base_dn: 'dc=ldap,dc=goauthentik,dc=io', authorization_flow: defaultAuthFlow.pk, invalidation_flow: defaultInvalidationFlow?.pk }; try { provider = await authentikFetch('/providers/ldap/', { method: 'POST', body: ldapData }); console.log('✅ LDAP provider created'); } catch (ldapError) { console.error('❌ LDAP provider failed:', ldapError.message); if (ldapError.data) { console.error('Details:', JSON.stringify(ldapError.data, null, 2)); } throw ldapError; } break; case 'proxy': // Proxy provider preset const proxyData = { name: `${body.name} Proxy`, external_host: body.meta_launch_url || body.launchUrl, internal_host: body.meta_launch_url || body.launchUrl, authorization_flow: defaultAuthFlow.pk, invalidation_flow: defaultInvalidationFlow?.pk }; try { provider = await authentikFetch('/providers/proxy/', { method: 'POST', body: proxyData }); console.log('✅ Proxy provider created'); } catch (proxyError) { console.error('❌ Proxy provider failed:', proxyError.message); if (proxyError.data) { console.error('Details:', JSON.stringify(proxyError.data, null, 2)); } throw proxyError; } break; } // Link provider to application if (provider && provider.pk) { await authentikFetch(`/core/applications/${application.slug}/`, { method: 'PATCH', body: { provider: provider.pk } }); console.log(`✅ ${body.providerType.toUpperCase()} provider linked to application`); } else { console.warn('⚠️ Provider was not created properly'); } } catch (providerError) { console.warn('⚠️ Provider creation failed, but application was created:', providerError.message); // Don't fail the entire operation if provider creation fails } } // Clear Authentik cache to ensure changes take effect immediately try { await clearAuthentikCache(); console.log('✅ Cache cleared after application creation'); } catch (cacheError) { console.warn('⚠️ Cache clearing failed but application was created:', cacheError.message); // Continue even if cache clearing fails } return { ...application, message: 'Application created successfully' }; } catch (error) { console.error('❌ Failed to create application:', error.message); throw error; } default: throw createError({ statusCode: 405, message: 'Method not allowed' }); } });