summaryrefslogtreecommitdiff
path: root/src/account/google.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/account/google.ts')
-rw-r--r--src/account/google.ts42
1 files changed, 42 insertions, 0 deletions
diff --git a/src/account/google.ts b/src/account/google.ts
new file mode 100644
index 0000000..2194a18
--- /dev/null
+++ b/src/account/google.ts
@@ -0,0 +1,42 @@
+import * as jose from "jose";
+import { logger } from "../lib/pino";
+
+const googleJwks = jose.createRemoteJWKSet(
+ new URL("https://www.googleapis.com/oauth2/v3/certs"),
+);
+
+export interface GoogleUserProfile {
+ email: string;
+ emailVerified: boolean;
+ subject: string;
+}
+
+export async function verifyGoogleIdToken(
+ token: string,
+): Promise<GoogleUserProfile> {
+ const googleClientId = process.env.GOOGLE_CLIENT_ID;
+
+ if (!googleClientId) {
+ logger.error("GOOGLE_CLIENT_ID environment variable not set");
+ throw new Error("GOOGLE_CLIENT_ID not configured");
+ }
+
+ const { payload } = await jose.jwtVerify(token, googleJwks, {
+ issuer: ["https://accounts.google.com", "accounts.google.com"],
+ audience: googleClientId,
+ });
+
+ if (typeof payload.email !== "string" || payload.email.length === 0) {
+ throw new Error("Google token is missing email");
+ }
+
+ if (typeof payload.sub !== "string" || payload.sub.length === 0) {
+ throw new Error("Google token is missing subject");
+ }
+
+ return {
+ email: payload.email,
+ emailVerified: payload.email_verified === true,
+ subject: payload.sub,
+ };
+}