UNPKG

@ouim/simple-logto

Version:

A simpler way to use @logto/react with prebuilt UI components and hooks for fast authentication setup

217 lines (216 loc) 6.08 kB
import { importJWK as x, jwtVerify as y } from "jose"; const w = /* @__PURE__ */ new Map(), I = 5 * 60 * 1e3; function i(t, e = "guest_logto_authtoken") { if (typeof (t == null ? void 0 : t.get) == "function") { const r = t.get(e); return (r == null ? void 0 : r.value) || f(); } else if (t && typeof t == "object") return t[e] || f(); return f(); } function l(t, e = "logto_authtoken") { if (typeof (t == null ? void 0 : t.get) == "function") { const r = t.get(e); return (r == null ? void 0 : r.value) || null; } else if (t && typeof t == "object") return t[e] || null; return null; } function d(t) { const e = typeof t.get == "function" ? t.get("authorization") : t.authorization; return typeof e == "string" && e.startsWith("Bearer ") ? e.slice(7) : null; } function p(t) { let e = t.replace(/-/g, "+").replace(/_/g, "/"); const r = e.length % 4; return r && (e += "=".repeat(4 - r)), typeof atob < "u" ? atob(e) : Buffer.from(e, "base64").toString(); } async function k(t) { const r = `${t.replace(/\/+$/, "")}/oidc/jwks`, o = Date.now(), n = w.get(r); if (n && n.expires > o) return n.keys; try { const s = await fetch(r); if (!s.ok) throw new Error(`Failed to fetch JWKS: ${s.status} ${s.statusText}`); const a = (await s.json()).keys || []; return w.set(r, { keys: a, expires: o + I }), a; } catch (s) { throw new Error(`Failed to fetch JWKS from ${r}: ${s instanceof Error ? s.message : "Unknown error"}`); } } function m(t, e, r) { if (!t || t.length === 0) throw new Error("No keys found in JWKS"); if (e) { const n = t.find((s) => s.kid === e); if (n) return n; throw new Error(`Key with kid "${e}" not found in JWKS`); } if (r) { const n = t.find((s) => s.alg === r); if (n) return n; } const o = t.find((n) => n.kty === "RSA" && (n.use === "sig" || !n.use)); return o || t[0]; } function E(t, e) { const { logtoUrl: r, audience: o, requiredScope: n } = e, s = new URL("oidc", r).toString(); if (t.iss !== s) throw new Error(`Invalid issuer. Expected: ${s}, Got: ${t.iss}`); if (o && t.aud !== o) throw new Error(`Invalid audience. Expected: ${o}, Got: ${t.aud}`); const u = Math.floor(Date.now() / 1e3); if (t.exp && t.exp < u) throw new Error("Token has expired"); if (t.nbf && t.nbf > u) throw new Error("Token is not yet valid"); if (n && (!t.scope || !t.scope.includes(n))) throw new Error(`Missing required scope: ${n}`); } async function h(t, e) { const { logtoUrl: r } = e; try { const [o] = t.split("."); if (!o) throw new Error("Invalid JWT format"); const n = p(o), s = JSON.parse(n), u = await k(r), a = m(u, s.kid, s.alg), g = await x(a, (s == null ? void 0 : s.alg) || "RS256"), { payload: c } = await y(t, g); return E(c, e), { userId: c.sub, isAuthenticated: !0, payload: c, isGuest: !1 }; } catch (o) { throw new Error(`Token verification failed: ${o instanceof Error ? o.message : "Unknown error"}`); } } const f = () => "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(t) { const e = Math.random() * 16 | 0; return (t === "x" ? e : e & 3 | 8).toString(16); }); function v(t) { return async (e, r, o) => { try { let n = l(e.cookies, t.cookieName); if (n || (n = d(e.headers)), !n) { if (t.allowGuest) { const u = i(e.cookies); return e.auth = { userId: null, isAuthenticated: !1, payload: null, isGuest: !0, guestId: u || void 0 }, o(); } return r.status(401).json({ error: "Authentication required", message: "No token found in cookies or Authorization header" }); } const s = await h(n, t); return e.auth = s, o(); } catch (n) { if (t.allowGuest) { const s = i(e.cookies); return e.auth = { userId: null, isAuthenticated: !1, payload: null, isGuest: !0, guestId: s || void 0 }, o(); } return r.status(401).json({ error: "Authentication failed", message: n instanceof Error ? n.message : "Unknown error" }); } }; } async function G(t, e) { try { let r = l(t.cookies, e.cookieName); return r || (r = d(t.headers)), r ? { success: !0, auth: await h(r, e) } : e.allowGuest ? { success: !1, error: "No authentication token found", auth: { userId: null, isAuthenticated: !1, payload: null, isGuest: !0, guestId: i(t.cookies) || void 0 } } : { success: !1, error: "No token found in cookies or Authorization header" }; } catch (r) { if (e.allowGuest) { const n = { userId: null, isAuthenticated: !1, payload: null, isGuest: !0, guestId: i(t.cookies) || void 0 }; return { success: !1, error: r instanceof Error ? r.message : "Unknown error", auth: n }; } return { success: !1, error: r instanceof Error ? r.message : "Unknown error" }; } } async function U(t, e) { let r; if (typeof t == "string") r = t; else { const o = l(t.cookies, e.cookieName) || d(t.headers); if (!o) { if (e.allowGuest) return { userId: null, isAuthenticated: !1, payload: null, isGuest: !0, guestId: i(t.cookies) || void 0 }; throw new Error("No token found in request"); } r = o; } try { return await h(r, e); } catch (o) { if (e.allowGuest && typeof t == "object") return { userId: null, isAuthenticated: !1, payload: null, isGuest: !0, guestId: i(t.cookies) || void 0 }; throw o; } } export { v as createExpressAuthMiddleware, U as verifyAuth, h as verifyLogtoToken, G as verifyNextAuth };