I'm currently working on implementing a custom authorizer for an API Gateway Websocket API.
Below is my custom authorizer implementation using CDK:
const authFunc = new lambda.Function(scope, utils.prefixed("WebsocketAuth"), {
runtime: lambda.Runtime.NODEJS_18_X,
handler: `auth.handler`,
code: lambda.Code.fromAsset(lambdaPath),
environment: {
API_KEY_ID: apiKey.keyId
}
});
const authorizer = new WebSocketLambdaAuthorizer(
"WebsocketAuth",
authFunc
);
const webSocketApi = new apigatewayv2.WebSocketApi(scope, 'WebSocketApi', {
connectRouteOptions: {
authorizer,
integration: new integrations.WebSocketLambdaIntegration('ConnectHandler', connectFunc),
},
disconnectRouteOptions: {
integration: new integrations.WebSocketLambdaIntegration('DisconnectHandler', disconnectFunc)
},
defaultRouteOptions: {
integration: new integrations.WebSocketLambdaIntegration('DefaultHandler', defaultFunc),
},
routeSelectionExpression: '$request.body.action',
});
Despite setting up the custom authorizer, when attempting to connect to the Websocket API, I receive a connection closure callback with error code 1006. However, upon checking the cloudwatch logs, there is no log group found for the custom authorizer lambda, indicating that it may not be invoked as intended.
This is how I establish the websocket connection:
ws = new WebSocket(`wss://${host}/${stage}?token=${authToken}`);
Prior to adding the custom authorizer, the websocket connection was successful and the API functioned correctly.
I have verified that the custom authorizer lambda can be executed using the Test
function in the console, and logs are generated accordingly.
Here is the implementation of the authorizer handler:
import { APIGatewayRequestAuthorizerEvent, APIGatewayAuthorizerResult } from 'aws-lambda';
const secret = process.env.API_SECRET ?? '';
export const handler = async (event: APIGatewayRequestAuthorizerEvent): Promise<APIGatewayAuthorizerResult> => {
console.log(`Event: ${JSON.stringify(event)}`);
const query = event.queryStringParameters ?? { token: 'NONE' };
const token = query['token'];
console.log(`Query: ${JSON.stringify(query)}`);
if (token === secret) {
console.log(`Allowed`);
return generatePolicy('user', 'Allow', event.methodArn);
} else {
console.log(`Denied`);
return generatePolicy('user', 'Deny', event.methodArn);
}
};
function generatePolicy(principalId: string, effect: string, resource: string) {
return {
principalId,
policyDocument: {
Version: '2012-10-17',
Statement: [
{
Action: 'execute-api:Invoke',
Effect: effect,
Resource: resource,
},
],
},
};
}
What could be missing in order to get this custom authorizer functioning properly?