Refactor Google authentication functions for Vertex AI - Exported `getVertexAIAuth`, `generateJWTToken`, and `getAccessToken` functions from google.js for better modularity. - Removed redundant JWT token generation and access token retrieval logic from chat-completions.js, utilizing the newly exported functions instead. - Improved code organization and maintainability by centralizing authentication logic.

1c048a6c799a37090b2a3e6bb024f8ebc1b25d68

InterestingDarkness <computeridiot999@gmail.com>

2 files changed, +4 -116Showing whitespace changes
src/endpoints/backends/chat-completions.js+1 -113
@@ -1,6 +1,5 @@
11import process from 'node:process';
22import util from 'node:util';
3-import crypto from 'node:crypto';
43import express from 'express';
54import fetch from 'node-fetch';
65
@@ -44,6 +43,7 @@ import {
4443 webTokenizers,
4544 getWebTokenizer,
4645} from '../tokenizers.js';
46+import { getVertexAIAuth } from '../google.js';
4747
4848const API_OPENAI = 'https://api.openai.com/v1';
4949const API_CLAUDE = 'https://api.anthropic.com/v1';
@@ -61,123 +61,11 @@ const API_DEEPSEEK = 'https://api.deepseek.com/beta';
6161const API_XAI = 'https://api.x.ai/v1';
6262const API_POLLINATIONS = 'https://text.pollinations.ai/openai';
6363
64-/**
65- * Generates a JWT token for Google Cloud authentication using service account credentials.
66- * @param {object} serviceAccount Service account JSON object
67- * @returns {Promise<string>} JWT token
68- */
69-async function generateJWTToken(serviceAccount) {
70- const now = Math.floor(Date.now() / 1000);
71- const expiry = now + 3600; // 1 hour
7264
73- const header = {
74- alg: 'RS256',
75- typ: 'JWT',
76- };
77-
78- const payload = {
79- iss: serviceAccount.client_email,
80- scope: 'https://www.googleapis.com/auth/cloud-platform',
81- aud: 'https://oauth2.googleapis.com/token',
82- iat: now,
83- exp: expiry,
84- };
8565
86- const headerBase64 = Buffer.from(JSON.stringify(header)).toString('base64url');
87- const payloadBase64 = Buffer.from(JSON.stringify(payload)).toString('base64url');
88- const signatureInput = `${headerBase64}.${payloadBase64}`;
8966
90- // Create signature using private key
91- const sign = crypto.createSign('RSA-SHA256');
92- sign.update(signatureInput);
93- const signature = sign.sign(serviceAccount.private_key, 'base64url');
9467
95- return `${signatureInput}.${signature}`;
96-}
9768
98-/**
99- * Gets an access token from Google OAuth2 using JWT assertion.
100- * @param {string} jwtToken JWT token
101- * @returns {Promise<string>} Access token
102- */
103-async function getAccessToken(jwtToken) {
104- const response = await fetch('https://oauth2.googleapis.com/token', {
105- method: 'POST',
106- headers: {
107- 'Content-Type': 'application/x-www-form-urlencoded',
108- },
109- body: new URLSearchParams({
110- grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
111- assertion: jwtToken,
112- }),
113- });
114-
115- if (!response.ok) {
116- throw new Error(`Failed to get access token: ${response.status} ${response.statusText}`);
117- }
118-
119- const data = await response.json();
120- return data.access_token;
121-}
122-
123-/**
124- * Gets authentication for Vertex AI - either API key or service account token.
125- * @param {object} request Express request
126- * @returns {Promise<{authHeader: string, authType: string}>} Authentication header and type
127- */
128-async function getVertexAIAuth(request) {
129- // Get the authentication mode from frontend
130- const authMode = request.body.vertexai_auth_mode || 'express';
131-
132- // Check if using reverse proxy
133- if (request.body.reverse_proxy) {
134- return {
135- authHeader: `Bearer ${request.body.proxy_password}`,
136- authType: 'proxy',
137- };
138- }
139-
140- if (authMode === 'express') {
141- // Express mode: use API key
142- const apiKey = readSecret(request.user.directories, SECRET_KEYS.VERTEXAI);
143- if (apiKey) {
144- return {
145- authHeader: `Bearer ${apiKey}`,
146- authType: 'express',
147- };
148- }
149- throw new Error('API key is required for Vertex AI Express mode');
150- } else if (authMode === 'full') {
151- // Full mode: use service account JSON
152- // First try to read from backend secret storage
153- let serviceAccountJson = readSecret(request.user.directories, SECRET_KEYS.VERTEXAI_SERVICE_ACCOUNT);
154-
155- // If not found in secrets, fall back to request body (for backward compatibility)
156- if (!serviceAccountJson) {
157- serviceAccountJson = request.body.vertexai_service_account_json;
158- }
159-
160- if (serviceAccountJson) {
161- try {
162- const serviceAccount = JSON.parse(serviceAccountJson);
163-
164- const jwtToken = await generateJWTToken(serviceAccount);
165- const accessToken = await getAccessToken(jwtToken);
166-
167- return {
168- authHeader: `Bearer ${accessToken}`,
169- authType: 'full',
170- };
171- } catch (error) {
172- console.error('Failed to authenticate with service account:', error);
173- throw new Error(`Service account authentication failed: ${error.message}`);
174- }
175- }
176- throw new Error('Service Account JSON is required for Vertex AI Full mode');
177- }
178-
179- throw new Error(`Unsupported Vertex AI authentication mode: ${authMode}`);
180-}
18169
18270/**
18371 * Applies a post-processing step to the generated messages.
src/endpoints/google.js+3 -3
@@ -11,7 +11,7 @@ const API_MAKERSUITE = 'https://generativelanguage.googleapis.com';
1111const API_VERTEX_AI = 'https://us-central1-aiplatform.googleapis.com';
1212
1313// Vertex AI authentication helper functions
1414export async function getVertexAIAuth(request) {
1515 const authMode = request.body.vertexai_auth_mode || 'express';
1616
1717 if (request.body.reverse_proxy) {
@@ -64,7 +64,7 @@ async function getVertexAIAuth(request) {
6464 * @param {object} serviceAccount Service account JSON object
6565 * @returns {Promise<string>} JWT token
6666 */
6767export async function generateJWTToken(serviceAccount) {
6868 const now = Math.floor(Date.now() / 1000);
6969 const expiry = now + 3600; // 1 hour
7070
@@ -93,7 +93,7 @@ async function generateJWTToken(serviceAccount) {
9393 return `${signatureInput}.${signature}`;
9494}
9595
9696export async function getAccessToken(jwtToken) {
9797 const response = await fetch('https://oauth2.googleapis.com/token', {
9898 method: 'POST',
9999 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },