diff options
| author | JustZvan <justzvan@justzvan.xyz> | 2026-04-06 14:25:51 +0200 |
|---|---|---|
| committer | JustZvan <justzvan@justzvan.xyz> | 2026-04-06 14:25:51 +0200 |
| commit | 18efc1e708821fd1f36532d659b928c320f4a143 (patch) | |
| tree | 2938c5fcefb4faccb2bfa01e59eaefc8efd409f7 /src/account/google.ts | |
| parent | de366e1607ae66fa5227ed8a5d7b0d2a2996e002 (diff) | |
feat: google signin
Diffstat (limited to 'src/account/google.ts')
| -rw-r--r-- | src/account/google.ts | 42 |
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, + }; +} |