|
1 | 1 | import { beforeEach, describe, expect, it } from "vitest"; |
2 | 2 | import { Hono } from "hono"; |
| 3 | +import { decodeJwt } from "jose"; |
3 | 4 | import { |
4 | 5 | Store, |
5 | 6 | WebhookDispatcher, |
@@ -30,7 +31,11 @@ function createTestApp() { |
30 | 31 | googlePlugin.register(app as any, store, webhooks, base, tokenMap); |
31 | 32 | googlePlugin.seed?.(store, base); |
32 | 33 | seedFromConfig(store, base, { |
33 | | - users: [{ email: "testuser@example.com", name: "Test User" }], |
| 34 | + users: [ |
| 35 | + { email: "testuser@example.com", name: "Test User" }, |
| 36 | + { email: "consumer@gmail.com", name: "Consumer User" }, |
| 37 | + { email: "workspaceuser@example.com", name: "Workspace User", hd: "override.io" }, |
| 38 | + ], |
34 | 39 | oauth_clients: [ |
35 | 40 | { |
36 | 41 | client_id: "emu_google_client_id", |
@@ -892,6 +897,42 @@ describe("Google plugin integration", () => { |
892 | 897 | expect(refreshBody.scope).toBe(tokenBody.scope); |
893 | 898 | }); |
894 | 899 |
|
| 900 | + it("derives, overrides, and omits the hd claim based on user config", async () => { |
| 901 | + async function getIdTokenClaims(email: string) { |
| 902 | + const authorize = await formRequest(app, "/o/oauth2/v2/auth/callback", { |
| 903 | + email, |
| 904 | + redirect_uri: "http://localhost:3000/api/auth/callback/google", |
| 905 | + scope: "openid email profile", |
| 906 | + client_id: "emu_google_client_id", |
| 907 | + }); |
| 908 | + const code = new URL(authorize.headers.get("Location")!).searchParams.get("code")!; |
| 909 | + const tokenRes = await formRequest(app, "/oauth2/token", { |
| 910 | + code, |
| 911 | + grant_type: "authorization_code", |
| 912 | + redirect_uri: "http://localhost:3000/api/auth/callback/google", |
| 913 | + client_id: "emu_google_client_id", |
| 914 | + client_secret: "emu_google_client_secret", |
| 915 | + }); |
| 916 | + const body = (await tokenRes.json()) as { id_token: string; access_token: string }; |
| 917 | + return { claims: decodeJwt(body.id_token) as { hd?: string }, accessToken: body.access_token }; |
| 918 | + } |
| 919 | + |
| 920 | + const derived = await getIdTokenClaims("testuser@example.com"); |
| 921 | + expect(derived.claims.hd).toBe("example.com"); |
| 922 | + |
| 923 | + const overridden = await getIdTokenClaims("workspaceuser@example.com"); |
| 924 | + expect(overridden.claims.hd).toBe("override.io"); |
| 925 | + |
| 926 | + const consumer = await getIdTokenClaims("consumer@gmail.com"); |
| 927 | + expect(consumer.claims.hd).toBeUndefined(); |
| 928 | + |
| 929 | + const userinfoRes = await app.request(`${base}/oauth2/v2/userinfo`, { |
| 930 | + headers: { Authorization: `Bearer ${overridden.accessToken}` }, |
| 931 | + }); |
| 932 | + expect(userinfoRes.status).toBe(200); |
| 933 | + expect(((await userinfoRes.json()) as { hd?: string }).hd).toBe("override.io"); |
| 934 | + }); |
| 935 | + |
895 | 936 | it("lists calendar resources, creates events, queries freebusy, and deletes events", async () => { |
896 | 937 | const calendarListRes = await app.request(`${base}/calendar/v3/users/me/calendarList`, { |
897 | 938 | headers: authHeaders(), |
|
0 commit comments