|
1 | | -import OAuthProvider, { |
2 | | - type AuthRequest, |
3 | | - type OAuthHelpers, |
4 | | -} from "@cloudflare/workers-oauth-provider"; |
| 1 | +import OAuthProvider from "@cloudflare/workers-oauth-provider"; |
5 | 2 | import { DurableMCP } from "workers-mcp"; |
6 | 3 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; |
7 | 4 | import { z } from "zod"; |
8 | | -import { Hono } from "hono"; |
9 | 5 | import { Octokit } from "octokit"; |
10 | | -import { fetchUpstreamAuthToken, getUpstreamAuthorizeUrl } from "./utils"; |
| 6 | +import { GitHubHandler } from "./github-handler"; |
11 | 7 |
|
12 | 8 | // Context from the auth process, encrypted & stored in the auth token |
13 | 9 | // and provided to the DurableMCP as this.props |
@@ -92,87 +88,10 @@ export class MyMCP extends DurableMCP<Props, Env> { |
92 | 88 | } |
93 | 89 | } |
94 | 90 |
|
95 | | -const app = new Hono<{ Bindings: Env & { OAUTH_PROVIDER: OAuthHelpers } }>(); |
96 | | - |
97 | | -/** |
98 | | - * OAuth Authorization Endpoint |
99 | | - * |
100 | | - * This route initiates the GitHub OAuth flow when a user wants to log in. |
101 | | - * It creates a random state parameter to prevent CSRF attacks and stores the |
102 | | - * original OAuth request information in KV storage for later retrieval. |
103 | | - * Then it redirects the user to GitHub's authorization page with the appropriate |
104 | | - * parameters so the user can authenticate and grant permissions. |
105 | | - */ |
106 | | -app.get("/authorize", async (c) => { |
107 | | - const oauthReqInfo = await c.env.OAUTH_PROVIDER.parseAuthRequest(c.req.raw); |
108 | | - if (!oauthReqInfo.clientId) { |
109 | | - return c.text("Invalid request", 400); |
110 | | - } |
111 | | - |
112 | | - return Response.redirect( |
113 | | - getUpstreamAuthorizeUrl({ |
114 | | - upstream_url: "https://github.com/login/oauth/authorize", |
115 | | - scope: "read:user", |
116 | | - client_id: c.env.GITHUB_CLIENT_ID, |
117 | | - redirect_uri: new URL("/callback", c.req.url).href, |
118 | | - state: btoa(JSON.stringify(oauthReqInfo)), |
119 | | - }), |
120 | | - ); |
121 | | -}); |
122 | | - |
123 | | -/** |
124 | | - * OAuth Callback Endpoint |
125 | | - * |
126 | | - * This route handles the callback from GitHub after user authentication. |
127 | | - * It exchanges the temporary code for an access token, then stores some |
128 | | - * user metadata & the auth token as part of the 'props' on the token passed |
129 | | - * down to the client. It ends by redirecting the client back to _its_ callback URL |
130 | | - */ |
131 | | -app.get("/callback", async (c) => { |
132 | | - // Get the oathReqInfo out of KV |
133 | | - const oauthReqInfo = JSON.parse(atob(c.req.query("state") as string)) as AuthRequest; |
134 | | - if (!oauthReqInfo.clientId) { |
135 | | - return c.text("Invalid state", 400); |
136 | | - } |
137 | | - |
138 | | - // Exchange the code for an access token |
139 | | - const [accessToken, errResponse] = await fetchUpstreamAuthToken({ |
140 | | - upstream_url: "https://github.com/login/oauth/access_token", |
141 | | - client_id: c.env.GITHUB_CLIENT_ID, |
142 | | - client_secret: c.env.GITHUB_CLIENT_SECRET, |
143 | | - code: c.req.query("code"), |
144 | | - redirect_uri: new URL("/callback", c.req.url).href, |
145 | | - }); |
146 | | - if (errResponse) return errResponse; |
147 | | - |
148 | | - // Fetch the user info from GitHub |
149 | | - const user = await new Octokit({ auth: accessToken }).rest.users.getAuthenticated(); |
150 | | - const { login, name, email } = user.data; |
151 | | - |
152 | | - // Return back to the MCP client a new token |
153 | | - const { redirectTo } = await c.env.OAUTH_PROVIDER.completeAuthorization({ |
154 | | - request: oauthReqInfo, |
155 | | - userId: login, |
156 | | - metadata: { |
157 | | - label: name, |
158 | | - }, |
159 | | - scope: oauthReqInfo.scope, |
160 | | - // This will be available on this.props inside MyMCP |
161 | | - props: { |
162 | | - login, |
163 | | - name, |
164 | | - email, |
165 | | - accessToken, |
166 | | - } as Props, |
167 | | - }); |
168 | | - |
169 | | - return Response.redirect(redirectTo); |
170 | | -}); |
171 | | - |
172 | 91 | export default new OAuthProvider({ |
173 | 92 | apiRoute: "/sse", |
174 | 93 | apiHandler: MyMCP.mount("/sse"), |
175 | | - defaultHandler: app, |
| 94 | + defaultHandler: GitHubHandler, |
176 | 95 | authorizeEndpoint: "/authorize", |
177 | 96 | tokenEndpoint: "/token", |
178 | 97 | clientRegistrationEndpoint: "/register", |
|
0 commit comments