Webux Lab

By Studio Webux

Cognito authentication for a CLI Tool

TG
Tommy Gingras Studio Webux 2025-01-19

Experimenting with Cognito to build a CLI tool

Here is the code to implement a secure frontend first (and only) authentication flow with Cognito User Pool

// https://docs.aws.amazon.com/cognito/latest/developerguide/logout-endpoint.html
// https://docs.aws.amazon.com/cognito/latest/developerguide/login-endpoint.html

import { type Context, Hono } from "hono";
import { logger } from "hono/logger";
import { ContentfulStatusCode } from "hono/utils/http-status";
import open from "npm:open";

const app = new Hono();

app.use(logger());

let user!: {
  token_type: "bearer";
  expires_in: number;
  refresh_token: string;
  access_token: string;
  id_token: string;
};

const domain =
  "https://<YOUR-COGNITO-USER-POOL-ID>.auth.ca-central-1.amazoncognito.com";

const cognitoAuthConfig = {
  client_id: "<YOUR-CLIENT-ID>",
  redirect_uri: "http://localhost:13567/redirect_uri",
  response_type: "code",
  scope: "email+openid+phone", // add what you need for your application
};

const loginUrl = `${domain}/login?client_id=${cognitoAuthConfig.client_id}&redirect_uri=${encodeURIComponent(cognitoAuthConfig.redirect_uri)}&response_type=${cognitoAuthConfig.response_type}&scope=${cognitoAuthConfig.scope}`;

console.log("Login URL", loginUrl);
open(loginUrl);

app.get("/redirect_uri", async (c: Context) => {
  console.log("received", c.req.url);
  const { code } = c.req.query();

  const tokens = await fetch(
    `${domain}/oauth2/token?grant_type=authorization_code&client_id=${cognitoAuthConfig.client_id}&redirect_uri=${encodeURIComponent(cognitoAuthConfig.redirect_uri)}&code=${code}&scope=${cognitoAuthConfig.scope}`,
    {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
    },
  );

  if (tokens.ok) {
    console.log(await tokens.json());
    user = await tokens.json();
    return c.text("Ok");
  }

  return c.text("Not Ok", (tokens.status as ContentfulStatusCode) || 500);
});

app.onError((err: Error, c: Context) => {
  console.error("GLOBAL ERROR HANDLING", err);
  return c.text("not ok", 500);
});

Deno.serve({ port: 13567, hostname: "0.0.0.0" }, app.fetch);

Search