feat: add query-param token auth and optional HTTP auth to gateway
Support ?token= query parameter as a fallback for WebSocket clients that cannot set Authorization headers (e.g. browsers). Add authHttp option to GatewayServer so token auth can be applied to HTTP requests too, returning 401 with WWW-Authenticate header on failure.
This commit is contained in:
@@ -6,6 +6,10 @@ function mockRequest(headers: Record<string, string> = {}): IncomingMessage {
|
||||
return { headers } as unknown as IncomingMessage;
|
||||
}
|
||||
|
||||
function mockRequestWithUrl(url: string, headers: Record<string, string> = {}): IncomingMessage {
|
||||
return { url, headers } as unknown as IncomingMessage;
|
||||
}
|
||||
|
||||
describe('authenticateRequest', () => {
|
||||
describe('no auth configured', () => {
|
||||
it('allows all connections', () => {
|
||||
@@ -30,7 +34,7 @@ describe('authenticateRequest', () => {
|
||||
it('rejects missing Authorization header', () => {
|
||||
const result = authenticateRequest(mockRequest(), config);
|
||||
expect(result.authenticated).toBe(false);
|
||||
expect(result.error).toContain('Authorization header required');
|
||||
expect(result.error).toContain('Authorization required');
|
||||
});
|
||||
|
||||
it('rejects invalid token', () => {
|
||||
@@ -82,4 +86,44 @@ describe('authenticateRequest', () => {
|
||||
expect(result.identity).toBe('anonymous');
|
||||
});
|
||||
});
|
||||
|
||||
describe('query parameter token', () => {
|
||||
const config = { token: 'secret-token-123' };
|
||||
|
||||
it('accepts valid token in query parameter', () => {
|
||||
const result = authenticateRequest(
|
||||
mockRequestWithUrl('/?token=secret-token-123'),
|
||||
config,
|
||||
);
|
||||
expect(result.authenticated).toBe(true);
|
||||
expect(result.identity).toBe('token-user');
|
||||
});
|
||||
|
||||
it('rejects invalid token in query parameter', () => {
|
||||
const result = authenticateRequest(
|
||||
mockRequestWithUrl('/?token=wrong'),
|
||||
config,
|
||||
);
|
||||
expect(result.authenticated).toBe(false);
|
||||
expect(result.error).toContain('Invalid token');
|
||||
});
|
||||
|
||||
it('prefers header over query parameter', () => {
|
||||
const result = authenticateRequest(
|
||||
mockRequestWithUrl('/?token=wrong', { authorization: 'Bearer secret-token-123' }),
|
||||
config,
|
||||
);
|
||||
expect(result.authenticated).toBe(true);
|
||||
expect(result.identity).toBe('token-user');
|
||||
});
|
||||
|
||||
it('rejects when neither header nor query parameter provided', () => {
|
||||
const result = authenticateRequest(
|
||||
mockRequestWithUrl('/'),
|
||||
config,
|
||||
);
|
||||
expect(result.authenticated).toBe(false);
|
||||
expect(result.error).toContain('Authorization required');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user