FULL-STACK / OCTOBER 2026
LinkLocker
A URL shortener with Google sign-in, deployed on an Azure VM.
BCIT course project with a teammate who set up the infrastructure. I made 15 of the 49 commits; they made 34.
- MY ROLE
- Application and authentication developer, 2-person team
- KEY RESULT
- Sign in with Google, and live on Azure
Built with
- Node.js
- Express
- MongoDB
- JavaScript
- Azure
- Nginx
What it is
LinkLocker is a link shortener. You paste a long web address and get a short one. When someone opens the short link, they are sent to the original page.
It was a two-person course project. I built the app and the sign-in, and my teammate set up the server it runs on, so it is really online.
What it can do
Short links
Paste any web address and get a short link back.
Sign in with Google
Only signed-in people can create links, so there is no need to make a new password.
Spam protection
Each person can create only 20 links every 15 minutes.
Checks the address
It only accepts web addresses that start with http or https, and turns anything else away.
Really online
It runs on a server in Azure with a secure HTTPS address.
How a request flows
- Visitor
- Nginx
- Express
- MongoDB
How it works
- 01
You sign in with your Google account.
- 02
You paste a long web address.
- 03
The app checks it is a real web address, makes a short random code, and saves the pair.
- 04
If that code is already taken, it quietly tries a new one.
- 05
When anyone opens the short link, the app looks up the code and sends them to the original page.
Screenshots
Why
The course asked for an app that is actually deployed, so the work was as much about getting a real server and sign-in flow running as about the shortener itself.
What I built
- 01
Built the front end and the Express backend for URL shortening, backed by MongoDB (Milestone A).
- 02
Implemented Google OAuth with passport.js, the auth routes, user sessions, and login-protected link creation (Milestone B).
- 03
Registered the production OAuth callback and wrote the Milestone B write-up.
The code
// Create a new short code and store the target URL in MongoDB.
// Only signed-in users may create links.
app.post("/api/links", requireAuth, async (req, res) => {
const destination = req.body?.url;
if (typeof destination !== "string") {
return res.status(400).json({ error: "Enter a valid HTTP or HTTPS URL." });
}
let parsedDestination;
try {
parsedDestination = new URL(destination);
} catch {
return res.status(400).json({ error: "Enter a valid HTTP or HTTPS URL." });
}
if (!["http:", "https:"].includes(parsedDestination.protocol)) {
return res.status(400).json({ error: "Enter a valid HTTP or HTTPS URL." });
}
// Retry a few times if a generated short code collides with an existing one.
for (let attempt = 0; attempt < 3; attempt += 1) {
const code = crypto.randomBytes(6).toString("base64url");
try {
await Link.create({ code, url: parsedDestination.toString(), owner: req.user._id });
return res.status(201).json({ code, path: `/l/${code}` });
} catch (error) {
if (error.code !== 11000 || attempt === 2) {
return res.status(503).json({ error: "Link storage is temporarily unavailable." });
}
}
}
});Outcome
A live shortener at its own HTTPS address. Milestones A and B are complete; Milestone C was not reached.
The trade-off
Everything runs on one Azure VM: Nginx terminates HTTPS and forwards to Express on 127.0.0.1:3000, managed by PM2. It keeps the setup small and only Nginx is public, but there is no redundancy if the VM goes down.
What I learned
Sign-in works locally long before it works in production: the OAuth callback and environment variables have to match the deployed address exactly.
What I'd fix next
Finish Milestone C, which the README lists as not reached yet, and add tests around the redirect and the login-protected routes.
Working on something like LinkLocker?
Tell me what you're building and I'll reply within two business days.