Skip to content

Express.js

js
import express from "express";
import crypto from "node:crypto";
import cookieParser from "cookie-parser";

const app = express();
app.use(cookieParser(process.env.COOKIE_SECRET));

const LOGI = process.env.LOGI_API_URL;
const CLIENT_ID = process.env.LOGI_CLIENT_ID;
const CLIENT_SECRET = process.env.LOGI_CLIENT_SECRET;
const REDIRECT = process.env.LOGI_REDIRECT_URI;

function b64url(buf) {
  return Buffer.from(buf).toString("base64url");
}

app.get("/auth/login", (req, res) => {
  const verifier = b64url(crypto.randomBytes(32));
  const challenge = b64url(crypto.createHash("sha256").update(verifier).digest());
  const state = b64url(crypto.randomBytes(16));

  res.cookie("logi_pkce", verifier, { httpOnly: true, secure: true, sameSite: "lax", maxAge: 600_000 });
  res.cookie("logi_state", state, { httpOnly: true, secure: true, sameSite: "lax", maxAge: 600_000 });

  const url = new URL(`${LOGI}/oauth/authorize`);
  url.searchParams.set("client_id", CLIENT_ID);
  url.searchParams.set("redirect_uri", REDIRECT);
  url.searchParams.set("response_type", "code");
  url.searchParams.set("scope", "profile email");
  url.searchParams.set("state", state);
  url.searchParams.set("code_challenge", challenge);
  url.searchParams.set("code_challenge_method", "S256");
  res.redirect(url.toString());
});

app.get("/auth/callback", async (req, res) => {
  if (req.query.state !== req.cookies.logi_state) return res.status(400).send("state mismatch");

  const tokens = await fetch(`${LOGI}/oauth/token`, {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: new URLSearchParams({
      grant_type: "authorization_code",
      code: req.query.code,
      redirect_uri: REDIRECT,
      code_verifier: req.cookies.logi_pkce,
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
    }),
  }).then(r => r.json());

  res.cookie("logi_rt", tokens.refresh_token, { httpOnly: true, secure: true, sameSite: "strict" });
  res.clearCookie("logi_pkce");
  res.clearCookie("logi_state");
  res.redirect("/");
});

MIT License · Identity가 제품의 신뢰를 만듭니다.