diff --git a/docs/pages/product/configuration/data-sources/snowflake.mdx b/docs/pages/product/configuration/data-sources/snowflake.mdx index 49885e07add92..4aadb1b570a88 100644 --- a/docs/pages/product/configuration/data-sources/snowflake.mdx +++ b/docs/pages/product/configuration/data-sources/snowflake.mdx @@ -84,6 +84,7 @@ if [dedicated infrastructure][ref-dedicated-infra] is used. Check out the | `CUBEJS_DB_SNOWFLAKE_PRIVATE_KEY` | The content of the private RSA key | Content of the private RSA key (encrypted or not) | ❌ | | `CUBEJS_DB_SNOWFLAKE_PRIVATE_KEY_PATH` | The path to the private RSA key | A valid path to the private RSA key | ❌ | | `CUBEJS_DB_SNOWFLAKE_PRIVATE_KEY_PASS` | The password for the private RSA key. Only required for encrypted keys | A valid password for the encrypted private RSA key | ❌ | +| `CUBEJS_DB_SNOWFLAKE_OAUTH_TOKEN` | The OAuth token | A valid OAuth token (string) | ❌ | | `CUBEJS_DB_SNOWFLAKE_OAUTH_TOKEN_PATH` | The path to the valid oauth toket file | A valid path for the oauth token file | ❌ | | `CUBEJS_DB_SNOWFLAKE_HOST` | Host address to which the driver should connect | A valid hostname | ❌ | | `CUBEJS_DB_SNOWFLAKE_QUOTED_IDENTIFIERS_IGNORE_CASE` | Whether or not [quoted identifiers should be case insensitive][link-snowflake-quoted-identifiers]. Default is `false` | `true`, `false` | ❌ | diff --git a/packages/cubejs-backend-shared/src/env.ts b/packages/cubejs-backend-shared/src/env.ts index f3f37fd0c7d39..60b4e263ebdb7 100644 --- a/packages/cubejs-backend-shared/src/env.ts +++ b/packages/cubejs-backend-shared/src/env.ts @@ -1569,6 +1569,19 @@ const variables: Record any> = { ] ), + /** + * Snowflake OAuth token (string). + */ + snowflakeOAuthToken: ({ + dataSource + }: { + dataSource: string, + }) => ( + process.env[ + keyByDataSource('CUBEJS_DB_SNOWFLAKE_OAUTH_TOKEN', dataSource) + ] + ), + /** * Snowflake OAuth token path. */ diff --git a/packages/cubejs-snowflake-driver/src/SnowflakeDriver.ts b/packages/cubejs-snowflake-driver/src/SnowflakeDriver.ts index 02e4ab3ec7d6d..298da844ba344 100644 --- a/packages/cubejs-snowflake-driver/src/SnowflakeDriver.ts +++ b/packages/cubejs-snowflake-driver/src/SnowflakeDriver.ts @@ -153,6 +153,7 @@ interface SnowflakeDriverOptions { clientSessionKeepAlive?: boolean, database?: string, authenticator?: string, + oauthToken?: string, oauthTokenPath?: string, token?: string, privateKeyPath?: string, @@ -189,7 +190,7 @@ export class SnowflakeDriver extends BaseDriver implements DriverInterface { /** * Returns the configurable driver options * Note: It returns the unprefixed option names. - * In case of using multisources options need to be prefixed manually. + * In case of using multi-sources options need to be prefixed manually. */ public static driverEnvVariables() { return [ @@ -202,6 +203,7 @@ export class SnowflakeDriver extends BaseDriver implements DriverInterface { 'CUBEJS_DB_SNOWFLAKE_ROLE', 'CUBEJS_DB_SNOWFLAKE_CLIENT_SESSION_KEEP_ALIVE', 'CUBEJS_DB_SNOWFLAKE_AUTHENTICATOR', + 'CUBEJS_DB_SNOWFLAKE_OAUTH_TOKEN', 'CUBEJS_DB_SNOWFLAKE_OAUTH_TOKEN_PATH', 'CUBEJS_DB_SNOWFLAKE_HOST', 'CUBEJS_DB_SNOWFLAKE_PRIVATE_KEY', @@ -286,6 +288,7 @@ export class SnowflakeDriver extends BaseDriver implements DriverInterface { username: getEnv('dbUser', { dataSource }), password: getEnv('dbPass', { dataSource }), authenticator: getEnv('snowflakeAuthenticator', { dataSource }), + oauthToken: getEnv('snowflakeOAuthToken', { dataSource }), oauthTokenPath: getEnv('snowflakeOAuthTokenPath', { dataSource }), privateKeyPath: getEnv('snowflakePrivateKeyPath', { dataSource }), privateKeyPass: getEnv('snowflakePrivateKeyPass', { dataSource }), @@ -423,12 +426,39 @@ export class SnowflakeDriver extends BaseDriver implements DriverInterface { return token.trim(); } - private async createConnection() { + private async prepareConnectOptions(): Promise { + const config: Record = { + account: this.config.account, + region: this.config.region, + host: this.config.host, + application: this.config.application, + authenticator: this.config.authenticator, + clientSessionKeepAlive: this.config.clientSessionKeepAlive, + database: this.config.database, + warehouse: this.config.warehouse, + role: this.config.role, + resultPrefetch: this.config.resultPrefetch, + }; + if (this.config.authenticator?.toUpperCase() === 'OAUTH') { - this.config.token = await this.readOAuthToken(); + config.token = this.config.oauthToken || await this.readOAuthToken(); + } else if (this.config.authenticator?.toUpperCase() === 'SNOWFLAKE_JWT') { + config.username = this.config.username; + config.privateKey = this.config.privateKey; + config.privateKeyPath = this.config.privateKeyPath; + config.privateKeyPass = this.config.privateKeyPass; + } else { + config.username = this.config.username; + config.password = this.config.password; } - return snowflake.createConnection(this.config); + return config as snowflake.ConnectionOptions; + } + + private async createConnection() { + const config = await this.prepareConnectOptions(); + + return snowflake.createConnection(config); } /**