import { describe, it, expect } from "bun:test";
import app from "../app";
async function register(body: unknown) {
return app.request("/oauth/register", {
method: "POST",
headers: { "content-type": "application/json" },
body: typeof body === "string" ? body : JSON.stringify(body),
});
}
describe("POST /oauth/register — validation (RFC 7591)", () => {
it("rejects a non-JSON body", async () => {
const res = await register("{not json");
expect(res.status).toBe(400);
expect((await res.json()).error).toBe("invalid_client_metadata");
});
it("requires a non-empty redirect_uris array", async () => {
const res = await register({ client_name: "X" });
expect(res.status).toBe(400);
expect((await res.json()).error).toBe("invalid_redirect_uri");
});
it("rejects a wildcard redirect URI", async () => {
const res = await register({
redirect_uris: ["https://evil.example.com/*"],
});
expect(res.status).toBe(400);
expect((await res.json()).error).toBe("invalid_redirect_uri");
});
it("rejects a non-https remote redirect URI", async () => {
const res = await register({
redirect_uris: ["http://evil.example.com/cb"],
});
expect(res.status).toBe(400);
expect((await res.json()).error).toBe("invalid_redirect_uri");
});
it("rejects too many redirect URIs", async () => {
const res = await register({
redirect_uris: Array.from({ length: 9 }, (_, i) => `https://a${i}.example.com/cb`),
});
expect(res.status).toBe(400);
expect((await res.json()).error).toBe("invalid_redirect_uri");
});
it("rejects an unsupported token_endpoint_auth_method", async () => {
const res = await register({
redirect_uris: ["https://claude.ai/cb"],
token_endpoint_auth_method: "private_key_jwt",
});
expect(res.status).toBe(400);
expect((await res.json()).error).toBe("invalid_client_metadata");
});
it("accepts a valid public-client registration (201) or degrades to 503", async () => {
const res = await register({
client_name: "Claude (test)",
redirect_uris: ["https://claude.ai/api/mcp/callback"],
token_endpoint_auth_method: "none",
scope: "read:repo write:pr bogus:scope",
});
expect([201, 503]).toContain(res.status);
if (res.status === 201) {
const doc = await res.json();
expect(doc.client_id).toMatch(/^glc_app_/);
expect(doc.client_secret).toBeUndefined();
expect(doc.token_endpoint_auth_method).toBe("none");
expect(doc.grant_types).toContain("authorization_code");
expect(doc.client_secret_expires_at).toBe(0);
expect(doc.registration_access_token).toBeTruthy();
expect(doc.scope).toContain("read:repo");
expect(doc.scope).not.toContain("bogus:scope");
}
});
it("accepts a confidential-client registration and returns a secret (201) or 503", async () => {
const res = await register({
client_name: "Confidential (test)",
redirect_uris: ["https://app.example.com/callback"],
token_endpoint_auth_method: "client_secret_basic",
});
expect([201, 503]).toContain(res.status);
if (res.status === 201) {
const doc = await res.json();
expect(doc.client_secret).toMatch(/^glcs_/);
}
});
});
|