FEAT: Enhance authentication system with internal API support, Keycloak connectivity diagnostics, and simplified client implementation

This commit is contained in:
2025-06-17 15:05:41 +02:00
parent 04ed9a094d
commit 8d378f5b53
4 changed files with 143 additions and 12 deletions

View File

@@ -0,0 +1,36 @@
export default defineEventHandler(async (event) => {
console.log('[DEBUG] Testing Keycloak connectivity...')
try {
// Test basic connectivity to Keycloak
const wellKnownUrl = 'https://auth.portnimara.dev/realms/client-portal/.well-known/openid-configuration'
const response = await $fetch(wellKnownUrl, {
retry: 0
}) as any
return {
success: true,
message: 'Keycloak connectivity successful',
endpoint: wellKnownUrl,
response: {
issuer: response.issuer,
authorization_endpoint: response.authorization_endpoint,
token_endpoint: response.token_endpoint,
userinfo_endpoint: response.userinfo_endpoint
}
}
} catch (error: any) {
console.error('[DEBUG] Keycloak connectivity test failed:', error)
return {
success: false,
message: 'Keycloak connectivity failed',
error: {
message: error.message,
status: error.status,
cause: error.cause?.message
}
}
}
})

View File

@@ -55,6 +55,14 @@ export const isAuthenticated = async (event: any): Promise<boolean> => {
}
export const requireAuth = async (event: any) => {
// First check for internal API authentication
const internalAuth = checkInternalAuth(event);
if (internalAuth) {
console.log('[requireAuth] Internal API authentication successful');
return;
}
// Then check user authentication
const authenticated = await isAuthenticated(event);
if (!authenticated) {
console.log('[requireAuth] Authentication failed for:', event.node.req.url);
@@ -66,6 +74,45 @@ export const requireAuth = async (event: any) => {
}
}
/**
* Check if the request is from an internal service/background task
*/
const checkInternalAuth = (event: any): boolean => {
const headers = event.node.req.headers;
// Check for internal service header with the system tag
const xTag = headers['x-tag'];
const xInternalSecret = headers['x-internal-secret'];
// System tag authentication (for background tasks)
if (xTag === '094ut234') {
console.log('[auth] Internal system tag authentication successful');
return true;
}
// Internal secret authentication (if set in environment)
const internalSecret = process.env.INTERNAL_API_SECRET;
if (internalSecret && xInternalSecret === internalSecret) {
console.log('[auth] Internal secret authentication successful');
return true;
}
// Check if request is from localhost (same container)
const xForwardedFor = headers['x-forwarded-for'];
const xRealIp = headers['x-real-ip'];
const remoteAddress = event.node.req.socket?.remoteAddress;
const isLocalhost = !xForwardedFor && !xRealIp &&
(remoteAddress === '127.0.0.1' || remoteAddress === '::1' || remoteAddress === '::ffff:127.0.0.1');
if (isLocalhost && xTag) {
console.log('[auth] Localhost with system tag authentication successful');
return true;
}
return false;
}
/**
* Get the authenticated user from the session
*/

View File

@@ -61,7 +61,6 @@ class KeycloakClient {
async fetch(url: string, options: any = {}, clientOptions: KeycloakClientOptions = {}): Promise<any> {
const {
timeout = 30000,
retries = 3,
retryDelay = 1000
} = clientOptions
@@ -81,17 +80,11 @@ class KeycloakClient {
try {
console.log(`[KEYCLOAK_CLIENT] Attempt ${attempt}/${retries + 1} for ${url}`)
// Use basic $fetch without problematic options
const response = await $fetch(url, {
...options,
timeout,
// Add connection reuse headers
headers: {
...options.headers,
'Connection': 'keep-alive',
'Keep-Alive': 'timeout=30, max=100'
},
// Disable automatic retries from $fetch to handle them ourselves
retry: 0
// Don't add custom headers that might be incompatible
retry: 0 // Disable automatic retries from $fetch to handle them ourselves
})
const duration = Date.now() - startTime