mirror of
https://github.com/better-auth/better-auth.git
synced 2026-05-27 01:16:55 -05:00
chore: add nonce check and verifying jwt claims for google (#6614)
This commit is contained in:
committed by
github-actions[bot]
parent
312fc0248a
commit
f758f14a4b
@@ -1,5 +1,6 @@
|
||||
import { betterFetch } from "@better-fetch/fetch";
|
||||
import { decodeJwt } from "jose";
|
||||
import { APIError } from "better-call";
|
||||
import { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from "jose";
|
||||
import { logger } from "../env";
|
||||
import { BetterAuthError } from "../error";
|
||||
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
||||
@@ -126,24 +127,26 @@ export const google = (options: GoogleOptions) => {
|
||||
if (options.verifyIdToken) {
|
||||
return options.verifyIdToken(token, nonce);
|
||||
}
|
||||
const googlePublicKeyUrl = `https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=${token}`;
|
||||
const { data: tokenInfo } = await betterFetch<{
|
||||
aud: string;
|
||||
iss: string;
|
||||
email: string;
|
||||
email_verified: boolean;
|
||||
name: string;
|
||||
picture: string;
|
||||
sub: string;
|
||||
}>(googlePublicKeyUrl);
|
||||
if (!tokenInfo) {
|
||||
|
||||
// Verify JWT integrity
|
||||
// See https://developers.google.com/identity/sign-in/web/backend-auth#verify-the-integrity-of-the-id-token
|
||||
|
||||
const { kid, alg: jwtAlg } = decodeProtectedHeader(token);
|
||||
if (!kid || !jwtAlg) return false;
|
||||
|
||||
const publicKey = await getGooglePublicKey(kid);
|
||||
const { payload: jwtClaims } = await jwtVerify(token, publicKey, {
|
||||
algorithms: [jwtAlg],
|
||||
issuer: ["https://accounts.google.com", "accounts.google.com"],
|
||||
audience: options.clientId,
|
||||
maxTokenAge: "1h",
|
||||
});
|
||||
|
||||
if (nonce && jwtClaims.nonce !== nonce) {
|
||||
return false;
|
||||
}
|
||||
const isValid =
|
||||
tokenInfo.aud === options.clientId &&
|
||||
(tokenInfo.iss === "https://accounts.google.com" ||
|
||||
tokenInfo.iss === "accounts.google.com");
|
||||
return isValid;
|
||||
|
||||
return true;
|
||||
},
|
||||
async getUserInfo(token) {
|
||||
if (options.getUserInfo) {
|
||||
@@ -169,3 +172,29 @@ export const google = (options: GoogleOptions) => {
|
||||
options,
|
||||
} satisfies OAuthProvider<GoogleProfile>;
|
||||
};
|
||||
|
||||
export const getGooglePublicKey = async (kid: string) => {
|
||||
const { data } = await betterFetch<{
|
||||
keys: Array<{
|
||||
kid: string;
|
||||
alg: string;
|
||||
kty: string;
|
||||
use: string;
|
||||
n: string;
|
||||
e: string;
|
||||
}>;
|
||||
}>("https://www.googleapis.com/oauth2/v3/certs");
|
||||
|
||||
if (!data?.keys) {
|
||||
throw new APIError("BAD_REQUEST", {
|
||||
message: "Keys not found",
|
||||
});
|
||||
}
|
||||
|
||||
const jwk = data.keys.find((key) => key.kid === kid);
|
||||
if (!jwk) {
|
||||
throw new Error(`JWK with kid ${kid} not found`);
|
||||
}
|
||||
|
||||
return await importJWK(jwk, jwk.alg);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user