Files
smartai/test/test.openai-auth.node.ts
T

210 lines
6.8 KiB
TypeScript
Raw Normal View History

import { tap, expect } from '@git.zone/tstest/tapbundle';
import * as smartai from '../ts/index.js';
import type { IOpenAiMaxTokenData } from '../ts/index.js';
interface IMockFetchRequest {
url: string;
init?: RequestInit;
}
function createJwt(payload: Record<string, unknown>): string {
const encode = (value: Record<string, unknown>) => Buffer.from(JSON.stringify(value)).toString('base64url');
return `${encode({ alg: 'none', typ: 'JWT' })}.${encode(payload)}.sig`;
}
function createTokenData(accountId = 'workspace-1'): IOpenAiMaxTokenData {
const idToken = createJwt({
email: 'user@example.com',
exp: 4_102_444_800,
'https://api.openai.com/auth': {
chatgpt_plan_type: 'pro',
chatgpt_user_id: 'user-1',
chatgpt_account_id: accountId,
chatgpt_account_is_fedramp: false,
},
});
const idTokenInfo = smartai.parseOpenAiMaxIdToken(idToken);
return {
idToken,
accessToken: 'access-token',
refreshToken: 'refresh-token',
accountId,
idTokenInfo,
};
}
function jsonResponse(body: unknown, status = 200): Response {
return new Response(JSON.stringify(body), {
status,
headers: { 'content-type': 'application/json' },
});
}
function getHeader(init: RequestInit | undefined, name: string): string | null {
return new Headers(init?.headers).get(name);
}
tap.test('requestOpenAiMaxDeviceCode requests a user code', async () => {
const originalFetch = globalThis.fetch;
const requests: IMockFetchRequest[] = [];
globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
requests.push({ url: String(input), init });
return jsonResponse({
device_auth_id: 'device-1',
usercode: 'ABCD-EFGH',
interval: '2',
});
};
try {
const deviceCode = await smartai.requestOpenAiMaxDeviceCode({
issuer: 'https://auth.example.test',
clientId: 'client-1',
});
expect(deviceCode).toEqual({
verificationUrl: 'https://auth.example.test/codex/device',
userCode: 'ABCD-EFGH',
deviceAuthId: 'device-1',
intervalSeconds: 2,
});
expect(requests[0].url).toEqual('https://auth.example.test/api/accounts/deviceauth/usercode');
expect(JSON.parse(String(requests[0].init?.body))).toEqual({ client_id: 'client-1' });
} finally {
globalThis.fetch = originalFetch;
}
});
tap.test('completeOpenAiMaxDeviceCodeLogin polls and exchanges OAuth tokens', async () => {
const originalFetch = globalThis.fetch;
const requests: IMockFetchRequest[] = [];
const tokenData = createTokenData('workspace-1');
const responses = [
jsonResponse({}, 403),
jsonResponse({
authorization_code: 'auth-code',
code_challenge: 'challenge',
code_verifier: 'verifier',
}),
jsonResponse({
id_token: tokenData.idToken,
access_token: tokenData.accessToken,
refresh_token: tokenData.refreshToken,
}),
];
globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
requests.push({ url: String(input), init });
const response = responses.shift();
if (!response) throw new Error('Unexpected fetch call');
return response;
};
try {
const result = await smartai.completeOpenAiMaxDeviceCodeLogin({
verificationUrl: 'https://auth.example.test/codex/device',
userCode: 'ABCD-EFGH',
deviceAuthId: 'device-1',
intervalSeconds: 1,
}, {
issuer: 'https://auth.example.test',
clientId: 'client-1',
forcedChatGptWorkspaceId: 'workspace-1',
sleep: async () => undefined,
});
expect(result.accessToken).toEqual('access-token');
expect(result.refreshToken).toEqual('refresh-token');
expect(result.idTokenInfo.chatgptAccountId).toEqual('workspace-1');
expect(requests.length).toEqual(3);
expect(JSON.parse(String(requests[0].init?.body))).toEqual({
device_auth_id: 'device-1',
user_code: 'ABCD-EFGH',
});
const tokenExchangeBody = new URLSearchParams(String(requests[2].init?.body));
expect(tokenExchangeBody.get('grant_type')).toEqual('authorization_code');
expect(tokenExchangeBody.get('code')).toEqual('auth-code');
expect(tokenExchangeBody.get('redirect_uri')).toEqual('https://auth.example.test/deviceauth/callback');
expect(tokenExchangeBody.get('client_id')).toEqual('client-1');
expect(tokenExchangeBody.get('code_verifier')).toEqual('verifier');
} finally {
globalThis.fetch = originalFetch;
}
});
tap.test('refreshOpenAiMaxTokenData refreshes and preserves omitted token fields', async () => {
const originalFetch = globalThis.fetch;
const requests: IMockFetchRequest[] = [];
const tokenData = createTokenData('workspace-1');
globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
requests.push({ url: String(input), init });
return jsonResponse({ access_token: 'new-access-token' });
};
try {
const result = await smartai.refreshOpenAiMaxTokenData(tokenData, {
issuer: 'https://auth.example.test',
clientId: 'client-1',
});
expect(result.accessToken).toEqual('new-access-token');
expect(result.refreshToken).toEqual('refresh-token');
expect(result.idToken).toEqual(tokenData.idToken);
expect(JSON.parse(String(requests[0].init?.body))).toEqual({
client_id: 'client-1',
grant_type: 'refresh_token',
refresh_token: 'refresh-token',
});
} finally {
globalThis.fetch = originalFetch;
}
});
tap.test('getModel uses ChatGPT Codex backend for OpenAI Max auth', async () => {
const originalFetch = globalThis.fetch;
let capturedRequest: IMockFetchRequest | undefined;
const tokenData = createTokenData('workspace-1');
const model = smartai.getModel({
provider: 'openai',
model: 'gpt-5.5',
openAiMaxAuth: tokenData,
});
globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
capturedRequest = { url: String(input), init };
return jsonResponse({
id: 'resp-1',
created_at: 1,
model: 'gpt-5.5',
output: [{
type: 'message',
role: 'assistant',
id: 'msg-1',
content: [{ type: 'output_text', text: 'ok', annotations: [] }],
}],
usage: {
input_tokens: 1,
output_tokens: 1,
},
});
};
try {
await model.doGenerate({
prompt: [{ role: 'user', content: [{ type: 'text', text: 'hello' }] }],
inputFormat: 'prompt',
} as any);
expect(capturedRequest?.url).toEqual('https://chatgpt.com/backend-api/codex/responses');
expect(getHeader(capturedRequest?.init, 'authorization')).toEqual('Bearer access-token');
expect(getHeader(capturedRequest?.init, 'chatgpt-account-id')).toEqual('workspace-1');
expect(getHeader(capturedRequest?.init, 'originator')).toEqual('smartai');
} finally {
globalThis.fetch = originalFetch;
}
});
export default tap.start();