S3: Secure Serverless Shortlinks On AWS

July 10, 2025

Inspiration is hard to come by in many fields – but not so in software engineering. When I attended a course on AWS offerings last year, I decided to try it out myself. With a little bit of hard work, the result was a serverless URL shortener built on AWS called shortener called Liliput.

A URL shortener is not an uncommon project but I wanted to focus specifically on:

  • Security: All operations in Liliput put security as a primary concern.
  • Atomicity with DyanamoDB for unique short links: DynamoDB supports atomic counters, that is used in the link generation logic

The source code is on Github. The home screen looks like this:

Image Description

What Liliput does

Liliput is a secure, serverless shortener of URLs with the following features:

  • Logged-in users can create short links (like liliput.mourjo.me/l/G4LZ1a)
  • Logged-in users can also view their previously created links
  • Anonymous users can visit shortlinks
  • All short links are unique to a user - if the same long link is shorted multiple times, the same short URL is returned
  • Usage counts (expansion count) are tracked and displayed on the UI
  • Links can be expanded at most 25 times to prevent illegitimate usage (spam and phishing)
  • Verified users can create links that can be expanded unlimited times (verification process is through the source code)

Here is a video that demoes the application.

Focus on Security

This application is secure because of the following features:

  • To create short links, you need a valid Google account
  • Signing into Google uses the OAuth 2.0 with PKCE
  • All cookies are HTTP-only (Javascript cannot access it)
  • Links can only be expanded 25 times to prevent misuse, unless the user is verified
  • All APIs are rate limited and alerts for when rate limit is breached

System Design

The system is built using the following:

  • DynamoDB for storage
  • Amazon Cognito and Google Oauth for login flows
  • Lambda functions for logic implementation (shown below)
  • API gateway for mapping lambda functions to routes
  • Authorizer in API gateway with another Lambda function
  • Public DNS (liliput.mourjo.me) for APIs

Logged In Flows

Anonymous Flows

Learnings

  • Amazon Cognito integration with Google OAuth and managing login state in a single-page Javascript between the OAuth dance
  • The authorizer middleware in API gateway with Lambda function
  • Generating IAM policy document for giving access to only verified users
  • Startup with Java based Lambda functions was quite slow

What’s next for Liliput

  • Verification without source code change
  • Disable link expansions explicitly
  • Switching between multiple Google accounts
  • Searching for links shortened

See anything to improve? Edit this post!