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.com, 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:
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"
declare global {
const ORY_SDK_URL: string
}
const ory = new oryApi.FrontendApi(
new oryApi.Configuration({
basePath: ORY_SDK_URL,
baseOptions: { adapter: fetchAdapter },
}),
)
export default async function authenticate(request: RequestWithMiddleware) {
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…
import { Session } from "@ory/client"
import { Connection } from "@planetscale/database/dist"
import { RequestLike } from "itty-router"
export interface RequestWithMiddleware extends RequestLike {
db: Connection
session: Session
}
…and the middleware is loaded in my main handler like so:
;async () => {
const router = Router()
router.get("*", authenticate)
}
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.
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.