Code changes for the TVM

A token vending machine (TVM) is a piece of server-side code responsible for creating short-lived, limited-scope auth tokens. These tokens are intended to be used in the front-end of an application. Since the tokens will be sent to an end user’s browsing session, there is potential for the token to be intercepted and the session could be compromised. We set the tokens to expire automatically after a short time, limiting the exposure and improving our security.

Enabling the Lambda function

Once again, we need to implement a new Lambda function. This process will be identical to how we implemented the stream handler function, and the directory “token-vending-machine” with index.js file already exists. We’re just going to need to uncomment the relevant sections in template.yaml.

Like last time, we’ll walk through the actual code and explain it on the next page. But for now, edit template.yaml and uncomment the sections as documented below.

Template updates

We need make an update to the template.yaml file to include our new function. This time though, our Lambda function is backing two API endpoints, so our structure looks a little different than it did with the stream handler.

  TokenVendingMachineFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: functions/token-vending-machine
      Policies:
        - AWSLambdaBasicExecutionRole
        - Version: 2012-10-17
          Statement:            
            - Effect: Allow
              Action:
                - secretsmanager:GetSecretValue
              Resource: !Ref MomentoSecret
      Events:
        AdminApi:
          Type: Api
          Properties:
            RestApiId: !Ref AdminApi
            Path: /tokens
            Method: GET
        OrderApi:
          Type: Api
          Properties:
            RestApiId: !Ref OrderApi
            Path: /tokens
            Method: GET

The code above should be pasted into the Resources section of the template.yaml file.

You see here there are two events listed in this resource definition. This means that if someone hits the GET /tokens endpoint in either the Admin Api or the Order Api, our function will be triggered.

Api definition updates

Our Apis are defined in Open API Specification files. The Admin Api is located at /api/admin-openapi.yaml and the Order AApi is at /api/order-openapi.yaml. We need to make the following change to both specifications - note that these lines are already present - just edit the files and uncomment as necessary.

  /tokens:
    get:
      summary: Gets a temporary, limited-scope token for use in a browser
      tags:
        - Auth
      responses:
        200:
          description: A token was generated and returned to the caller
          content:
            application/json:
              schema:
                type: object
                properties:
                  token:
                    type: string
                  exp: 
                    type: Number
        500:
          $ref: '#/components/responses/UnknownError'
      x-amazon-apigateway-request-validator: Validate All
      x-amazon-apigateway-integration:
        uri:
          Fn::Sub: arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${TokenVendingMachineFunction.Arn}/invocations
        httpMethod: POST
        type: aws_proxy

This entire code block is found inside the paths block in both files.

This definition is enabling SAM to create the necessary permissions and connections for API Gateway to our Lambda function. A cool note here - if we were defining a POST endpoint with a request body, SAM would automatically generate validation models and check schemas for us at API Gateway, freeing our function code up from doing manual validations!

Deploy

With these changes in place, it’s time to deploy our changes and verify we can get a short-lived token. Run the following commands in a terminal at the /api directory:

sam build
sam deploy

To test, we need to take the base urls from the output of our deployment and run them through a curl command via the terminal (or something like Postman, if that’s your preference). Remember the URLs from the deployment output? They looked a bit like this…

Outputs from deployment

curl '<OrderApiEndpoint>/tokens'
curl '<AdminApiEndpoint>/tokens'

If all goes to plan, you should recieve a response like this: Curl command and successful response


Now we’re good to go! Let’s take a step back for a minute and go through the function code on the next page so we know what we just built 👉