Pusher private-channel authentication using AWS Lambda w/ Gateway API

Intro

Pusher private-channels require authentication [i].

Lambda functions [ii] are a good candidate for doing the computation that determines whether a user is authenticated for a private channel, or not.

An API Gateway resource [iii] is necessary to receive the Pusher client’s request & send it to the Lambda function, then send the Lambda function’s response back

The Request

  • The request is generated by Pusher’s client-side library [iv]
  • I’m using JSONP because I don’t want the constraint of requiring my client and server to be on the same domain
  • The Pusher client does not support POST across domains, regardless of CORS settings
  • In order to have access to the parameters in this JSONP request, sent by the Pusher client, you need to configure the API Gateway endpoint to parse the requesat and send it to the Lambda function (getting the Gateway endpoint & Lambda function integrated is out of the scope of this document - reach out if you need help)
  • You accomplish the above with a “mapping template” for the “Integration Request” of the Gateway endpoint/resource. Mine is [v], and I have “When there are no templates defined (recommended)” selected.

The Response

  • I compute the request with this Lambda Node.js function [vi]
  • The response must be a content-type of application/javascript in order for the Pusher client to receive it properly. This is achieved by:
    • creating a “Content-Type” for the “200” (successful) “Response Header” of the “Method Response” for the API Gateway resource
    • creating a “Header Mapping” of “Content-Type” -> ‘application/javascript’ in the “Integration Response” of the Gateway resource
  • The pusher docs [iv] provide an example of how to generate the request body using various languages & frameworks
  • The data returned from Lambda is a string like: Pusher.auth_callbacks['1']({"auth": )
  • This string response will be escaped by Gateway API, which will stop the Pusher client from receiving it correctly
  • To fix the above, you add a “Body Mapping Template” for the “Integration Response” of the Gateway resource method. I used Content-Type of “application/javascript” and a template of $input.path('$')

Deployment stages

  • I want to support 2 environments: staging & production
  • API Gateway supports “Stage Variables” that can be set for different “stages” (e.g. staging, production) [vii]
  • I pass the stage variables to Lambda, after setting them in the Gateway API UI, with the $stageVariables portion of the Integration Request mapping I’ve provided [v]
  • In the Lambda function, I can now get the stage variables with event.stageVariables

Sources