Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/auth-server/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ['@repo/eslint-config/default.cjs'],
}
7 changes: 7 additions & 0 deletions apps/auth-server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Auth Server

This server is responsible for handling callbacks from Cloudflare oauth flow, and then redirecting them to a whitelisted server's callback URL e.g workers/observability/oauth/callback.

This simplifies the oauth authentication implementation for MCP servers within this monorepo, as each MCP server simply needs to be added to the whitelisted callback url list and then each server can handle the forwarded callback from auth-server.

Note: In development, the auth-server is not needed, as each server (e.g workers/observability) will simply handle the callback on the <http://localhost:8976/oauth/callback> endpoint.
28 changes: 28 additions & 0 deletions apps/auth-server/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "auth-server",
"version": "0.0.1",
"private": true,
"scripts": {
"check:lint": "run-eslint-workers",
"check:types": "run-tsc",
"deploy": "wrangler deploy",
"dev": "wrangler dev",
"start": "wrangler dev",
"cf-typegen": "wrangler types",
"test": "vitest run"
},
"dependencies": {
"@hono/zod-validator": "0.4.3",
"@repo/mcp-common": "workspace:*",
"hono": "4.7.6",
"zod": "3.24.2"
},
"devDependencies": {
"@cloudflare/vitest-pool-workers": "0.8.14",
"@cloudflare/workers-types": "4.20250410.0",
"prettier": "3.5.3",
"typescript": "5.5.4",
"vitest": "3.0.9",
"wrangler": "4.9.1"
}
}
52 changes: 52 additions & 0 deletions apps/auth-server/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { zValidator } from '@hono/zod-validator'
import { Hono } from 'hono'

import {
AuthQuery,
AuthRequestSchemaWithExtraParams,
ValidServers,
} from '@repo/mcp-common/src/cloudflare-oauth-handler'
import { McpError } from '@repo/mcp-common/src/mcp-error'

// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
export const getApp = () =>
new Hono()
/**
* OAuth Callback Endpoint
*
* This route handles the callback from Cloudflare after user authentication.
* It then proceeds to redirect the user to a valid server callback path (e.g /workers/observability/callback)
*/
.get('/oauth/callback', zValidator('query', AuthQuery), async (c) => {
try {
const { state, code, scope } = c.req.valid('query')
const oauthReqInfo = AuthRequestSchemaWithExtraParams.parse(atob(state))
if (!oauthReqInfo.clientId) {
throw new McpError('Invalid State', 400)
}
const params = new URLSearchParams({
code,
state,
scope,
})

if (!ValidServers.safeParse(oauthReqInfo.serverPath).success) {
throw new McpError(`Invalid server redirect ${oauthReqInfo.serverPath}`, 400)
}

const redirectUrl = new URL(
`${new URL(c.req.url).origin}/${oauthReqInfo.serverPath}/oauth/callback?${params.toString()}`
)
return Response.redirect(redirectUrl.toString(), 302)
} catch (e) {
console.error(e)
if (e instanceof McpError) {
return c.text(e.message, { status: e.code })
}
return c.text('Internal Error', 500)
}
})

export default {
fetch: getApp().fetch,
} satisfies ExportedHandler
3 changes: 3 additions & 0 deletions apps/auth-server/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "@repo/typescript-config/workers.json"
}
5 changes: 5 additions & 0 deletions apps/auth-server/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { TestEnv } from './vitest.config'

declare module 'cloudflare:test' {
interface ProvidedEnv extends TestEnv {}
}
Loading
Loading