diff --git a/src/server/push_notification/default_push_notification_sender.ts b/src/server/push_notification/default_push_notification_sender.ts index d3dd50cf..3782f78f 100644 --- a/src/server/push_notification/default_push_notification_sender.ts +++ b/src/server/push_notification/default_push_notification_sender.ts @@ -82,6 +82,15 @@ export class DefaultPushNotificationSender implements PushNotificationSender { headers[this.options.tokenHeaderName] = pushConfig.token; } + if (pushConfig.authentication && pushConfig.authentication.credentials) { + const { schemes, credentials } = pushConfig.authentication; + if (schemes.includes('Bearer')) { + headers['Authorization'] = `Bearer ${credentials}`; + } else if (schemes.includes('Basic')) { + headers['Authorization'] = `Basic ${credentials}`; + } + } + const response = await fetch(url, { method: 'POST', headers, diff --git a/test/server/push_notification_integration.spec.ts b/test/server/push_notification_integration.spec.ts index 08ce1ec6..210fa3ac 100644 --- a/test/server/push_notification_integration.spec.ts +++ b/test/server/push_notification_integration.spec.ts @@ -700,5 +700,150 @@ describe('Push Notification Integration Tests', () => { ); }); }); + it('should send correct Authorization header when authentication config is provided', async () => { + const pushConfig: PushNotificationConfig = { + id: 'auth-test-config', + url: `${testServerUrl}/notify`, + authentication: { + schemes: ['Bearer', 'Basic'], + credentials: 'test-credentials', + }, + }; + + const params: MessageSendParams = { + message: createTestMessage('Test with authentication'), + configuration: { + pushNotificationConfig: pushConfig, + }, + }; + + // Mock the agent executor to publish completion + mockAgentExecutor.execute.callsFake(async (ctx, bus) => { + const taskId = ctx.taskId; + const contextId = ctx.contextId; + + bus.publish({ + id: taskId, + contextId, + status: { state: 'working' }, + kind: 'task', + }); + + bus.publish({ + taskId, + contextId, + kind: 'status-update', + status: { state: 'completed' }, + final: true, + }); + + bus.finished(); + }); + + await handler.sendMessage(params); + + // Wait for async push notifications to be sent + await new Promise((resolve) => setTimeout(resolve, 200)); + + // Verify notification received + assert.lengthOf( + receivedNotifications, + 2, + 'Should send notifications for working and completed states' + ); + + // Check the last notification (completed) + const notification = receivedNotifications[1]; + + // Verify Authorization header + // Bearer should be prioritized over Basic + assert.equal( + notification.headers['authorization'], + 'Bearer test-credentials', + 'Should prioritize Bearer scheme' + ); + }); + + it('should send Bearer Authorization header', async () => { + const pushConfig: PushNotificationConfig = { + id: 'bearer-auth-test', + url: `${testServerUrl}/notify`, + authentication: { + schemes: ['Bearer'], + credentials: 'bearer-token', + }, + }; + + const params: MessageSendParams = { + message: createTestMessage('Test with Bearer auth'), + configuration: { + pushNotificationConfig: pushConfig, + }, + }; + + mockAgentExecutor.execute.callsFake(async (ctx, bus) => { + bus.publish({ + id: ctx.taskId, + contextId: ctx.contextId, + status: { state: 'working' }, + kind: 'task', + }); + bus.publish({ + taskId: ctx.taskId, + contextId: ctx.contextId, + kind: 'status-update', + status: { state: 'completed' }, + final: true, + }); + bus.finished(); + }); + + await handler.sendMessage(params); + await new Promise((resolve) => setTimeout(resolve, 200)); + + assert.lengthOf(receivedNotifications, 2); + assert.equal(receivedNotifications[1].headers['authorization'], 'Bearer bearer-token'); + }); + + it('should send Basic Authorization header', async () => { + const pushConfig: PushNotificationConfig = { + id: 'basic-auth-test', + url: `${testServerUrl}/notify`, + authentication: { + schemes: ['Basic'], + credentials: 'basic-creds', + }, + }; + + const params: MessageSendParams = { + message: createTestMessage('Test with Basic auth'), + configuration: { + pushNotificationConfig: pushConfig, + }, + }; + + mockAgentExecutor.execute.callsFake(async (ctx, bus) => { + bus.publish({ + id: ctx.taskId, + contextId: ctx.contextId, + status: { state: 'working' }, + kind: 'task', + }); + bus.publish({ + taskId: ctx.taskId, + contextId: ctx.contextId, + kind: 'status-update', + status: { state: 'completed' }, + final: true, + }); + bus.finished(); + }); + + await handler.sendMessage(params); + await new Promise((resolve) => setTimeout(resolve, 200)); + + assert.lengthOf(receivedNotifications, 2); + assert.equal(receivedNotifications[1].headers['authorization'], 'Basic basic-creds'); + }); }); });