Guide

Using Ory with Cloudflare Workers

I’ve used some of my Christmas break to deep-dive into the many advancements the serverless & infrastructure world has made in the past year. I’ve been thoroughly enjoying my hands-on experience with Cloudflare Workers, Ory.sh, and PlanetScale, and I'm impressed by the level of innovation that is emerging from these platforms.

One issue I ran into with Cloudflare Workers was library support. As Workers is built on V8, not Node.js, some NPM modules are not supported. One of the major libraries that is not supported is Axios, with far-reaching implications: libraries that use Axios, such as @ory/client, will not run properly in Cloudflare Workers.

When trying to use one of these libraries, you will receive an error that looks like this:

TypeError: adapter is not a function at dispatchRequest (worker.js:873:16) at
Axios.request (worker.js:1229:21) at Function.wrap [as request]
(worker.js:63:21) at worker.js:1523:24 at worker.js:2895:156 at async
authenticate (worker.js:6714:20) at async Object.handle (worker.js:6401:20) {
stack: TypeError: adapter is not a function at dispat…0) at async Object.handle
(worker.js:6401:20), message: adapter is not a function }

After some wrangling, I found a solution. @haverstack/axios-fetch-adapter implements an Axios adapter that uses Fetch APIs instead of the Node-dependent default adapter of Axios. By using the baseOptions section of Ory's configuration, this adapter can be passed through to Ory API requests. This trick should also work for any other Axios-based modules that have Axios configuration options exposed within their module. Here’s how to get it working:

Firstly, in your wrangler.toml file, create your ORY_SDK_URL. This should be the URL given to you by the Ory application.

Next, create a new piece of middleware. We’re using itty-router, so our request middleware looks something like this:

// ./src/middleware/ory.ts
import fetchAdapter from "@haverstack/axios-fetch-adapter"
import * as oryApi from "@ory/client"
import { Session } from "@ory/client"
import { json } from "itty-router-extras"
import { RequestWithMiddleware } from "../types/RequestWithMiddleware"

// get our globals from the Cloudflare environment
declare global {
  const ORY_SDK_URL: string
}

// create our oryApi client
const ory = new oryApi.FrontendApi(
  new oryApi.Configuration({
    basePath: ORY_SDK_URL,
    baseOptions: { adapter: fetchAdapter },
  }),
)

export default async function authenticate(request: RequestWithMiddleware) {
  // get our cookies from the header
  const cookies = request.headers.get("Cookie")

  try {
    const resp = await ory.toSession({ cookie: cookies })
    request.session = resp.data
  } catch (e) {
    return json({ error: "Not Authorized" }, { status: 401 })
  }
}

For completeness of this example, RequestWithMiddleware is an extension of itty-router’s default Request type. My RequestWithMiddleware class looks as follows…

// ./src/types/RequestWithMiddleWare.ts
import { Session } from "@ory/client"
import { Connection } from "@planetscale/database/dist"
import { RequestLike } from "itty-router"

export interface RequestWithMiddleware extends RequestLike {
  db: Connection // the DB connection
  session: Session // the ory session, if authenticated
}

…and the middleware is loaded in my main handler like so:

// ./src/handler.ts

;async () => {
  // ... config ...

  const router = Router()
  router.get("*", authenticate)
  // ... the rest of my routes
}

Now, any Ory sessions passed through to your Worker functions via the cookies will correctly be checked for authentication.

This guest author blogpost was first published 27.12.2022 on holye.io.

info

Sign up here and try out Ory with Cloudflare workers on a free Ory Network Developer project.

Visit the Ory Changelog to keep up to date with improvements on Ory Network and the Ory Open Source ecosystem.

Never miss an article - Subscribe to our newsletter!