Olympus Docs
IntegrateBackends

Hono integration

Authenticate Hono routes against Olympus

Hono is a lightweight web framework, runs on Bun, Node, Cloudflare Workers, Deno, AWS Lambda. Great for serverless / edge deployments fronting Olympus.

Setup

bun add hono

Middleware

import { Hono } from "hono";
import { createMiddleware } from "hono/factory";

const olympusAuth = createMiddleware(async (c, next) => {
  const auth = c.req.header("authorization");
  if (!auth?.startsWith("Bearer ")) return c.json({ error: "missing_token" }, 401);
  const token = auth.slice(7);

  const res = await fetch(`${c.env.OLYMPUS_ISSUER}/admin/oauth2/introspect`, {
    method: "POST",
    headers: {
      "content-type": "application/x-www-form-urlencoded",
      authorization: "Basic " + btoa(`${c.env.HYDRA_ADMIN_USER}:${c.env.HYDRA_ADMIN_PASS}`),
    },
    body: new URLSearchParams({ token }),
  });
  const info = await res.json() as { active: boolean; sub: string; scope: string };
  if (!info.active) return c.json({ error: "inactive" }, 401);

  c.set("user", info);
  await next();
});

const app = new Hono();
app.use("/api/*", olympusAuth);

app.get("/api/widgets", (c) => {
  const user = c.get("user");
  return c.json({ user: user.sub, widgets: [] });
});

export default app;

Cloudflare Workers

Hono shines on Workers. Set Olympus env vars in wrangler.toml:

[vars]
OLYMPUS_ISSUER = "https://ciam.your-domain"
HYDRA_ADMIN_USER = "<from secret>"
HYDRA_ADMIN_PASS = "<from secret>"

Workers can validate tokens for ~free for typical traffic levels.

JWT validation on the edge

For Olympus issuing JWT access tokens, validate locally without round-tripping to Hydra:

import { jwtVerify, createRemoteJWKSet } from "jose";

const JWKS = createRemoteJWKSet(new URL(`${ISSUER}/.well-known/jwks.json`));

app.use("/api/*", async (c, next) => {
  const token = c.req.header("authorization")?.slice(7);
  if (!token) return c.json({ error: "missing" }, 401);

  try {
    const { payload } = await jwtVerify(token, JWKS, { issuer: ISSUER });
    c.set("user", payload);
    await next();
  } catch {
    return c.json({ error: "invalid" }, 401);
  }
});

On Workers with subrequest caching, JWKS fetch is amortized.

On this page