summaryrefslogtreecommitdiffhomepage
path: root/packages/function/src/api.ts
diff options
context:
space:
mode:
authorFrank <[email protected]>2025-07-11 05:01:27 +0800
committerFrank <[email protected]>2025-07-11 05:01:27 +0800
commit1c4fd7f28ff776953c8f3b191dc19243e6c6c8d1 (patch)
tree10f64998872a9d459f7a0deb861c129f81ceea0a /packages/function/src/api.ts
parent85805d2c38d0c2e4ddbdc749b5404f316b209c90 (diff)
downloadopencode-1c4fd7f28ff776953c8f3b191dc19243e6c6c8d1.tar.gz
opencode-1c4fd7f28ff776953c8f3b191dc19243e6c6c8d1.zip
Api: add endpoint for getting github app token
Diffstat (limited to 'packages/function/src/api.ts')
-rw-r--r--packages/function/src/api.ts40
1 files changed, 40 insertions, 0 deletions
diff --git a/packages/function/src/api.ts b/packages/function/src/api.ts
index be6ef1923..3ba3d71d1 100644
--- a/packages/function/src/api.ts
+++ b/packages/function/src/api.ts
@@ -1,5 +1,8 @@
import { DurableObject } from "cloudflare:workers"
import { randomUUID } from "node:crypto"
+import { jwtVerify, createRemoteJWKSet } from "jose"
+import { createAppAuth } from "@octokit/auth-app"
+import { Resource } from "sst"
type Env = {
SYNC_SERVER: DurableObjectNamespace<SyncServer>
@@ -218,5 +221,42 @@ export default {
},
)
}
+
+ if (request.method === "POST" && method === "exchange_github_app_token") {
+ const EXPECTED_AUDIENCE = "opencode-github-action"
+ const GITHUB_ISSUER = "https://token.actions.githubusercontent.com"
+ const JWKS_URL = `${GITHUB_ISSUER}/.well-known/jwks`
+
+ // get Authorization header
+ const authHeader = request.headers.get("Authorization")
+ const token = authHeader?.replace(/^Bearer /, "")
+ if (!token) return new Response("Error: authorization header is required", { status: 401 })
+
+ // verify token
+ const JWKS = createRemoteJWKSet(new URL(JWKS_URL))
+ try {
+ await jwtVerify(token, JWKS, {
+ issuer: GITHUB_ISSUER,
+ audience: EXPECTED_AUDIENCE,
+ })
+ } catch (err) {
+ console.error("Token verification failed:", err)
+ return new Response(JSON.stringify({ error: "Invalid or expired token" }), {
+ status: 403,
+ headers: { "Content-Type": "application/json" },
+ })
+ }
+
+ // Create app token
+ const auth = createAppAuth({
+ appId: Resource.GITHUB_APP_ID.value,
+ privateKey: Resource.GITHUB_APP_PRIVATE_KEY.value,
+ })
+ const appAuthentication = await auth({ type: "app" })
+
+ return new Response(JSON.stringify({ token: appAuthentication.token }), {
+ headers: { "Content-Type": "application/json" },
+ })
+ }
},
}