import { AbstractClient } from './AbstractClient.js'; const AUTH_API_ENDPOINT = 'api/v2/auth/pkey/jwt/'; /** * # Client examples * * Authenticate against a Graphistry server using a personal key id and secret, and manage communications with it. * * Different authentication modes may be desirable depending on the type of Graphistry server. * *
* * --- * *
* * @example **Authenticate against Graphistry Hub for a personal account** * ```javascript * import { Client } from '@graphistry/node-api'; * const client = new Client('my_personal_key_id', 'my_personal_key_secret'); * ``` * *
* * @example **Authenticate against an org in Graphistry Hub** * ```javascript * import { Client } from '@graphistry/node-api'; * const client = new Client('my_personal_key_id', 'my_personal_key_secret', 'my_org'); * ``` * *
* * @example **Authenticate against a private Graphistry server** * ```javascript * import { Client } from '@graphistry/node-api'; * const client = new Client('my_personal_key_id', 'my_personal_key_secret', '', 'http', 'my-ec2.aws.com:8080'); * ``` * *
* * @example **Upload via internal IP but publish urls via a public domain** * ```javascript * import { Client } from '@graphistry/node-api'; * const client = new Client( * 'my_personal_key_id', 'my_personal_key_secret', '', * 'http', '10.20.0.1:8080', * 'https://www.my-site.com' * ); * ``` * *
* * @example **Upload through the local docker network but publish urls via a public domain** * ```javascript * import { Client } from '@graphistry/node-api'; * const client = new Client( * 'my_personal_key_id', 'my_personal_key_secret', '', * 'http', 'nginx', * 'https://www.my-site.com' * ); * ``` * *
* * @example **Create a client with an externally-provided JWT token** * ```javascript * import { Client } from '@graphistry/node-api'; * const client = new Client(); * client.setToken('Bearer 123abc'); * ``` */ export class ClientPKey extends AbstractClient { public readonly personalKeyId: string; private _personalKeySecret: string; /** * * See examples at top of file * * @param personalKeyId The personal key id to authenticate with. * @param personalKeySecret The personal key secret to authenticate with. * @param org The organization to use (optional) * @param protocol The protocol to use for the server during uploads: 'http' or 'https'. * @param host The hostname of the server during uploads: defaults to 'hub.graphistry.com' * @param clientProtocolHostname Base path to use inside the browser and when sharing public URLs: defaults to '{protocol}://{host}' * @param fetch The fetch implementation to use * @param version The version of the client library * @param agent The agent name to use when communicating with the server */ constructor ( personalKeyId: string, personalKeySecret: string, org?: string, protocol = 'https', host = 'hub.graphistry.com', clientProtocolHostname?: string, fetch?: any, version?: string, agent = '@graphistry/js-upload-api', ) { super(org, protocol, host, clientProtocolHostname, fetch, version, agent); this.personalKeyId = personalKeyId; this._personalKeySecret = personalKeySecret; if (this.isServerConfigured()) { this._getAuthTokenPromise = this.getAuthToken(); } } public isServerConfigured() { return (this.personalKeyId || '') !== '' && (this._personalKeySecret || '') !== '' && (this.host || '') !== ''; } public checkStale(personalKeyId: string, personalKeySecret: string, protocol: string, host: string, clientProtocolHostname?: string) { // personalKeyId changed if (this.personalKeyId !== personalKeyId) { return true; } // personalKeySecret changed if (this._personalKeySecret !== personalKeySecret) { return true; } // protocol changed if (this.protocol !== protocol) { return true; } // host changed if (this.host !== host) { return true; } // clientProtocolHostname changed if (this.clientProtocolHostname !== clientProtocolHostname) { return true; } return false; } private getPKeyString(id: string, secret: string) { return `PersonalKey ${id}:${secret}`; } /** * Get the authentication token for the current user. * By default, reuses current token if available. * * @param force If true, forces a new token to be generated; defaults to false * * @returns The authentication token * */ protected async getAuthToken(force = false) { if (!force && this.authTokenValid()) { return this._token || ''; // workaround ts not recognizing that _token is set } //Throw exception if invalid personalKeyId or personalKeySecret if (!this.isServerConfigured()) { throw new Error('Invalid personalKeyId or personalKeySecret'); } if (!force && this._getAuthTokenPromise) { // reusing outstanding auth promise return await this._getAuthTokenPromise; } let response = await this.postToApi( AUTH_API_ENDPOINT, { ...(this.org ? {org_name: this.org} : {}), }, { "Authorization": this.getPKeyString(this.personalKeyId, this._personalKeySecret), ...this.getBaseHeaders(), } ); // fallback to personal-only GET pkey auth if 405 (Method Not Allowed) if(response.status === 405) { if(this.org) { console.warn('Host does not support org auth via PKey, use username/password auth instead'); } response = await this.getToApi( AUTH_API_ENDPOINT, { "Authorization": this.getPKeyString(this.personalKeyId, this._personalKeySecret), } ); } response = await response.json(); const tok : string = response.token; this._token = tok; if (!this.authTokenValid()) { console.error('auth token failure', {response, personalKeyId: this.personalKeyId, host: this.host}); throw new Error({'error': 'Auth token failure', ...(response||{})}); } return tok; } /** * * @param personalKeyId * @param personalKeySecret * @param org * @param protocol * @param host * @returns Promise for the authentication token * * Helper to fetch a token for a given user * */ public async fetchToken( personalKeyId: string, personalKeySecret: string, org?: string, protocol = 'https', host = 'hub.graphistry.com' ): Promise { let response = await this.postToApi( AUTH_API_ENDPOINT, { ...(org ? {org_name: org} : {}), }, { "Authorization": this.getPKeyString(personalKeyId, personalKeySecret), ...this.getBaseHeaders(), }, `${protocol}://${host}/` ); // fallback to personal-only GET pkey auth if 405 (Method Not Allowed) if(response.status === 405) { if(org) { console.warn('Host does not support org auth via PKey, use username/password auth instead'); } response = await this.getToApi( AUTH_API_ENDPOINT, { "Authorization": this.getPKeyString(personalKeyId, personalKeySecret), }, `${protocol}://${host}/` ); } response = await response.json(); return response.token; } }