Auth Middleware

You want execution authentication that rejects unauthenticated route-execution requests and passes the verified user identity to every tool call in that execution. Here's how.

The code

import { allow, defineMiddleware, reject } from "@dawn-ai/sdk"
 
export default defineMiddleware(async (req) => {
  const auth = req.headers["authorization"]
  if (!auth?.startsWith("Bearer ")) {
    return reject(401, { error: "Missing bearer token" })
  }
 
  const token = auth.slice("Bearer ".length)
  const userId = await verifyJwt(token).catch(() => null)
  if (!userId) {
    return reject(401, { error: "Invalid token" })
  }
 
  return allow({ userId })
})
 
async function verifyJwt(token: string): Promise<string> {
  // Replace with your real verifier.
  const res = await fetch("https://auth.example.com/verify", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ token }),
  })
  if (!res.ok) throw new Error("verify failed")
  const body = (await res.json()) as { readonly sub: string }
  return body.sub
}

Notes

  • Tool name equals the file basename. The tool file is tools/loadProfile.ts, so it is called as ctx.tools.loadProfile(...). A file named tools/load-profile.ts would instead be ctx.tools["load-profile"](...). Use camelCase filenames to get camelCase ctx.tools keys.
  • One global middleware. src/middleware.ts runs once per route-execution request before the route. Branch by req.routeId if you need per-route policy — there is no array of layered middlewares.
  • reject short-circuits. The route never executes; the body of reject(status, body?) is the HTTP response.
  • allow(context) flows to tools. Whatever you pass becomes ctx.middleware on every tool call for that request. It is undefined if you call allow() with no arguments.
  • Throwing equals 500. Any uncaught error becomes HTTP 500. Prefer explicit reject(401, ...) with a real body so callers see a useful response.
  • Deployment scope matters. This middleware runs under dawn dev, the Node Dawn HTTP runtime (dawn start or generated server.mjs), and Hono builds. Generated LangSmith graph entries do not include Dawn HTTP middleware, so enforce authentication at that platform boundary separately.