@databricks/sdk-auth 0.48.0 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/credentials/default/chain.d.ts +2 -0
- package/dist/credentials/default/chain.d.ts.map +1 -1
- package/dist/credentials/default/chain.js +6 -1
- package/dist/credentials/default/chain.js.map +1 -1
- package/dist/credentials/default/default-credentials.d.ts +4 -0
- package/dist/credentials/default/default-credentials.d.ts.map +1 -1
- package/dist/credentials/default/default-credentials.js +4 -0
- package/dist/credentials/default/default-credentials.js.map +1 -1
- package/dist/credentials/default/errors.d.ts +1 -1
- package/dist/credentials/default/errors.d.ts.map +1 -1
- package/dist/credentials/default/errors.js.map +1 -1
- package/dist/credentials/default/u2m-strategy.js +1 -0
- package/dist/credentials/default/u2m-strategy.js.map +1 -1
- package/dist/credentials/m2m.d.ts +5 -0
- package/dist/credentials/m2m.d.ts.map +1 -1
- package/dist/credentials/m2m.js +4 -2
- package/dist/credentials/m2m.js.map +1 -1
- package/dist/oidc/tokensource.d.ts +5 -0
- package/dist/oidc/tokensource.d.ts.map +1 -1
- package/dist/oidc/tokensource.js +1 -0
- package/dist/oidc/tokensource.js.map +1 -1
- package/dist/package.js +1 -1
- package/package.json +2 -2
|
@@ -11,6 +11,8 @@ import { Profile } from "@databricks/sdk-core/profiles";
|
|
|
11
11
|
interface Strategy {
|
|
12
12
|
/** Short identifier, e.g. `pat`, `oauth-m2m`, or `databricks-cli`. */
|
|
13
13
|
readonly name: string;
|
|
14
|
+
/** Whether this strategy can request credentials for an assumed group. */
|
|
15
|
+
readonly supportsGroupAssumption: boolean;
|
|
14
16
|
readonly configure: (profile: Profile) => Credentials | undefined;
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain.d.ts","names":[],"sources":["../../../src/credentials/default/chain.ts"],"mappings":";;;;;;AAcA;;;;UAAiB,QAAA;
|
|
1
|
+
{"version":3,"file":"chain.d.ts","names":[],"sources":["../../../src/credentials/default/chain.ts"],"mappings":";;;;;;AAcA;;;;UAAiB,QAAA;EAIN;EAAA,SAFA,IAAA;EAGqB;EAAA,SADrB,uBAAA;EAAA,SACA,SAAA,GAAY,OAAA,EAAS,OAAA,KAAY,WAAA;AAAA;;AAc5C;;;;;;;cAAa,kBAAA,YAA8B,WAAA;EAAA,iBAItB,UAAA;EAAA,iBACA,WAAA;EAAA,QAJX,QAAA;cAGW,UAAA,WAAqB,QAAA,IACrB,WAAA,QAAmB,OAAA,CAAQ,OAAA;EAD3B;;;;;EASnB,IAAA,CAAA;EAIM,WAAA,CAAA,GAAe,OAAA,CAAQ,MAAA;EAAA,QAKf,YAAA;EAAA,QAwBN,iBAAA;AAAA;;cA8BG,WAAA,EAAa,QAAA;;;;;cAcb,WAAA,EAAa,QAAA"}
|
|
@@ -35,6 +35,7 @@ var DefaultCredentials = class {
|
|
|
35
35
|
const profile = await this.loadProfile();
|
|
36
36
|
if (profile.authType !== void 0) return this.resolveByAuthType(profile, profile.authType);
|
|
37
37
|
for (const strategy of this.strategies) {
|
|
38
|
+
if (profile.groupId !== void 0 && profile.groupId !== "" && !strategy.supportsGroupAssumption) continue;
|
|
38
39
|
const built = strategy.configure(profile);
|
|
39
40
|
if (built !== void 0) return built;
|
|
40
41
|
}
|
|
@@ -43,6 +44,7 @@ var DefaultCredentials = class {
|
|
|
43
44
|
resolveByAuthType(profile, authType) {
|
|
44
45
|
const strategy = this.strategies.find((s) => s.name === authType);
|
|
45
46
|
if (strategy === void 0) throw new DefaultCredentialsError("AUTH_TYPE_NOT_FOUND", `auth type "${authType}" not found, please check ${AUTH_DOC_URL} for a list of supported auth types`);
|
|
47
|
+
if (profile.groupId !== void 0 && profile.groupId !== "" && !strategy.supportsGroupAssumption) throw new DefaultCredentialsError("GROUP_ROLE_UNSUPPORTED", `auth type "${authType}" does not support group role assumption. Use OAuth M2M or Workload Identity Federation`);
|
|
46
48
|
const built = strategy.configure(profile);
|
|
47
49
|
if (built === void 0) throw new DefaultCredentialsError("NO_AUTH_CONFIGURED", NO_AUTH_CONFIGURED_MESSAGE);
|
|
48
50
|
return built;
|
|
@@ -51,6 +53,7 @@ var DefaultCredentials = class {
|
|
|
51
53
|
/** PAT strategy: configured when `token` is set in the profile. */
|
|
52
54
|
const patStrategy = {
|
|
53
55
|
name: "pat",
|
|
56
|
+
supportsGroupAssumption: false,
|
|
54
57
|
configure: (profile) => {
|
|
55
58
|
if (profile.host === void 0) return void 0;
|
|
56
59
|
if (profile.token === void 0) return void 0;
|
|
@@ -63,6 +66,7 @@ const patStrategy = {
|
|
|
63
66
|
*/
|
|
64
67
|
const m2mStrategy = {
|
|
65
68
|
name: "oauth-m2m",
|
|
69
|
+
supportsGroupAssumption: true,
|
|
66
70
|
configure: (profile) => {
|
|
67
71
|
if (profile.host === void 0) return void 0;
|
|
68
72
|
if (profile.clientId === void 0) return void 0;
|
|
@@ -71,7 +75,8 @@ const m2mStrategy = {
|
|
|
71
75
|
host: profile.host,
|
|
72
76
|
clientId: profile.clientId,
|
|
73
77
|
clientSecret: profile.clientSecret.value,
|
|
74
|
-
...profile.accountId !== void 0 && { accountId: profile.accountId }
|
|
78
|
+
...profile.accountId !== void 0 && { accountId: profile.accountId },
|
|
79
|
+
...profile.groupId !== void 0 && { groupId: profile.groupId }
|
|
75
80
|
});
|
|
76
81
|
}
|
|
77
82
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain.js","names":[],"sources":["../../../src/credentials/default/chain.ts"],"sourcesContent":["import type {Profile} from '@databricks/sdk-core/profiles';\n\nimport type {Credentials, Header} from '../../auth';\nimport {newM2mCredentials} from '../m2m';\nimport {newPatCredentials} from '../pat';\n\nimport {DefaultCredentialsError} from './errors';\n\n/**\n * A named strategy that inspects a profile and either returns configured\n * credentials or `undefined` if it is not applicable. The `name` matches the\n * `name()` of the credentials it produces, so it can be selected by a\n * profile's `authType`.\n */\nexport interface Strategy {\n /** Short identifier, e.g. `pat`, `oauth-m2m`, or `databricks-cli`. */\n readonly name: string;\n readonly configure: (profile: Profile) => Credentials | undefined;\n}\n\nconst AUTH_DOC_URL = 'https://docs.databricks.com/aws/en/dev-tools/auth/index';\nconst NO_AUTH_CONFIGURED_MESSAGE = `cannot configure default credentials, please check ${AUTH_DOC_URL} to configure credentials for your preferred authentication method`;\n\n/**\n * Lazy {@link Credentials} that resolves to a configured strategy on the\n * first `authHeaders()` call.\n *\n * If the profile sets `authType`, the strategy whose name matches it is\n * selected. Otherwise the strategies are tried in order and the first\n * configured one wins.\n */\nexport class DefaultCredentials implements Credentials {\n private resolved: Credentials | undefined;\n\n constructor(\n private readonly strategies: readonly Strategy[],\n private readonly loadProfile: () => Promise<Profile>\n ) {}\n\n /**\n * Returns `default` until a strategy has been resolved, then delegates to\n * the resolved strategy so callers (logging, telemetry) can tell which\n * authentication method won.\n */\n name(): string {\n return this.resolved?.name() ?? 'default';\n }\n\n async authHeaders(): Promise<Header[]> {\n this.resolved ??= await this.resolveChain();\n return this.resolved.authHeaders();\n }\n\n private async resolveChain(): Promise<Credentials> {\n const profile = await this.loadProfile();\n if (profile.authType !== undefined) {\n return this.resolveByAuthType(profile, profile.authType);\n }\n for (const strategy of this.strategies) {\n const built = strategy.configure(profile);\n if (built !== undefined) {\n return built;\n }\n }\n throw new DefaultCredentialsError(\n 'NO_AUTH_CONFIGURED',\n NO_AUTH_CONFIGURED_MESSAGE\n );\n }\n\n private resolveByAuthType(profile: Profile, authType: string): Credentials {\n const strategy = this.strategies.find(s => s.name === authType);\n if (strategy === undefined) {\n throw new DefaultCredentialsError(\n 'AUTH_TYPE_NOT_FOUND',\n `auth type \"${authType}\" not found, please check ${AUTH_DOC_URL} for a list of supported auth types`\n );\n }\n const built = strategy.configure(profile);\n if (built === undefined) {\n throw new DefaultCredentialsError(\n 'NO_AUTH_CONFIGURED',\n NO_AUTH_CONFIGURED_MESSAGE\n );\n }\n return built;\n }\n}\n\n/** PAT strategy: configured when `token` is set in the profile. */\nexport const patStrategy: Strategy = {\n name: 'pat',\n configure: profile => {\n if (profile.host === undefined) return undefined;\n if (profile.token === undefined) return undefined;\n return newPatCredentials(profile.token.value);\n },\n};\n\n/**\n * OAuth M2M strategy: configured when `clientId` and `clientSecret` are\n * both set in the profile.\n */\nexport const m2mStrategy: Strategy = {\n name: 'oauth-m2m',\n configure: profile => {\n if (profile.host === undefined) return undefined;\n if (profile.clientId === undefined) return undefined;\n if (profile.clientSecret === undefined) return undefined;\n return newM2mCredentials({\n host: profile.host,\n clientId: profile.clientId,\n clientSecret: profile.clientSecret.value,\n ...(profile.accountId !== undefined && {accountId: profile.accountId}),\n });\n },\n};\n"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"chain.js","names":[],"sources":["../../../src/credentials/default/chain.ts"],"sourcesContent":["import type {Profile} from '@databricks/sdk-core/profiles';\n\nimport type {Credentials, Header} from '../../auth';\nimport {newM2mCredentials} from '../m2m';\nimport {newPatCredentials} from '../pat';\n\nimport {DefaultCredentialsError} from './errors';\n\n/**\n * A named strategy that inspects a profile and either returns configured\n * credentials or `undefined` if it is not applicable. The `name` matches the\n * `name()` of the credentials it produces, so it can be selected by a\n * profile's `authType`.\n */\nexport interface Strategy {\n /** Short identifier, e.g. `pat`, `oauth-m2m`, or `databricks-cli`. */\n readonly name: string;\n /** Whether this strategy can request credentials for an assumed group. */\n readonly supportsGroupAssumption: boolean;\n readonly configure: (profile: Profile) => Credentials | undefined;\n}\n\nconst AUTH_DOC_URL = 'https://docs.databricks.com/aws/en/dev-tools/auth/index';\nconst NO_AUTH_CONFIGURED_MESSAGE = `cannot configure default credentials, please check ${AUTH_DOC_URL} to configure credentials for your preferred authentication method`;\n\n/**\n * Lazy {@link Credentials} that resolves to a configured strategy on the\n * first `authHeaders()` call.\n *\n * If the profile sets `authType`, the strategy whose name matches it is\n * selected. Otherwise the strategies are tried in order and the first\n * configured one wins.\n */\nexport class DefaultCredentials implements Credentials {\n private resolved: Credentials | undefined;\n\n constructor(\n private readonly strategies: readonly Strategy[],\n private readonly loadProfile: () => Promise<Profile>\n ) {}\n\n /**\n * Returns `default` until a strategy has been resolved, then delegates to\n * the resolved strategy so callers (logging, telemetry) can tell which\n * authentication method won.\n */\n name(): string {\n return this.resolved?.name() ?? 'default';\n }\n\n async authHeaders(): Promise<Header[]> {\n this.resolved ??= await this.resolveChain();\n return this.resolved.authHeaders();\n }\n\n private async resolveChain(): Promise<Credentials> {\n const profile = await this.loadProfile();\n if (profile.authType !== undefined) {\n return this.resolveByAuthType(profile, profile.authType);\n }\n for (const strategy of this.strategies) {\n if (\n profile.groupId !== undefined &&\n profile.groupId !== '' &&\n !strategy.supportsGroupAssumption\n ) {\n continue;\n }\n const built = strategy.configure(profile);\n if (built !== undefined) {\n return built;\n }\n }\n throw new DefaultCredentialsError(\n 'NO_AUTH_CONFIGURED',\n NO_AUTH_CONFIGURED_MESSAGE\n );\n }\n\n private resolveByAuthType(profile: Profile, authType: string): Credentials {\n const strategy = this.strategies.find(s => s.name === authType);\n if (strategy === undefined) {\n throw new DefaultCredentialsError(\n 'AUTH_TYPE_NOT_FOUND',\n `auth type \"${authType}\" not found, please check ${AUTH_DOC_URL} for a list of supported auth types`\n );\n }\n if (\n profile.groupId !== undefined &&\n profile.groupId !== '' &&\n !strategy.supportsGroupAssumption\n ) {\n throw new DefaultCredentialsError(\n 'GROUP_ROLE_UNSUPPORTED',\n `auth type \"${authType}\" does not support group role assumption. Use OAuth M2M or Workload Identity Federation`\n );\n }\n const built = strategy.configure(profile);\n if (built === undefined) {\n throw new DefaultCredentialsError(\n 'NO_AUTH_CONFIGURED',\n NO_AUTH_CONFIGURED_MESSAGE\n );\n }\n return built;\n }\n}\n\n/** PAT strategy: configured when `token` is set in the profile. */\nexport const patStrategy: Strategy = {\n name: 'pat',\n supportsGroupAssumption: false,\n configure: profile => {\n if (profile.host === undefined) return undefined;\n if (profile.token === undefined) return undefined;\n return newPatCredentials(profile.token.value);\n },\n};\n\n/**\n * OAuth M2M strategy: configured when `clientId` and `clientSecret` are\n * both set in the profile.\n */\nexport const m2mStrategy: Strategy = {\n name: 'oauth-m2m',\n supportsGroupAssumption: true,\n configure: profile => {\n if (profile.host === undefined) return undefined;\n if (profile.clientId === undefined) return undefined;\n if (profile.clientSecret === undefined) return undefined;\n return newM2mCredentials({\n host: profile.host,\n clientId: profile.clientId,\n clientSecret: profile.clientSecret.value,\n ...(profile.accountId !== undefined && {accountId: profile.accountId}),\n ...(profile.groupId !== undefined && {groupId: profile.groupId}),\n });\n },\n};\n"],"mappings":";;;;;AAsBA,MAAM,eAAe;AACrB,MAAM,6BAA6B,sDAAsD,aAAa;;;;;;;;;AAUtG,IAAa,qBAAb,MAAuD;CACrD,AAAQ;CAER,YACE,AAAiB,YACjB,AAAiB,aACjB;EAFiB;EACA;;;;;;;CAQnB,OAAe;AACb,SAAO,KAAK,UAAU,MAAM,IAAI;;CAGlC,MAAM,cAAiC;AACrC,OAAK,aAAa,MAAM,KAAK,cAAc;AAC3C,SAAO,KAAK,SAAS,aAAa;;CAGpC,MAAc,eAAqC;EACjD,MAAM,UAAU,MAAM,KAAK,aAAa;AACxC,MAAI,QAAQ,aAAa,OACvB,QAAO,KAAK,kBAAkB,SAAS,QAAQ,SAAS;AAE1D,OAAK,MAAM,YAAY,KAAK,YAAY;AACtC,OACE,QAAQ,YAAY,UACpB,QAAQ,YAAY,MACpB,CAAC,SAAS,wBAEV;GAEF,MAAM,QAAQ,SAAS,UAAU,QAAQ;AACzC,OAAI,UAAU,OACZ,QAAO;;AAGX,QAAM,IAAI,wBACR,sBACA,2BACD;;CAGH,AAAQ,kBAAkB,SAAkB,UAA+B;EACzE,MAAM,WAAW,KAAK,WAAW,MAAK,MAAK,EAAE,SAAS,SAAS;AAC/D,MAAI,aAAa,OACf,OAAM,IAAI,wBACR,uBACA,cAAc,SAAS,4BAA4B,aAAa,qCACjE;AAEH,MACE,QAAQ,YAAY,UACpB,QAAQ,YAAY,MACpB,CAAC,SAAS,wBAEV,OAAM,IAAI,wBACR,0BACA,cAAc,SAAS,yFACxB;EAEH,MAAM,QAAQ,SAAS,UAAU,QAAQ;AACzC,MAAI,UAAU,OACZ,OAAM,IAAI,wBACR,sBACA,2BACD;AAEH,SAAO;;;;AAKX,MAAa,cAAwB;CACnC,MAAM;CACN,yBAAyB;CACzB,YAAW,YAAW;AACpB,MAAI,QAAQ,SAAS,OAAW,QAAO;AACvC,MAAI,QAAQ,UAAU,OAAW,QAAO;AACxC,SAAO,kBAAkB,QAAQ,MAAM,MAAM;;CAEhD;;;;;AAMD,MAAa,cAAwB;CACnC,MAAM;CACN,yBAAyB;CACzB,YAAW,YAAW;AACpB,MAAI,QAAQ,SAAS,OAAW,QAAO;AACvC,MAAI,QAAQ,aAAa,OAAW,QAAO;AAC3C,MAAI,QAAQ,iBAAiB,OAAW,QAAO;AAC/C,SAAO,kBAAkB;GACvB,MAAM,QAAQ;GACd,UAAU,QAAQ;GAClB,cAAc,QAAQ,aAAa;GACnC,GAAI,QAAQ,cAAc,UAAa,EAAC,WAAW,QAAQ,WAAU;GACrE,GAAI,QAAQ,YAAY,UAAa,EAAC,SAAS,QAAQ,SAAQ;GAChE,CAAC;;CAEL"}
|
|
@@ -18,6 +18,10 @@ interface DefaultCredentialsOptions {
|
|
|
18
18
|
* 2. OAuth M2M (`oauth-m2m`).
|
|
19
19
|
* 3. Databricks CLI (`databricks-cli`).
|
|
20
20
|
*
|
|
21
|
+
* When the resolved profile contains a non-empty group ID, strategies that
|
|
22
|
+
* cannot assume a group are skipped. Explicitly selecting such a strategy
|
|
23
|
+
* through `authType` returns an error.
|
|
24
|
+
*
|
|
21
25
|
* When no profile is provided via `options.profile`, the profile is
|
|
22
26
|
* resolved on first use from the default config file (~/.databrickscfg)
|
|
23
27
|
* and environment variables.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-credentials.d.ts","names":[],"sources":["../../../src/credentials/default/default-credentials.ts"],"mappings":";;;;UAWU,yBAAA;;AARkC;;;EAa1C,OAAA,GAAU,OAAA;AAAA;
|
|
1
|
+
{"version":3,"file":"default-credentials.d.ts","names":[],"sources":["../../../src/credentials/default/default-credentials.ts"],"mappings":";;;;UAWU,yBAAA;;AARkC;;;EAa1C,OAAA,GAAU,OAAA;AAAA;AAoBZ;;;;;;;;;;;;;;;;;AAAA,iBAAgB,kBAAA,CACd,OAAA,GAAU,yBAAA,GACT,WAAA"}
|
|
@@ -17,6 +17,10 @@ const STRATEGIES = [
|
|
|
17
17
|
* 2. OAuth M2M (`oauth-m2m`).
|
|
18
18
|
* 3. Databricks CLI (`databricks-cli`).
|
|
19
19
|
*
|
|
20
|
+
* When the resolved profile contains a non-empty group ID, strategies that
|
|
21
|
+
* cannot assume a group are skipped. Explicitly selecting such a strategy
|
|
22
|
+
* through `authType` returns an error.
|
|
23
|
+
*
|
|
20
24
|
* When no profile is provided via `options.profile`, the profile is
|
|
21
25
|
* resolved on first use from the default config file (~/.databrickscfg)
|
|
22
26
|
* and environment variables.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"default-credentials.js","names":[],"sources":["../../../src/credentials/default/default-credentials.ts"],"sourcesContent":["import type {Profile} from '@databricks/sdk-core/profiles';\nimport {resolve} from '@databricks/sdk-core/profiles';\n\nimport type {Credentials} from '../../auth';\n\nimport {DefaultCredentials, m2mStrategy, patStrategy} from './chain';\nimport type {Strategy} from './chain';\nimport {u2mStrategy} from './u2m-strategy';\n\nconst STRATEGIES: readonly Strategy[] = [patStrategy, m2mStrategy, u2mStrategy];\n\ninterface DefaultCredentialsOptions {\n /**\n * Pre-resolved profile. When omitted, the profile is resolved on first\n * use from the default config file and environment variables.\n */\n profile?: Profile;\n}\n\n/**\n * Returns a lazy {@link Credentials} that resolves to the first configured\n * authentication strategy on first use.\n *\n * Strategies are tried in this order:\n * 1. PAT (`pat`).\n * 2. OAuth M2M (`oauth-m2m`).\n * 3. Databricks CLI (`databricks-cli`).\n *\n * When no profile is provided via `options.profile`, the profile is\n * resolved on first use from the default config file (~/.databrickscfg)\n * and environment variables.\n */\nexport function defaultCredentials(\n options?: DefaultCredentialsOptions\n): Credentials {\n const explicit = options?.profile;\n const loadProfile = (): Promise<Profile> =>\n explicit !== undefined ? Promise.resolve(explicit) : resolve();\n return new DefaultCredentials(STRATEGIES, loadProfile);\n}\n"],"mappings":";;;;;AASA,MAAM,aAAkC;CAAC;CAAa;CAAa;CAAY
|
|
1
|
+
{"version":3,"file":"default-credentials.js","names":[],"sources":["../../../src/credentials/default/default-credentials.ts"],"sourcesContent":["import type {Profile} from '@databricks/sdk-core/profiles';\nimport {resolve} from '@databricks/sdk-core/profiles';\n\nimport type {Credentials} from '../../auth';\n\nimport {DefaultCredentials, m2mStrategy, patStrategy} from './chain';\nimport type {Strategy} from './chain';\nimport {u2mStrategy} from './u2m-strategy';\n\nconst STRATEGIES: readonly Strategy[] = [patStrategy, m2mStrategy, u2mStrategy];\n\ninterface DefaultCredentialsOptions {\n /**\n * Pre-resolved profile. When omitted, the profile is resolved on first\n * use from the default config file and environment variables.\n */\n profile?: Profile;\n}\n\n/**\n * Returns a lazy {@link Credentials} that resolves to the first configured\n * authentication strategy on first use.\n *\n * Strategies are tried in this order:\n * 1. PAT (`pat`).\n * 2. OAuth M2M (`oauth-m2m`).\n * 3. Databricks CLI (`databricks-cli`).\n *\n * When the resolved profile contains a non-empty group ID, strategies that\n * cannot assume a group are skipped. Explicitly selecting such a strategy\n * through `authType` returns an error.\n *\n * When no profile is provided via `options.profile`, the profile is\n * resolved on first use from the default config file (~/.databrickscfg)\n * and environment variables.\n */\nexport function defaultCredentials(\n options?: DefaultCredentialsOptions\n): Credentials {\n const explicit = options?.profile;\n const loadProfile = (): Promise<Profile> =>\n explicit !== undefined ? Promise.resolve(explicit) : resolve();\n return new DefaultCredentials(STRATEGIES, loadProfile);\n}\n"],"mappings":";;;;;AASA,MAAM,aAAkC;CAAC;CAAa;CAAa;CAAY;;;;;;;;;;;;;;;;;;AA2B/E,SAAgB,mBACd,SACa;CACb,MAAM,WAAW,SAAS;CAC1B,MAAM,oBACJ,aAAa,SAAY,QAAQ,QAAQ,SAAS,GAAG,SAAS;AAChE,QAAO,IAAI,mBAAmB,YAAY,YAAY"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#region src/credentials/default/errors.d.ts
|
|
2
2
|
/** Discriminant codes for {@link DefaultCredentialsError}. */
|
|
3
|
-
type DefaultCredentialsErrorCode = 'NO_AUTH_CONFIGURED' | 'AUTH_TYPE_NOT_FOUND';
|
|
3
|
+
type DefaultCredentialsErrorCode = 'NO_AUTH_CONFIGURED' | 'AUTH_TYPE_NOT_FOUND' | 'GROUP_ROLE_UNSUPPORTED';
|
|
4
4
|
/**
|
|
5
5
|
* Error thrown when the default credentials chain cannot resolve a
|
|
6
6
|
* strategy to authenticate with.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","names":[],"sources":["../../../src/credentials/default/errors.ts"],"mappings":";;KACY,2BAAA;;;;;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","names":[],"sources":["../../../src/credentials/default/errors.ts"],"mappings":";;KACY,2BAAA;;;;;AAWZ;;cAAa,uBAAA,SAAgC,KAAA;EAAA,SAClC,IAAA,EAAM,2BAAA;cAEH,IAAA,EAAM,2BAAA,EAA6B,OAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","names":[],"sources":["../../../src/credentials/default/errors.ts"],"sourcesContent":["/** Discriminant codes for {@link DefaultCredentialsError}. */\nexport type DefaultCredentialsErrorCode =\n | 'NO_AUTH_CONFIGURED'\n | 'AUTH_TYPE_NOT_FOUND';\n\n/**\n * Error thrown when the default credentials chain cannot resolve a\n * strategy to authenticate with.\n *\n * Use the `code` field to distinguish between error causes.\n */\nexport class DefaultCredentialsError extends Error {\n readonly code: DefaultCredentialsErrorCode;\n\n constructor(code: DefaultCredentialsErrorCode, message: string) {\n super(message);\n this.name = 'DefaultCredentialsError';\n this.code = code;\n }\n}\n"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../../../src/credentials/default/errors.ts"],"sourcesContent":["/** Discriminant codes for {@link DefaultCredentialsError}. */\nexport type DefaultCredentialsErrorCode =\n | 'NO_AUTH_CONFIGURED'\n | 'AUTH_TYPE_NOT_FOUND'\n | 'GROUP_ROLE_UNSUPPORTED';\n\n/**\n * Error thrown when the default credentials chain cannot resolve a\n * strategy to authenticate with.\n *\n * Use the `code` field to distinguish between error causes.\n */\nexport class DefaultCredentialsError extends Error {\n readonly code: DefaultCredentialsErrorCode;\n\n constructor(code: DefaultCredentialsErrorCode, message: string) {\n super(message);\n this.name = 'DefaultCredentialsError';\n this.code = code;\n }\n}\n"],"mappings":";;;;;;;AAYA,IAAa,0BAAb,cAA6C,MAAM;CACjD,AAAS;CAET,YAAY,MAAmC,SAAiB;AAC9D,QAAM,QAAQ;AACd,OAAK,OAAO;AACZ,OAAK,OAAO"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"u2m-strategy.js","names":[],"sources":["../../../src/credentials/default/u2m-strategy.ts"],"sourcesContent":["import {newU2mCredentials} from '../u2m';\n\nimport type {Strategy} from './chain';\n\n/**\n * U2M (Databricks CLI) strategy. Configured when the profile was loaded\n * from the config file (so the section name is known) and a host is set.\n * The CLI must have been logged in ahead of time via `databricks auth\n * login`.\n */\nexport const u2mStrategy: Strategy = {\n name: 'databricks-cli',\n configure: profile => {\n if (profile.host === undefined) return undefined;\n if (profile.name === undefined) return undefined;\n return newU2mCredentials({\n profile: profile.name,\n ...(profile.databricksCliPath !== undefined && {\n cliPath: profile.databricksCliPath,\n }),\n });\n },\n};\n"],"mappings":";;;;;;;;;AAUA,MAAa,cAAwB;CACnC,MAAM;CACN,YAAW,YAAW;AACpB,MAAI,QAAQ,SAAS,OAAW,QAAO;AACvC,MAAI,QAAQ,SAAS,OAAW,QAAO;AACvC,SAAO,kBAAkB;GACvB,SAAS,QAAQ;GACjB,GAAI,QAAQ,sBAAsB,UAAa,EAC7C,SAAS,QAAQ,mBAClB;GACF,CAAC;;CAEL"}
|
|
1
|
+
{"version":3,"file":"u2m-strategy.js","names":[],"sources":["../../../src/credentials/default/u2m-strategy.ts"],"sourcesContent":["import {newU2mCredentials} from '../u2m';\n\nimport type {Strategy} from './chain';\n\n/**\n * U2M (Databricks CLI) strategy. Configured when the profile was loaded\n * from the config file (so the section name is known) and a host is set.\n * The CLI must have been logged in ahead of time via `databricks auth\n * login`.\n */\nexport const u2mStrategy: Strategy = {\n name: 'databricks-cli',\n supportsGroupAssumption: false,\n configure: profile => {\n if (profile.host === undefined) return undefined;\n if (profile.name === undefined) return undefined;\n return newU2mCredentials({\n profile: profile.name,\n ...(profile.databricksCliPath !== undefined && {\n cliPath: profile.databricksCliPath,\n }),\n });\n },\n};\n"],"mappings":";;;;;;;;;AAUA,MAAa,cAAwB;CACnC,MAAM;CACN,yBAAyB;CACzB,YAAW,YAAW;AACpB,MAAI,QAAQ,SAAS,OAAW,QAAO;AACvC,MAAI,QAAQ,SAAS,OAAW,QAAO;AACvC,SAAO,kBAAkB;GACvB,SAAS,QAAQ;GACjB,GAAI,QAAQ,sBAAsB,UAAa,EAC7C,SAAS,QAAQ,mBAClB;GACF,CAAC;;CAEL"}
|
|
@@ -20,6 +20,11 @@ interface M2mCredentialsOptions {
|
|
|
20
20
|
* Databricks account ID. Required for account hosts.
|
|
21
21
|
*/
|
|
22
22
|
accountId?: string;
|
|
23
|
+
/**
|
|
24
|
+
* ID of the group whose role is assumed by the issued token. When omitted
|
|
25
|
+
* or empty, no group role is assumed.
|
|
26
|
+
*/
|
|
27
|
+
groupId?: string;
|
|
23
28
|
/**
|
|
24
29
|
* OAuth scopes to request. When omitted or empty, defaults to
|
|
25
30
|
* `['all-apis']`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"m2m.d.ts","names":[],"sources":["../../src/credentials/m2m.ts"],"mappings":";;;;UAaiB,qBAAA;EAAqB;;;;EAKpC,IAAA;EAqBA;;;EAhBA,QAAA;
|
|
1
|
+
{"version":3,"file":"m2m.d.ts","names":[],"sources":["../../src/credentials/m2m.ts"],"mappings":";;;;UAaiB,qBAAA;EAAqB;;;;EAKpC,IAAA;EAqBA;;;EAhBA,QAAA;EAoCc;;;EA/Bd,YAAA;EAgCS;;;EA3BT,SAAA;EA4BiB;;;;EAtBjB,OAAA;;;;;EAMA,MAAA;AAAA;;;;;;;;;;iBAcc,iBAAA,CACd,OAAA,EAAS,qBAAA,GACR,gBAAA"}
|
package/dist/credentials/m2m.js
CHANGED
|
@@ -22,10 +22,12 @@ function newM2mCredentials(options) {
|
|
|
22
22
|
if (options.clientSecret === "") throw new M2mCredentialsError("CLIENT_SECRET_REQUIRED", "clientSecret is required");
|
|
23
23
|
if (options.host === "") throw new M2mCredentialsError("HOST_REQUIRED", "host is required");
|
|
24
24
|
const scopes = options.scopes !== void 0 && options.scopes.length > 0 ? options.scopes : DEFAULT_SCOPES;
|
|
25
|
-
const
|
|
25
|
+
const params = new URLSearchParams({
|
|
26
26
|
grant_type: "client_credentials",
|
|
27
27
|
scope: scopes.join(" ")
|
|
28
|
-
})
|
|
28
|
+
});
|
|
29
|
+
if (options.groupId !== void 0 && options.groupId !== "") params.set("assume_group", options.groupId);
|
|
30
|
+
const body = params.toString();
|
|
29
31
|
const basicAuth = btoa(`${encodeURIComponent(options.clientId)}:${encodeURIComponent(options.clientSecret)}`);
|
|
30
32
|
let cachedTokenEndpoint;
|
|
31
33
|
const getTokenEndpoint = async () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"m2m.js","names":[],"sources":["../../src/credentials/m2m.ts"],"sourcesContent":["/**\n * Machine-to-machine (M2M) OAuth credentials for the Databricks SDK.\n */\n\nimport {z} from 'zod';\n\nimport type {Token, TokenCredentials} from '../auth';\nimport {newTokenCredentials, tokenProviderFn} from '../auth';\n\nimport {M2mCredentialsError} from './errors';\nimport {resolveTokenEndpoint} from './host-metadata';\n\n/** Options for {@link newM2mCredentials}. */\nexport interface M2mCredentialsOptions {\n /**\n * Databricks host (workspace or account) used to discover the OAuth token\n * endpoint.\n */\n host: string;\n\n /**\n * OAuth client ID issued to the service principal.\n */\n clientId: string;\n\n /**\n * OAuth client secret issued to the service principal.\n */\n clientSecret: string;\n\n /**\n * Databricks account ID. Required for account hosts.\n */\n accountId?: string;\n\n /**\n * OAuth scopes to request. When omitted or empty, defaults to\n * `['all-apis']`.\n */\n scopes?: string[];\n}\n\nconst DEFAULT_SCOPES: readonly string[] = ['all-apis'];\n\n/**\n * Creates a TokenCredentials that authenticates as a Databricks service\n * principal using the OAuth client credentials grant.\n *\n * @param options - Host plus client credentials.\n * @throws M2mCredentialsError when host, clientId, or clientSecret is empty,\n * when token-endpoint discovery fails, or when the token endpoint returns\n * an error.\n */\nexport function newM2mCredentials(\n options: M2mCredentialsOptions\n): TokenCredentials {\n if (options.clientId === '') {\n throw new M2mCredentialsError('CLIENT_ID_REQUIRED', 'clientId is required');\n }\n if (options.clientSecret === '') {\n throw new M2mCredentialsError(\n 'CLIENT_SECRET_REQUIRED',\n 'clientSecret is required'\n );\n }\n if (options.host === '') {\n throw new M2mCredentialsError('HOST_REQUIRED', 'host is required');\n }\n\n const scopes =\n options.scopes !== undefined && options.scopes.length > 0\n ? options.scopes\n : DEFAULT_SCOPES;\n\n const
|
|
1
|
+
{"version":3,"file":"m2m.js","names":[],"sources":["../../src/credentials/m2m.ts"],"sourcesContent":["/**\n * Machine-to-machine (M2M) OAuth credentials for the Databricks SDK.\n */\n\nimport {z} from 'zod';\n\nimport type {Token, TokenCredentials} from '../auth';\nimport {newTokenCredentials, tokenProviderFn} from '../auth';\n\nimport {M2mCredentialsError} from './errors';\nimport {resolveTokenEndpoint} from './host-metadata';\n\n/** Options for {@link newM2mCredentials}. */\nexport interface M2mCredentialsOptions {\n /**\n * Databricks host (workspace or account) used to discover the OAuth token\n * endpoint.\n */\n host: string;\n\n /**\n * OAuth client ID issued to the service principal.\n */\n clientId: string;\n\n /**\n * OAuth client secret issued to the service principal.\n */\n clientSecret: string;\n\n /**\n * Databricks account ID. Required for account hosts.\n */\n accountId?: string;\n\n /**\n * ID of the group whose role is assumed by the issued token. When omitted\n * or empty, no group role is assumed.\n */\n groupId?: string;\n\n /**\n * OAuth scopes to request. When omitted or empty, defaults to\n * `['all-apis']`.\n */\n scopes?: string[];\n}\n\nconst DEFAULT_SCOPES: readonly string[] = ['all-apis'];\n\n/**\n * Creates a TokenCredentials that authenticates as a Databricks service\n * principal using the OAuth client credentials grant.\n *\n * @param options - Host plus client credentials.\n * @throws M2mCredentialsError when host, clientId, or clientSecret is empty,\n * when token-endpoint discovery fails, or when the token endpoint returns\n * an error.\n */\nexport function newM2mCredentials(\n options: M2mCredentialsOptions\n): TokenCredentials {\n if (options.clientId === '') {\n throw new M2mCredentialsError('CLIENT_ID_REQUIRED', 'clientId is required');\n }\n if (options.clientSecret === '') {\n throw new M2mCredentialsError(\n 'CLIENT_SECRET_REQUIRED',\n 'clientSecret is required'\n );\n }\n if (options.host === '') {\n throw new M2mCredentialsError('HOST_REQUIRED', 'host is required');\n }\n\n const scopes =\n options.scopes !== undefined && options.scopes.length > 0\n ? options.scopes\n : DEFAULT_SCOPES;\n\n const params = new URLSearchParams({\n grant_type: 'client_credentials',\n scope: scopes.join(' '),\n });\n if (options.groupId !== undefined && options.groupId !== '') {\n params.set('assume_group', options.groupId);\n }\n const body = params.toString();\n\n // Client ID and secret are URL-encoded before Basic auth encoding to\n // avoid ambiguity with special characters in either value, matching the\n // behavior of golang.org/x/oauth2.\n const basicAuth = btoa(\n `${encodeURIComponent(options.clientId)}:${encodeURIComponent(options.clientSecret)}`\n );\n\n let cachedTokenEndpoint: string | undefined;\n const getTokenEndpoint = async (): Promise<string> => {\n if (cachedTokenEndpoint === undefined) {\n try {\n cachedTokenEndpoint = await resolveTokenEndpoint(\n options.host,\n options.accountId\n );\n } catch (e) {\n throw new M2mCredentialsError(\n 'DISCOVERY_FAILED',\n `discovering token endpoint failed: ${stringifyError(e)}`\n );\n }\n }\n return cachedTokenEndpoint;\n };\n\n const provider = tokenProviderFn(async () => {\n const tokenEndpoint = await getTokenEndpoint();\n return fetchAccessToken(tokenEndpoint, basicAuth, body);\n });\n\n return newTokenCredentials('oauth-m2m', provider);\n}\n\nasync function fetchAccessToken(\n tokenEndpoint: string,\n basicAuth: string,\n body: string\n): Promise<Token> {\n const response = await fetch(tokenEndpoint, {\n method: 'POST',\n headers: {\n Authorization: `Basic ${basicAuth}`,\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body,\n });\n if (!response.ok) {\n const text = await response.text();\n throw new M2mCredentialsError(\n 'TOKEN_REQUEST_FAILED',\n `token request failed with status ${response.status.toString()}: ${text}`\n );\n }\n const parsed = tokenResponseSchema.parse(await response.json());\n const expiry =\n parsed.expires_in !== undefined\n ? new Date(Date.now() + parsed.expires_in * 1000)\n : undefined;\n return {\n value: parsed.access_token,\n ...(parsed.token_type !== undefined && {type: parsed.token_type}),\n ...(expiry !== undefined && {expiry}),\n };\n}\n\nconst tokenResponseSchema = z.object({\n access_token: z.string(),\n token_type: z.string().optional(),\n expires_in: z.number().optional(),\n});\n\nfunction stringifyError(e: unknown): string {\n if (e instanceof Error) {\n return e.message;\n }\n return String(e);\n}\n"],"mappings":";;;;;;;;;AAgDA,MAAM,iBAAoC,CAAC,WAAW;;;;;;;;;;AAWtD,SAAgB,kBACd,SACkB;AAClB,KAAI,QAAQ,aAAa,GACvB,OAAM,IAAI,oBAAoB,sBAAsB,uBAAuB;AAE7E,KAAI,QAAQ,iBAAiB,GAC3B,OAAM,IAAI,oBACR,0BACA,2BACD;AAEH,KAAI,QAAQ,SAAS,GACnB,OAAM,IAAI,oBAAoB,iBAAiB,mBAAmB;CAGpE,MAAM,SACJ,QAAQ,WAAW,UAAa,QAAQ,OAAO,SAAS,IACpD,QAAQ,SACR;CAEN,MAAM,SAAS,IAAI,gBAAgB;EACjC,YAAY;EACZ,OAAO,OAAO,KAAK,IAAI;EACxB,CAAC;AACF,KAAI,QAAQ,YAAY,UAAa,QAAQ,YAAY,GACvD,QAAO,IAAI,gBAAgB,QAAQ,QAAQ;CAE7C,MAAM,OAAO,OAAO,UAAU;CAK9B,MAAM,YAAY,KAChB,GAAG,mBAAmB,QAAQ,SAAS,CAAC,GAAG,mBAAmB,QAAQ,aAAa,GACpF;CAED,IAAI;CACJ,MAAM,mBAAmB,YAA6B;AACpD,MAAI,wBAAwB,OAC1B,KAAI;AACF,yBAAsB,MAAM,qBAC1B,QAAQ,MACR,QAAQ,UACT;WACM,GAAG;AACV,SAAM,IAAI,oBACR,oBACA,sCAAsC,eAAe,EAAE,GACxD;;AAGL,SAAO;;AAQT,QAAO,oBAAoB,aALV,gBAAgB,YAAY;AAE3C,SAAO,iBADe,MAAM,kBAAkB,EACP,WAAW,KAAK;GACvD,CAE+C;;AAGnD,eAAe,iBACb,eACA,WACA,MACgB;CAChB,MAAM,WAAW,MAAM,MAAM,eAAe;EAC1C,QAAQ;EACR,SAAS;GACP,eAAe,SAAS;GACxB,gBAAgB;GACjB;EACD;EACD,CAAC;AACF,KAAI,CAAC,SAAS,IAAI;EAChB,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,QAAM,IAAI,oBACR,wBACA,oCAAoC,SAAS,OAAO,UAAU,CAAC,IAAI,OACpE;;CAEH,MAAM,SAAS,oBAAoB,MAAM,MAAM,SAAS,MAAM,CAAC;CAC/D,MAAM,SACJ,OAAO,eAAe,SAClB,IAAI,KAAK,KAAK,KAAK,GAAG,OAAO,aAAa,IAAK,GAC/C;AACN,QAAO;EACL,OAAO,OAAO;EACd,GAAI,OAAO,eAAe,UAAa,EAAC,MAAM,OAAO,YAAW;EAChE,GAAI,WAAW,UAAa,EAAC,QAAO;EACrC;;AAGH,MAAM,sBAAsB,EAAE,OAAO;CACnC,cAAc,EAAE,QAAQ;CACxB,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,YAAY,EAAE,QAAQ,CAAC,UAAU;CAClC,CAAC;AAEF,SAAS,eAAe,GAAoB;AAC1C,KAAI,aAAa,MACf,QAAO,EAAE;AAEX,QAAO,OAAO,EAAE"}
|
|
@@ -31,6 +31,11 @@ interface DatabricksOidcTokenProviderConfig {
|
|
|
31
31
|
* Host is the host of the Databricks account or workspace.
|
|
32
32
|
*/
|
|
33
33
|
host: string;
|
|
34
|
+
/**
|
|
35
|
+
* ID of the group whose role is assumed by the exchanged token. When
|
|
36
|
+
* omitted or empty, no group role is assumed.
|
|
37
|
+
*/
|
|
38
|
+
groupId?: string;
|
|
34
39
|
/**
|
|
35
40
|
* TokenEndpointProvider returns the token endpoint for the Databricks OIDC
|
|
36
41
|
* application.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokensource.d.ts","names":[],"sources":["../../src/oidc/tokensource.ts"],"mappings":";;;;;;;AAwBA;UARiB,wBAAA;EACf,aAAA;AAAA;;;;;UAOe,iCAAA;EAcf;;;;;;;EANA,QAAA;
|
|
1
|
+
{"version":3,"file":"tokensource.d.ts","names":[],"sources":["../../src/oidc/tokensource.ts"],"mappings":";;;;;;;AAwBA;UARiB,wBAAA;EACf,aAAA;AAAA;;;;;UAOe,iCAAA;EAcf;;;;;;;EANA,QAAA;EAkCiB;;;AAOnB;EAnCE,SAAA;;;;EAKA,IAAA;EAgCC;;;;EA1BD,OAAA;;;;;EAMA,qBAAA,QAA6B,OAAA,CAAQ,wBAAA;;;;;EAMrC,QAAA;;;;EAKA,eAAA,EAAiB,eAAA;AAAA;;;;;iBAOH,8BAAA,CACd,MAAA,EAAQ,iCAAA,GACP,aAAA"}
|
package/dist/oidc/tokensource.js
CHANGED
|
@@ -24,6 +24,7 @@ async function exchangeIdToken(config) {
|
|
|
24
24
|
params.set("subject_token_type", "urn:ietf:params:oauth:token-type:jwt");
|
|
25
25
|
params.set("subject_token", idToken.value);
|
|
26
26
|
params.set("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange");
|
|
27
|
+
if (config.groupId !== void 0 && config.groupId !== "") params.set("assume_group", config.groupId);
|
|
27
28
|
const response = await fetch(endpoints.tokenEndpoint, {
|
|
28
29
|
method: "POST",
|
|
29
30
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokensource.js","names":[],"sources":["../../src/oidc/tokensource.ts"],"sourcesContent":["/**\n * Databricks OIDC token-exchange provider. Exchanges an OIDC ID token for a\n * Databricks access token using the OAuth 2.0 token-exchange grant.\n */\n\nimport {z} from 'zod';\n\nimport type {Token, TokenProvider} from '../auth';\nimport {tokenProviderFn} from '../auth';\n\nimport type {IdTokenProvider} from './oidc';\n\n/**\n * OAuthAuthorizationServer describes the OAuth endpoints used to mint\n * Databricks access tokens.\n */\nexport interface OAuthAuthorizationServer {\n tokenEndpoint: string;\n}\n\n/**\n * DatabricksOidcTokenProviderConfig is the configuration for a Databricks OIDC\n * TokenProvider.\n */\nexport interface DatabricksOidcTokenProviderConfig {\n /**\n * Client ID of the Databricks OIDC application. It corresponds to the\n * Application ID of the Databricks Service Principal.\n *\n * This field is only required for Workload Identity Federation and should\n * be empty for Account-wide token federation.\n */\n clientId?: string;\n\n /**\n * Account ID of the Databricks Account. This field is only required for\n * Account-wide token federation.\n */\n accountId?: string;\n\n /**\n * Host is the host of the Databricks account or workspace.\n */\n host: string;\n\n /**\n * TokenEndpointProvider returns the token endpoint for the Databricks OIDC\n * application.\n */\n tokenEndpointProvider: () => Promise<OAuthAuthorizationServer>;\n\n /**\n * Audience is the audience of the Databricks OIDC application.\n * This is only used for Workspace level tokens.\n */\n audience?: string;\n\n /**\n * IdTokenProvider returns the ID token to be used for the token exchange.\n */\n idTokenProvider: IdTokenProvider;\n}\n\n/**\n * Returns a new Databricks OIDC TokenProvider that exchanges an OIDC ID token\n * for a Databricks access token using the OAuth 2.0 token-exchange grant.\n */\nexport function newDatabricksOidcTokenProvider(\n config: DatabricksOidcTokenProviderConfig\n): TokenProvider {\n return tokenProviderFn(() => exchangeIdToken(config));\n}\n\nasync function exchangeIdToken(\n config: DatabricksOidcTokenProviderConfig\n): Promise<Token> {\n if (config.host === '') {\n throw new Error('missing Host');\n }\n const endpoints = await config.tokenEndpointProvider();\n const audience = determineAudience(config, endpoints);\n const idToken = await config.idTokenProvider.idToken(audience);\n\n const params = new URLSearchParams();\n if (config.clientId !== undefined && config.clientId !== '') {\n params.set('client_id', config.clientId);\n }\n params.set('scope', 'all-apis');\n params.set('subject_token_type', 'urn:ietf:params:oauth:token-type:jwt');\n params.set('subject_token', idToken.value);\n params.set('grant_type', 'urn:ietf:params:oauth:grant-type:token-exchange');\n\n const response = await fetch(endpoints.tokenEndpoint, {\n method: 'POST',\n headers: {'Content-Type': 'application/x-www-form-urlencoded'},\n body: params.toString(),\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `token request failed with status ${response.status.toString()}: ${text}`\n );\n }\n const parsed = tokenResponseSchema.parse(await response.json());\n const expiry =\n parsed.expires_in !== undefined\n ? new Date(Date.now() + parsed.expires_in * 1000)\n : undefined;\n return {\n value: parsed.access_token,\n ...(parsed.token_type !== undefined && {type: parsed.token_type}),\n ...(expiry !== undefined && {expiry}),\n };\n}\n\nfunction determineAudience(\n config: DatabricksOidcTokenProviderConfig,\n endpoints: OAuthAuthorizationServer\n): string {\n if (config.audience !== undefined && config.audience !== '') {\n return config.audience;\n }\n if (config.accountId !== undefined && config.accountId !== '') {\n return config.accountId;\n }\n return endpoints.tokenEndpoint;\n}\n\nconst tokenResponseSchema = z.object({\n access_token: z.string(),\n token_type: z.string().optional(),\n expires_in: z.number().optional(),\n});\n"],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"tokensource.js","names":[],"sources":["../../src/oidc/tokensource.ts"],"sourcesContent":["/**\n * Databricks OIDC token-exchange provider. Exchanges an OIDC ID token for a\n * Databricks access token using the OAuth 2.0 token-exchange grant.\n */\n\nimport {z} from 'zod';\n\nimport type {Token, TokenProvider} from '../auth';\nimport {tokenProviderFn} from '../auth';\n\nimport type {IdTokenProvider} from './oidc';\n\n/**\n * OAuthAuthorizationServer describes the OAuth endpoints used to mint\n * Databricks access tokens.\n */\nexport interface OAuthAuthorizationServer {\n tokenEndpoint: string;\n}\n\n/**\n * DatabricksOidcTokenProviderConfig is the configuration for a Databricks OIDC\n * TokenProvider.\n */\nexport interface DatabricksOidcTokenProviderConfig {\n /**\n * Client ID of the Databricks OIDC application. It corresponds to the\n * Application ID of the Databricks Service Principal.\n *\n * This field is only required for Workload Identity Federation and should\n * be empty for Account-wide token federation.\n */\n clientId?: string;\n\n /**\n * Account ID of the Databricks Account. This field is only required for\n * Account-wide token federation.\n */\n accountId?: string;\n\n /**\n * Host is the host of the Databricks account or workspace.\n */\n host: string;\n\n /**\n * ID of the group whose role is assumed by the exchanged token. When\n * omitted or empty, no group role is assumed.\n */\n groupId?: string;\n\n /**\n * TokenEndpointProvider returns the token endpoint for the Databricks OIDC\n * application.\n */\n tokenEndpointProvider: () => Promise<OAuthAuthorizationServer>;\n\n /**\n * Audience is the audience of the Databricks OIDC application.\n * This is only used for Workspace level tokens.\n */\n audience?: string;\n\n /**\n * IdTokenProvider returns the ID token to be used for the token exchange.\n */\n idTokenProvider: IdTokenProvider;\n}\n\n/**\n * Returns a new Databricks OIDC TokenProvider that exchanges an OIDC ID token\n * for a Databricks access token using the OAuth 2.0 token-exchange grant.\n */\nexport function newDatabricksOidcTokenProvider(\n config: DatabricksOidcTokenProviderConfig\n): TokenProvider {\n return tokenProviderFn(() => exchangeIdToken(config));\n}\n\nasync function exchangeIdToken(\n config: DatabricksOidcTokenProviderConfig\n): Promise<Token> {\n if (config.host === '') {\n throw new Error('missing Host');\n }\n const endpoints = await config.tokenEndpointProvider();\n const audience = determineAudience(config, endpoints);\n const idToken = await config.idTokenProvider.idToken(audience);\n\n const params = new URLSearchParams();\n if (config.clientId !== undefined && config.clientId !== '') {\n params.set('client_id', config.clientId);\n }\n params.set('scope', 'all-apis');\n params.set('subject_token_type', 'urn:ietf:params:oauth:token-type:jwt');\n params.set('subject_token', idToken.value);\n params.set('grant_type', 'urn:ietf:params:oauth:grant-type:token-exchange');\n if (config.groupId !== undefined && config.groupId !== '') {\n params.set('assume_group', config.groupId);\n }\n\n const response = await fetch(endpoints.tokenEndpoint, {\n method: 'POST',\n headers: {'Content-Type': 'application/x-www-form-urlencoded'},\n body: params.toString(),\n });\n if (!response.ok) {\n const text = await response.text();\n throw new Error(\n `token request failed with status ${response.status.toString()}: ${text}`\n );\n }\n const parsed = tokenResponseSchema.parse(await response.json());\n const expiry =\n parsed.expires_in !== undefined\n ? new Date(Date.now() + parsed.expires_in * 1000)\n : undefined;\n return {\n value: parsed.access_token,\n ...(parsed.token_type !== undefined && {type: parsed.token_type}),\n ...(expiry !== undefined && {expiry}),\n };\n}\n\nfunction determineAudience(\n config: DatabricksOidcTokenProviderConfig,\n endpoints: OAuthAuthorizationServer\n): string {\n if (config.audience !== undefined && config.audience !== '') {\n return config.audience;\n }\n if (config.accountId !== undefined && config.accountId !== '') {\n return config.accountId;\n }\n return endpoints.tokenEndpoint;\n}\n\nconst tokenResponseSchema = z.object({\n access_token: z.string(),\n token_type: z.string().optional(),\n expires_in: z.number().optional(),\n});\n"],"mappings":";;;;;;;;;;;;AAyEA,SAAgB,+BACd,QACe;AACf,QAAO,sBAAsB,gBAAgB,OAAO,CAAC;;AAGvD,eAAe,gBACb,QACgB;AAChB,KAAI,OAAO,SAAS,GAClB,OAAM,IAAI,MAAM,eAAe;CAEjC,MAAM,YAAY,MAAM,OAAO,uBAAuB;CACtD,MAAM,WAAW,kBAAkB,QAAQ,UAAU;CACrD,MAAM,UAAU,MAAM,OAAO,gBAAgB,QAAQ,SAAS;CAE9D,MAAM,SAAS,IAAI,iBAAiB;AACpC,KAAI,OAAO,aAAa,UAAa,OAAO,aAAa,GACvD,QAAO,IAAI,aAAa,OAAO,SAAS;AAE1C,QAAO,IAAI,SAAS,WAAW;AAC/B,QAAO,IAAI,sBAAsB,uCAAuC;AACxE,QAAO,IAAI,iBAAiB,QAAQ,MAAM;AAC1C,QAAO,IAAI,cAAc,kDAAkD;AAC3E,KAAI,OAAO,YAAY,UAAa,OAAO,YAAY,GACrD,QAAO,IAAI,gBAAgB,OAAO,QAAQ;CAG5C,MAAM,WAAW,MAAM,MAAM,UAAU,eAAe;EACpD,QAAQ;EACR,SAAS,EAAC,gBAAgB,qCAAoC;EAC9D,MAAM,OAAO,UAAU;EACxB,CAAC;AACF,KAAI,CAAC,SAAS,IAAI;EAChB,MAAM,OAAO,MAAM,SAAS,MAAM;AAClC,QAAM,IAAI,MACR,oCAAoC,SAAS,OAAO,UAAU,CAAC,IAAI,OACpE;;CAEH,MAAM,SAAS,oBAAoB,MAAM,MAAM,SAAS,MAAM,CAAC;CAC/D,MAAM,SACJ,OAAO,eAAe,SAClB,IAAI,KAAK,KAAK,KAAK,GAAG,OAAO,aAAa,IAAK,GAC/C;AACN,QAAO;EACL,OAAO,OAAO;EACd,GAAI,OAAO,eAAe,UAAa,EAAC,MAAM,OAAO,YAAW;EAChE,GAAI,WAAW,UAAa,EAAC,QAAO;EACrC;;AAGH,SAAS,kBACP,QACA,WACQ;AACR,KAAI,OAAO,aAAa,UAAa,OAAO,aAAa,GACvD,QAAO,OAAO;AAEhB,KAAI,OAAO,cAAc,UAAa,OAAO,cAAc,GACzD,QAAO,OAAO;AAEhB,QAAO,UAAU;;AAGnB,MAAM,sBAAsB,EAAE,OAAO;CACnC,cAAc,EAAE,QAAQ;CACxB,YAAY,EAAE,QAAQ,CAAC,UAAU;CACjC,YAAY,EAAE,QAAQ,CAAC,UAAU;CAClC,CAAC"}
|
package/dist/package.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@databricks/sdk-auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0",
|
|
4
4
|
"description": "Databricks authentication library for JavaScript/TypeScript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"node": ">=22.0.0"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@databricks/sdk-core": ">=0.
|
|
56
|
+
"@databricks/sdk-core": ">=0.50.0 <1.0.0",
|
|
57
57
|
"zod": "^4.3.6"
|
|
58
58
|
}
|
|
59
59
|
}
|