Implementing Serverless Video on Demand Streaming with AWS: A Five-Part Series (Part 5)

Nic Lasdoce
01 Feb 20245 minutes read

This series guides the creation of a serverless Video on Demand (VoD) architecture using AWS, detailing the process from video upload to HLS conversion, ensuring secure, scalable streaming with immediate playback capabilities for a seamless user experience. This is Part 5 where we will integrate AWS Cognito for user authentication and link it with API Gateway and Lambda for token access, ensuring that only authorized users can upload and access videos.

Introduction

In the 5th and final installment of our serverless Video on Demand (VoD) system series, we're focusing on securing our endpoints. Only authorized users will have the ability to upload and fetch streaming files. We'll be integrating new AWS services like Cognito for user authentication and linking it with API Gateway and Lambda for accessing and verifying tokens at API Gateway endpoints.

The series is structured as follows:

  • Part 1 - Architecture Overview: We lay the groundwork, detailing the architecture and AWS services involved in our serverless VoD solution.

  • Part 2 - Secured File Upload: We'll cover the video upload process, how to securely upload to s3 bucket using signed url

  • Part 3 - Converting to Stream Format: This part will explain how to manage events from s3 upload to trigger conversion job to transform them into streaming format

  • Part 4 - Saving, Retrieving, and Playing: We will go through the saving and retrieval of video links, then play them using HLS Player on Chrome

  • Part 5 - Securing the Streaming: The final part will focus on securing the application to ensure that only authenticated users can access the videos.

Recap

Before we move forward, let's review our progress:

  1. Architecture Understanding: We have explored the full architecture and identified the AWS services required for our VoD system.
  2. Preparation and Upload Flow: A secure upload process was established, allowing files to be uploaded through a signed URL.
  3. Conversion Using S3 and Lambda: We've set up a system where newly uploaded files trigger a Lambda function to convert them for streaming.
  4. Save, Retrieve, and Play Stream Files: Created resources for saving and retrieving converted files and provided a quick tutorial on playing them using Chrome’s HLS Plugin.

Now let's proceed to the next step.

Process Overview

Here we will set up the following resources:

  • Cognito User Pools: For user authentication
  • API Gateway Authorizer: To secure endpoints.
  • API Gateway Callback URL: Used as a redirect URL after user authentication with Cognito.
  • Lambda Function to Granting Access Token: Handles the redirect URL from Cognito and returns the access token.

Section 1: Cognito User Pool

  1. Create cognito user pool.
  2. Follow the settings provided in these images during creation.
  3. Review and create the user pool.
  4. Create a cognito domain. We will use this later to authenticate users.
  5. Remember the API Gateway we have been using? let's copy that and add /authorize at the end(e.g. https://es8m6m6ezd.execute-api.us-east-1.amazonaws.com/dev/authorize) and it will server as our callback url
  6. Scroll down on your selected user pool to look for App client List and click the app client we just created.
  7. Click Edit beside the HostedUI.
  8. Add the callback url from step 5. Then fillout the remaining details based on the image below then save changes.
  9. Copy the client id and client secret and save it somewhere, we will use it later
  10. Go back to user pool we created and copy the cognito domain.
  11. Now let's create a user by clicking Create user.
  12. Since this is our user then let's automatically verify it by ticking the Mark email as verified and do not send invitation.

Section 2: Lambda Function for Token Exchange

  1. Go to lambda functions and click create.
  2. We named our function cognito-exchange-token, if you named it differently then take note because we will use this in next section
  3. Copy and paste the following code
import json
from urllib.parse import urlencode
import urllib3
client_id = 'client_id_from_cognito_app_created_above'
client_secret = 'client_secret_from_cognito_app_created_above'
redirect_uri = 'the /authorize endpoint of our api gateway domain' # e.g. https://es8m6m6ezd.execute-api.us-east-1.amazonaws.com/dev/authorize
url = 'your.cognito.domain.created.earlier/oauth2/token' # e.g. https://vod-app-auth.auth.us-east-1.amazoncognito.com/oauth2/token
def lambda_handler(event, context):
if code := event.get('queryStringParameters', {}).get('code', None):
http = urllib3.PoolManager()
print(code)
# Prepare the request data
data = {
'grant_type': 'authorization_code',
'client_id': client_id,
'client_secret': client_secret,
'redirect_uri': redirect_uri,
'code': code
}
encoded_data = urlencode(data).encode('utf-8')
# Headers
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
# Create and send the request
response = http.request(
'POST',
url,
body=encoded_data,
headers=headers,
)
# Decode the response
tokens = json.loads(response.data.decode('utf-8'))
return {
'statusCode': 200,
'body': json.dumps(tokens, indent=4)
}
else:
return {
'statusCode': 400,
'body': 'invalid code'
}
  1. Replace the client_id and client secret with the one we copied from the cognito app integration
  2. Replace the redirect_uri with the api gateway url we created in the step 5 above (used as call back url), in my case it is https://es8m6m6ezd.execute-api.us-east-1.amazonaws.com/dev/authorize. If you are lost then go back to your api gateway -> stages -> dev (this is the one we created in previous tutorial) -> Invoke URL. then add /authorize at the end
  3. Replace url with the cognito domain created in step 4 above then add /oauth2/token (e.g. https://vod-app-auth.auth.us-east-1.amazoncognito.com/oauth2/token)
  4. Deploy your function. NOTE, this is obviously a bad practice to store sensitive data, but we are only doing it for quick tutorial, you can store this in AWS Secrets for better protection

Section 3: Create API Gateway Callback Endpoint

  1. Create a new resource named authorize.
  2. Create a GET method to the authorize resource with lambda function integration and choose the lambda function you created above.
  3. Deploy the api to publish latest changes
  4. This endpoint will be accessible via api-gateway-endpoint/authorize (e.g. https://es8m6m6ezd.execute-api.us-east-1.amazonaws.com/dev/authorize)

Section 4: Connect the Authorizer

  1. Go to API gateway -> APIs-> Select the One we created before (mine is cloudfleet-vod-api)-> Authorizer -> Create Authorizer
  2. Create an authorizer with the following values:
    1. Name: cognito-user-auth
    2. Type: Cognito
    3. Cognito User Pool: vod-user-pool (or use whatever name you used for cognito pool creation earlier)
    4. Token Source: Authorization
  3. Go back to API Gateway -> APIs -> Your API -> Resources
  4. Go to /streams resource end click edit
  5. Update the following:
    1. Authorization: Select cognito-user-auth (this is the Authorizer we just created)
    2. Request validator: None
  6. Do the same to /upload resource
  7. Deploy the API and wait for 5 to 10 minutes to make sure everything is updated
  8. Now try to Call the /streams endpoint of our api gateway again (e.g. https://es8m6m6ezd.execute-api.us-east-1.amazonaws.com/dev/streams) and you be blocked now because you are unauthorized.
  9. To fix this, proceed to the last section to obtain tokens

Section 5: Getting authorization token

  1. Open the following url now [your-cognito-domain]/authorize?response_type=code&client_id=1ehvmahqd3jfk6m6rdu63qrrf7&redirect_uri=[endpoint-from-step-4-just-above-this]. For example: https://vod-app-auth.auth.us-east-1.amazoncognito.com/authorize?response_type=code&client_id=1ehvmahqd3jfk6m6rdu63qrrf7&redirect_uri=https://es8m6m6ezd.execute-api.us-east-1.amazonaws.com/dev/authorize
  2. The result should give you list of tokens, copy the id_token because we will need that for the authorization this time.
  3. Go to Postman -> Get Streams -> Headers
  4. Add the header with key = Authorization and value = id_token. Then run the request again, you should now have access.
  5. Do the same for the /upload endpoint and you should be able to get access again now.
  6. Note that the token expires for 1 hour so you will need to start with the signin url again (step 1 of this section) to get new token
  7. On you actual project, you will need to implement using the refresh token so you do not always need to have your users signin every hour.

Conclusion

That's it, we have finally completed this entire series on creating a secured serverless video on demand. There is one last thing that you can add here is to also make the streaming link secured through signing but that requires a lot more code modification, route redirection, and cloudfront rules; feel free to email me if you wish to learn that part as well.

Bonus

If you are a founder needing help in your Software Architecture or Cloud Infrastructure, we do free assessment and we will tell you if we can do it or not! Feel free to contact us at any of the following:
Social
Contact

Email: nic@triglon.tech

Drop a Message

Tags:
Software Development
TechStack
AWS
Python

Nic Lasdoce

Software Architect

Unmasking Challenges, Architecting Solutions, Deploying Results

Member since Mar 15, 2021

Tech Hub

Unleash Your Tech Potential: Explore Our Cutting-Edge Guides!

Stay ahead of the curve with our cutting-edge tech guides, providing expert insights and knowledge to empower your tech journey.

View All
Struggling with Database Performance? Discover These 5 Aurora Patterns for Better Operations
30 Jun 20242 minutes read
Monolith: From Zero to Millions
14 May 20244 minutes read
View All

Get The Right Job For You

Subscribe to get updated on latest and relevant career opportunities