Fix JWT generation using native Deno Web Crypto API

- Remove external jose library dependency that was causing import errors
- Use native crypto.subtle API available in Deno
- Manual base64url encoding for JWT header, payload, and signature
- Use RSASSA-PKCS1-v1_5 with SHA-256 for RS256 algorithm
- Remove cat heredoc wrapper from file
This commit is contained in:
dwindown
2025-12-23 11:25:20 +07:00
parent 43305a2f16
commit bc8bc1159d

View File

@@ -27,30 +27,11 @@ interface CreateMeetRequest {
notes?: string; notes?: string;
} }
// Function to create JWT and get access token // Function to create JWT and get access token using native Web Crypto API
async function getGoogleAccessToken(serviceAccount: GoogleServiceAccount): Promise<string> { async function getGoogleAccessToken(serviceAccount: GoogleServiceAccount): Promise<string> {
try { try {
// Use a different JWT library that's more compatible with Google's requirements
const { importKey, sign } = await import("https://deno.land/x/jose@v4.15.1/node/crypto.ts");
const now = Math.floor(Date.now() / 1000); const now = Math.floor(Date.now() / 1000);
// Convert PEM format private key to CryptoKey
const privateKey = await importKey(
"pkcs8",
// Convert PEM to binary
Uint8Array.from(
atob(serviceAccount.private_key
.replace(/-----BEGIN PRIVATE KEY-----/g, "")
.replace(/-----END PRIVATE KEY-----/g, "")
.replace(/\s/g, "")),
c => c.charCodeAt(0)
),
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
false,
["sign"]
);
// Build JWT header and payload manually // Build JWT header and payload manually
const header = { const header = {
alg: "RS256", alg: "RS256",
@@ -65,21 +46,40 @@ async function getGoogleAccessToken(serviceAccount: GoogleServiceAccount): Promi
iat: now, iat: now,
}; };
// Encode header and payload // Encode header and payload (base64url)
const encodedHeader = btoa(JSON.stringify(header)) const base64UrlEncode = (str: string) => {
.replace(/\+/g, "-") return btoa(str)
.replace(/\//g, "_") .replace(/\+/g, "-")
.replace(/=/g, ""); .replace(/\//g, "_")
.replace(/=/g, "");
const encodedPayload = btoa(JSON.stringify(payload)) };
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
const encodedHeader = base64UrlEncode(JSON.stringify(header));
const encodedPayload = base64UrlEncode(JSON.stringify(payload));
const signatureInput = `${encodedHeader}.${encodedPayload}`; const signatureInput = `${encodedHeader}.${encodedPayload}`;
// Convert PEM to binary
const keyData = serviceAccount.private_key
.replace(/-----BEGIN PRIVATE KEY-----/g, "")
.replace(/-----END PRIVATE KEY-----/g, "")
.replace(/\s/g, "");
const binaryKey = Uint8Array.from(atob(keyData), c => c.charCodeAt(0));
// Import private key using native Web Crypto API
const privateKey = await crypto.subtle.importKey(
"pkcs8",
binaryKey,
{
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
},
false,
["sign"]
);
// Sign the JWT // Sign the JWT
const signature = await sign( const signature = await crypto.subtle.sign(
"RSASSA-PKCS1-v1_5", "RSASSA-PKCS1-v1_5",
privateKey, privateKey,
new TextEncoder().encode(signatureInput) new TextEncoder().encode(signatureInput)