@azure/communication-common 2.3.2-alpha.20250122.7 → 2.3.2-alpha.20250127.1
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/README.md +34 -49
- package/dist/browser/azureCommunicationTokenCredential.d.ts +0 -6
- package/dist/browser/azureCommunicationTokenCredential.d.ts.map +1 -1
- package/dist/browser/azureCommunicationTokenCredential.js +4 -8
- package/dist/browser/azureCommunicationTokenCredential.js.map +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/index.d.ts.map +1 -1
- package/dist/browser/index.js +1 -0
- package/dist/browser/index.js.map +1 -1
- package/dist/commonjs/azureCommunicationTokenCredential.d.ts +0 -6
- package/dist/commonjs/azureCommunicationTokenCredential.d.ts.map +1 -1
- package/dist/commonjs/azureCommunicationTokenCredential.js +4 -8
- package/dist/commonjs/azureCommunicationTokenCredential.js.map +1 -1
- package/dist/commonjs/index.d.ts +1 -1
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js +1 -0
- package/dist/commonjs/index.js.map +1 -1
- package/dist/esm/azureCommunicationTokenCredential.d.ts +0 -6
- package/dist/esm/azureCommunicationTokenCredential.d.ts.map +1 -1
- package/dist/esm/azureCommunicationTokenCredential.js +4 -8
- package/dist/esm/azureCommunicationTokenCredential.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/react-native/azureCommunicationTokenCredential.d.ts +0 -6
- package/dist/react-native/azureCommunicationTokenCredential.d.ts.map +1 -1
- package/dist/react-native/azureCommunicationTokenCredential.js +4 -8
- package/dist/react-native/azureCommunicationTokenCredential.js.map +1 -1
- package/dist/react-native/index.d.ts +1 -1
- package/dist/react-native/index.d.ts.map +1 -1
- package/dist/react-native/index.js +1 -0
- package/dist/react-native/index.js.map +1 -1
- package/package.json +11 -25
- package/dist/browser/entraTokenCredential.d.ts +0 -45
- package/dist/browser/entraTokenCredential.d.ts.map +0 -1
- package/dist/browser/entraTokenCredential.js +0 -120
- package/dist/browser/entraTokenCredential.js.map +0 -1
- package/dist/commonjs/entraTokenCredential.d.ts +0 -45
- package/dist/commonjs/entraTokenCredential.d.ts.map +0 -1
- package/dist/commonjs/entraTokenCredential.js +0 -124
- package/dist/commonjs/entraTokenCredential.js.map +0 -1
- package/dist/esm/entraTokenCredential.d.ts +0 -45
- package/dist/esm/entraTokenCredential.d.ts.map +0 -1
- package/dist/esm/entraTokenCredential.js +0 -120
- package/dist/esm/entraTokenCredential.js.map +0 -1
- package/dist/react-native/entraTokenCredential.d.ts +0 -45
- package/dist/react-native/entraTokenCredential.d.ts.map +0 -1
- package/dist/react-native/entraTokenCredential.js +0 -120
- package/dist/react-native/entraTokenCredential.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@azure/communication-common",
|
|
3
|
-
"version": "2.3.2-alpha.
|
|
3
|
+
"version": "2.3.2-alpha.20250127.1",
|
|
4
4
|
"description": "Common package for Azure Communication services.",
|
|
5
5
|
"sdk-type": "client",
|
|
6
6
|
"main": "./dist/commonjs/index.js",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"unit-test": "npm run unit-test:node && npm run unit-test:browser",
|
|
31
31
|
"unit-test:browser": "npm run clean && dev-tool run build-package && dev-tool run build-test && dev-tool run test:vitest --no-test-proxy --browser",
|
|
32
32
|
"unit-test:node": "dev-tool run test:vitest --no-test-proxy",
|
|
33
|
-
"update-snippets": "
|
|
33
|
+
"update-snippets": "dev-tool run update-snippets"
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
36
|
"dist/",
|
|
@@ -58,41 +58,27 @@
|
|
|
58
58
|
"prettier": "@azure/eslint-plugin-azure-sdk/prettier.json",
|
|
59
59
|
"dependencies": {
|
|
60
60
|
"@azure/abort-controller": "^2.1.2",
|
|
61
|
-
"@azure/core-auth": "^1.
|
|
62
|
-
"@azure
|
|
63
|
-
"@azure/core-rest-pipeline": "^1.17.0",
|
|
61
|
+
"@azure/core-auth": "^1.9.0",
|
|
62
|
+
"@azure/core-rest-pipeline": "^1.18.2",
|
|
64
63
|
"@azure/core-tracing": "^1.2.0",
|
|
65
|
-
"@azure/core-util": "^1.
|
|
66
|
-
"events": "^3.
|
|
64
|
+
"@azure/core-util": "^1.11.0",
|
|
65
|
+
"events": "^3.3.0",
|
|
67
66
|
"jwt-decode": "^4.0.0",
|
|
68
|
-
"tslib": "^2.
|
|
67
|
+
"tslib": "^2.8.1"
|
|
69
68
|
},
|
|
70
69
|
"devDependencies": {
|
|
71
70
|
"@azure-tools/test-utils-vitest": ">=1.0.0-alpha <1.0.0-alphb",
|
|
72
71
|
"@azure/dev-tool": ">=1.0.0-alpha <1.0.0-alphb",
|
|
73
|
-
"@azure/identity": "~4.3.0",
|
|
74
72
|
"@azure/eslint-plugin-azure-sdk": ">=3.0.0-alpha <3.0.0-alphb",
|
|
73
|
+
"@azure/logger": "^1.1.4",
|
|
75
74
|
"@types/node": "^18.0.0",
|
|
76
|
-
"@vitest/browser": "^
|
|
77
|
-
"@vitest/coverage-istanbul": "^
|
|
75
|
+
"@vitest/browser": "^3.0.3",
|
|
76
|
+
"@vitest/coverage-istanbul": "^3.0.3",
|
|
78
77
|
"eslint": "^9.9.0",
|
|
79
|
-
"inherits": "^2.0.3",
|
|
80
|
-
"karma": "^6.2.0",
|
|
81
|
-
"karma-chrome-launcher": "^3.0.0",
|
|
82
|
-
"karma-coverage": "^2.0.0",
|
|
83
|
-
"karma-env-preprocessor": "^0.1.1",
|
|
84
|
-
"karma-firefox-launcher": "^1.1.0",
|
|
85
|
-
"karma-junit-reporter": "^2.0.1",
|
|
86
|
-
"karma-mocha": "^2.0.1",
|
|
87
|
-
"karma-mocha-reporter": "^2.2.5",
|
|
88
|
-
"karma-sourcemap-loader": "^0.3.8",
|
|
89
|
-
"mocha": "^10.0.0",
|
|
90
|
-
"nock": "14.0.0-beta.7",
|
|
91
78
|
"mockdate": "^3.0.5",
|
|
92
79
|
"playwright": "^1.48.0",
|
|
93
80
|
"typescript": "~5.7.2",
|
|
94
|
-
"
|
|
95
|
-
"vitest": "^2.1.3"
|
|
81
|
+
"vitest": "^3.0.3"
|
|
96
82
|
},
|
|
97
83
|
"type": "module",
|
|
98
84
|
"tshy": {
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { type AccessToken } from "@azure/core-auth";
|
|
2
|
-
import { type TokenCredential } from "@azure/identity";
|
|
3
|
-
import { type TokenCredential as AcsTokenCredential, type CommunicationGetTokenOptions } from "./communicationTokenCredential.js";
|
|
4
|
-
export interface ExchangeTokenResponse {
|
|
5
|
-
identity: string;
|
|
6
|
-
accessToken: {
|
|
7
|
-
token: string;
|
|
8
|
-
expiresOn: string;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* The Entra Communication Token Options.
|
|
13
|
-
*/
|
|
14
|
-
export interface EntraCommunicationTokenCredentialOptions {
|
|
15
|
-
/**
|
|
16
|
-
* The Azure Communication Service resource endpoint URL, e.g. https://myResource.communication.azure.com.
|
|
17
|
-
*/
|
|
18
|
-
resourceEndpoint: string;
|
|
19
|
-
/**
|
|
20
|
-
* The Entra ID token credential.
|
|
21
|
-
*/
|
|
22
|
-
tokenCredential: TokenCredential;
|
|
23
|
-
/**
|
|
24
|
-
* The scopes for retrieving the Entra ID access token.
|
|
25
|
-
*/
|
|
26
|
-
scopes?: string[];
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Represents a credential that exchanges an Entra token for an Azure Communication Services (ACS) token, enabling access to ACS resources.
|
|
30
|
-
*/
|
|
31
|
-
export declare class EntraTokenCredential implements AcsTokenCredential {
|
|
32
|
-
private options;
|
|
33
|
-
private isPending;
|
|
34
|
-
private result;
|
|
35
|
-
private client;
|
|
36
|
-
private httpClient;
|
|
37
|
-
constructor(options: EntraCommunicationTokenCredentialOptions);
|
|
38
|
-
getToken(options?: CommunicationGetTokenOptions): Promise<AccessToken>;
|
|
39
|
-
private getTokenInternal;
|
|
40
|
-
dispose(): void;
|
|
41
|
-
private exchangeEntraToken;
|
|
42
|
-
private createRequestUri;
|
|
43
|
-
private determineEndpointAndApiVersion;
|
|
44
|
-
}
|
|
45
|
-
//# sourceMappingURL=entraTokenCredential.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"entraTokenCredential.d.ts","sourceRoot":"","sources":["../../src/entraTokenCredential.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EACL,KAAK,eAAe,IAAI,kBAAkB,EAC1C,KAAK,4BAA4B,EAClC,MAAM,mCAAmC,CAAC;AAiB3C,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE;QACX,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,wCAAwC;IACvD;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,eAAe,EAAE,eAAe,CAAC;IACjC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,oBAAqB,YAAW,kBAAkB;IASjD,OAAO,CAAC,OAAO;IAR3B,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,MAAM,CAGZ;IACF,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAa;gBAEX,OAAO,EAAE,wCAAwC;IAYxD,QAAQ,CAAC,OAAO,CAAC,EAAE,4BAA4B,GAAG,OAAO,CAAC,WAAW,CAAC;YAoBrE,gBAAgB;IAmCvB,OAAO,IAAI,IAAI;YAOR,kBAAkB;IA8BhC,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,8BAA8B;CAiBvC"}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import { getClient } from "@azure-rest/core-client";
|
|
4
|
-
import { createDefaultHttpClient, createHttpHeaders, createPipelineRequest, } from "@azure/core-rest-pipeline";
|
|
5
|
-
const TeamsExtensionScopePrefix = "https://auth.msft.communication.azure.com/";
|
|
6
|
-
const ComunicationClientsScopePrefix = "https://communication.azure.com/clients/";
|
|
7
|
-
const TeamsExtensionEndpoint = "/access/teamsPhone/:exchangeAccessToken";
|
|
8
|
-
const TeamsExtensionApiVersion = "2025-03-02-preview";
|
|
9
|
-
const ComunicationClientsEndpoint = "/access/entra/:exchangeAccessToken";
|
|
10
|
-
const ComunicationClientsApiVersion = "2024-04-01-preview";
|
|
11
|
-
/**
|
|
12
|
-
* Represents a credential that exchanges an Entra token for an Azure Communication Services (ACS) token, enabling access to ACS resources.
|
|
13
|
-
*/
|
|
14
|
-
export class EntraTokenCredential {
|
|
15
|
-
constructor(options) {
|
|
16
|
-
this.options = options;
|
|
17
|
-
this.result = {
|
|
18
|
-
entraToken: undefined,
|
|
19
|
-
acsToken: { token: "", expiresOnTimestamp: 0 },
|
|
20
|
-
};
|
|
21
|
-
this.client = getClient(options.resourceEndpoint);
|
|
22
|
-
this.httpClient = createDefaultHttpClient();
|
|
23
|
-
this.options = options;
|
|
24
|
-
this.options.scopes = this.options.scopes || [
|
|
25
|
-
"https://communication.azure.com/clients/.default",
|
|
26
|
-
];
|
|
27
|
-
// immediately fetch the token to pre-warm
|
|
28
|
-
this.isPending = this.getToken();
|
|
29
|
-
}
|
|
30
|
-
async getToken(options) {
|
|
31
|
-
var _a;
|
|
32
|
-
if ((_a = options === null || options === void 0 ? void 0 : options.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) {
|
|
33
|
-
return { token: "", expiresOnTimestamp: 0 };
|
|
34
|
-
}
|
|
35
|
-
// we're awaiting the token fetch, so we don't want to start another one
|
|
36
|
-
// however, we're ignoring the new abortSignal, unfortunately
|
|
37
|
-
if (!this.isPending) {
|
|
38
|
-
this.isPending = this.getTokenInternal(options);
|
|
39
|
-
}
|
|
40
|
-
try {
|
|
41
|
-
await this.isPending;
|
|
42
|
-
}
|
|
43
|
-
finally {
|
|
44
|
-
this.isPending = null;
|
|
45
|
-
}
|
|
46
|
-
return this.result.acsToken;
|
|
47
|
-
}
|
|
48
|
-
async getTokenInternal(options) {
|
|
49
|
-
const getTokenOptions = (options === null || options === void 0 ? void 0 : options.abortSignal) ? { abortSignal: options.abortSignal } : undefined;
|
|
50
|
-
const token = await this.options.tokenCredential.getToken(this.options.scopes
|
|
51
|
-
? this.options.scopes
|
|
52
|
-
: ["https://communication.azure.com/clients/.default"], getTokenOptions);
|
|
53
|
-
const currentDateTime = new Date();
|
|
54
|
-
const tokenExpiresOn = new Date(this.result.acsToken.expiresOnTimestamp);
|
|
55
|
-
if (token === null) {
|
|
56
|
-
this.result = {
|
|
57
|
-
entraToken: undefined,
|
|
58
|
-
acsToken: { token: "", expiresOnTimestamp: 0 },
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
else if (this.result.acsToken.token === "" ||
|
|
62
|
-
token.token !== this.result.entraToken ||
|
|
63
|
-
tokenExpiresOn < currentDateTime) {
|
|
64
|
-
const acsToken = await this.exchangeEntraToken(this.options.resourceEndpoint, token.token, getTokenOptions);
|
|
65
|
-
this.result = {
|
|
66
|
-
entraToken: token.token,
|
|
67
|
-
acsToken,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
return this.result.acsToken;
|
|
71
|
-
}
|
|
72
|
-
dispose() {
|
|
73
|
-
this.result = {
|
|
74
|
-
entraToken: undefined,
|
|
75
|
-
acsToken: { token: "", expiresOnTimestamp: 0 },
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
async exchangeEntraToken(resourceEndpoint, entraToken, options) {
|
|
79
|
-
const request = createPipelineRequest({
|
|
80
|
-
url: this.createRequestUri(resourceEndpoint),
|
|
81
|
-
method: "POST",
|
|
82
|
-
headers: createHttpHeaders({
|
|
83
|
-
Authorization: `Bearer ${entraToken}`,
|
|
84
|
-
"Content-Type": "application/json",
|
|
85
|
-
Accept: "application/json",
|
|
86
|
-
}),
|
|
87
|
-
abortSignal: options === null || options === void 0 ? void 0 : options.abortSignal,
|
|
88
|
-
body: JSON.stringify({}),
|
|
89
|
-
});
|
|
90
|
-
const response = await this.client.pipeline.sendRequest(this.httpClient, request);
|
|
91
|
-
if (response.status !== 200 || !response.bodyAsText) {
|
|
92
|
-
throw new Error(`Service request failed. Status: ${response.status}, Body: ${response.bodyAsText}`);
|
|
93
|
-
}
|
|
94
|
-
const json = JSON.parse(response.bodyAsText);
|
|
95
|
-
return {
|
|
96
|
-
token: json.accessToken.token,
|
|
97
|
-
expiresOnTimestamp: Date.parse(json.accessToken.expiresOn),
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
createRequestUri(resourceEndpoint) {
|
|
101
|
-
const [endpoint, apiVersion] = this.determineEndpointAndApiVersion();
|
|
102
|
-
const requestUri = `${resourceEndpoint}${endpoint}?api-version=${apiVersion}`;
|
|
103
|
-
return requestUri;
|
|
104
|
-
}
|
|
105
|
-
determineEndpointAndApiVersion() {
|
|
106
|
-
if (!this.options.scopes || this.options.scopes.length === 0) {
|
|
107
|
-
throw new Error(`Scopes validation failed. Ensure all scopes start with either {TeamsExtensionScopePrefix} or {ComunicationClientsScopePrefix}.`);
|
|
108
|
-
}
|
|
109
|
-
else if (this.options.scopes.every((scope) => scope.startsWith(TeamsExtensionScopePrefix))) {
|
|
110
|
-
return [TeamsExtensionEndpoint, TeamsExtensionApiVersion];
|
|
111
|
-
}
|
|
112
|
-
else if (this.options.scopes.every((scope) => scope.startsWith(ComunicationClientsScopePrefix))) {
|
|
113
|
-
return [ComunicationClientsEndpoint, ComunicationClientsApiVersion];
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
throw new Error(`Scopes validation failed. Ensure all scopes start with either {TeamsExtensionScopePrefix} or {ComunicationClientsScopePrefix}.`);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
//# sourceMappingURL=entraTokenCredential.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"entraTokenCredential.js","sourceRoot":"","sources":["../../src/entraTokenCredential.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { type AccessToken } from \"@azure/core-auth\";\nimport { type TokenCredential } from \"@azure/identity\";\nimport {\n type TokenCredential as AcsTokenCredential,\n type CommunicationGetTokenOptions,\n} from \"./communicationTokenCredential.js\";\nimport { type AbortSignalLike } from \"@azure/abort-controller\";\nimport { type Client, getClient } from \"@azure-rest/core-client\";\nimport {\n type HttpClient,\n createDefaultHttpClient,\n createHttpHeaders,\n createPipelineRequest,\n} from \"@azure/core-rest-pipeline\";\n\nconst TeamsExtensionScopePrefix = \"https://auth.msft.communication.azure.com/\";\nconst ComunicationClientsScopePrefix = \"https://communication.azure.com/clients/\";\nconst TeamsExtensionEndpoint = \"/access/teamsPhone/:exchangeAccessToken\";\nconst TeamsExtensionApiVersion = \"2025-03-02-preview\";\nconst ComunicationClientsEndpoint = \"/access/entra/:exchangeAccessToken\";\nconst ComunicationClientsApiVersion = \"2024-04-01-preview\";\n\nexport interface ExchangeTokenResponse {\n identity: string;\n accessToken: {\n token: string;\n expiresOn: string;\n };\n}\n\n/**\n * The Entra Communication Token Options.\n */\nexport interface EntraCommunicationTokenCredentialOptions {\n /**\n * The Azure Communication Service resource endpoint URL, e.g. https://myResource.communication.azure.com.\n */\n resourceEndpoint: string;\n /**\n * The Entra ID token credential.\n */\n tokenCredential: TokenCredential;\n /**\n * The scopes for retrieving the Entra ID access token.\n */\n scopes?: string[];\n}\n\n/**\n * Represents a credential that exchanges an Entra token for an Azure Communication Services (ACS) token, enabling access to ACS resources.\n */\nexport class EntraTokenCredential implements AcsTokenCredential {\n private isPending: Promise<AccessToken> | null;\n private result = {\n entraToken: undefined as string | undefined,\n acsToken: { token: \"\", expiresOnTimestamp: 0 },\n };\n private client: Client;\n private httpClient: HttpClient;\n\n constructor(private options: EntraCommunicationTokenCredentialOptions) {\n this.client = getClient(options.resourceEndpoint);\n this.httpClient = createDefaultHttpClient();\n this.options = options;\n this.options.scopes = this.options.scopes || [\n \"https://communication.azure.com/clients/.default\",\n ];\n\n // immediately fetch the token to pre-warm\n this.isPending = this.getToken();\n }\n\n public async getToken(options?: CommunicationGetTokenOptions): Promise<AccessToken> {\n if (options?.abortSignal?.aborted) {\n return { token: \"\", expiresOnTimestamp: 0 };\n }\n\n // we're awaiting the token fetch, so we don't want to start another one\n // however, we're ignoring the new abortSignal, unfortunately\n if (!this.isPending) {\n this.isPending = this.getTokenInternal(options);\n }\n\n try {\n await this.isPending;\n } finally {\n this.isPending = null;\n }\n\n return this.result.acsToken;\n }\n\n private async getTokenInternal(options?: CommunicationGetTokenOptions): Promise<AccessToken> {\n const getTokenOptions = options?.abortSignal ? { abortSignal: options.abortSignal } : undefined;\n const token = await this.options.tokenCredential.getToken(\n this.options.scopes\n ? this.options.scopes\n : [\"https://communication.azure.com/clients/.default\"],\n getTokenOptions,\n );\n const currentDateTime = new Date();\n const tokenExpiresOn = new Date(this.result.acsToken.expiresOnTimestamp);\n\n if (token === null) {\n this.result = {\n entraToken: undefined,\n acsToken: { token: \"\", expiresOnTimestamp: 0 },\n };\n } else if (\n this.result.acsToken.token === \"\" ||\n token.token !== this.result.entraToken ||\n tokenExpiresOn < currentDateTime\n ) {\n const acsToken = await this.exchangeEntraToken(\n this.options.resourceEndpoint,\n token.token,\n getTokenOptions,\n );\n this.result = {\n entraToken: token.token,\n acsToken,\n };\n }\n\n return this.result.acsToken;\n }\n\n public dispose(): void {\n this.result = {\n entraToken: undefined,\n acsToken: { token: \"\", expiresOnTimestamp: 0 },\n };\n }\n\n private async exchangeEntraToken(\n resourceEndpoint: string,\n entraToken: string,\n options?: { abortSignal: AbortSignalLike },\n ): Promise<AccessToken> {\n const request = createPipelineRequest({\n url: this.createRequestUri(resourceEndpoint),\n method: \"POST\",\n headers: createHttpHeaders({\n Authorization: `Bearer ${entraToken}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n }),\n abortSignal: options?.abortSignal,\n body: JSON.stringify({}),\n });\n const response = await this.client.pipeline.sendRequest(this.httpClient, request);\n\n if (response.status !== 200 || !response.bodyAsText) {\n throw new Error(\n `Service request failed. Status: ${response.status}, Body: ${response.bodyAsText}`,\n );\n }\n const json = JSON.parse(response.bodyAsText) as ExchangeTokenResponse;\n return {\n token: json.accessToken.token,\n expiresOnTimestamp: Date.parse(json.accessToken.expiresOn),\n };\n }\n\n private createRequestUri(resourceEndpoint: string): string {\n const [endpoint, apiVersion] = this.determineEndpointAndApiVersion();\n const requestUri = `${resourceEndpoint}${endpoint}?api-version=${apiVersion}`;\n return requestUri;\n }\n\n private determineEndpointAndApiVersion(): [string, string] {\n if (!this.options.scopes || this.options.scopes.length === 0) {\n throw new Error(\n `Scopes validation failed. Ensure all scopes start with either {TeamsExtensionScopePrefix} or {ComunicationClientsScopePrefix}.`,\n );\n } else if (this.options.scopes.every((scope) => scope.startsWith(TeamsExtensionScopePrefix))) {\n return [TeamsExtensionEndpoint, TeamsExtensionApiVersion];\n } else if (\n this.options.scopes.every((scope) => scope.startsWith(ComunicationClientsScopePrefix))\n ) {\n return [ComunicationClientsEndpoint, ComunicationClientsApiVersion];\n } else {\n throw new Error(\n `Scopes validation failed. Ensure all scopes start with either {TeamsExtensionScopePrefix} or {ComunicationClientsScopePrefix}.`,\n );\n }\n }\n}\n"]}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { type AccessToken } from "@azure/core-auth";
|
|
2
|
-
import { type TokenCredential } from "@azure/identity";
|
|
3
|
-
import { type TokenCredential as AcsTokenCredential, type CommunicationGetTokenOptions } from "./communicationTokenCredential.js";
|
|
4
|
-
export interface ExchangeTokenResponse {
|
|
5
|
-
identity: string;
|
|
6
|
-
accessToken: {
|
|
7
|
-
token: string;
|
|
8
|
-
expiresOn: string;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* The Entra Communication Token Options.
|
|
13
|
-
*/
|
|
14
|
-
export interface EntraCommunicationTokenCredentialOptions {
|
|
15
|
-
/**
|
|
16
|
-
* The Azure Communication Service resource endpoint URL, e.g. https://myResource.communication.azure.com.
|
|
17
|
-
*/
|
|
18
|
-
resourceEndpoint: string;
|
|
19
|
-
/**
|
|
20
|
-
* The Entra ID token credential.
|
|
21
|
-
*/
|
|
22
|
-
tokenCredential: TokenCredential;
|
|
23
|
-
/**
|
|
24
|
-
* The scopes for retrieving the Entra ID access token.
|
|
25
|
-
*/
|
|
26
|
-
scopes?: string[];
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Represents a credential that exchanges an Entra token for an Azure Communication Services (ACS) token, enabling access to ACS resources.
|
|
30
|
-
*/
|
|
31
|
-
export declare class EntraTokenCredential implements AcsTokenCredential {
|
|
32
|
-
private options;
|
|
33
|
-
private isPending;
|
|
34
|
-
private result;
|
|
35
|
-
private client;
|
|
36
|
-
private httpClient;
|
|
37
|
-
constructor(options: EntraCommunicationTokenCredentialOptions);
|
|
38
|
-
getToken(options?: CommunicationGetTokenOptions): Promise<AccessToken>;
|
|
39
|
-
private getTokenInternal;
|
|
40
|
-
dispose(): void;
|
|
41
|
-
private exchangeEntraToken;
|
|
42
|
-
private createRequestUri;
|
|
43
|
-
private determineEndpointAndApiVersion;
|
|
44
|
-
}
|
|
45
|
-
//# sourceMappingURL=entraTokenCredential.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"entraTokenCredential.d.ts","sourceRoot":"","sources":["../../src/entraTokenCredential.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EACL,KAAK,eAAe,IAAI,kBAAkB,EAC1C,KAAK,4BAA4B,EAClC,MAAM,mCAAmC,CAAC;AAiB3C,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE;QACX,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,wCAAwC;IACvD;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,eAAe,EAAE,eAAe,CAAC;IACjC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,oBAAqB,YAAW,kBAAkB;IASjD,OAAO,CAAC,OAAO;IAR3B,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,MAAM,CAGZ;IACF,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAa;gBAEX,OAAO,EAAE,wCAAwC;IAYxD,QAAQ,CAAC,OAAO,CAAC,EAAE,4BAA4B,GAAG,OAAO,CAAC,WAAW,CAAC;YAoBrE,gBAAgB;IAmCvB,OAAO,IAAI,IAAI;YAOR,kBAAkB;IA8BhC,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,8BAA8B;CAiBvC"}
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
// Copyright (c) Microsoft Corporation.
|
|
3
|
-
// Licensed under the MIT License.
|
|
4
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
-
exports.EntraTokenCredential = void 0;
|
|
6
|
-
const core_client_1 = require("@azure-rest/core-client");
|
|
7
|
-
const core_rest_pipeline_1 = require("@azure/core-rest-pipeline");
|
|
8
|
-
const TeamsExtensionScopePrefix = "https://auth.msft.communication.azure.com/";
|
|
9
|
-
const ComunicationClientsScopePrefix = "https://communication.azure.com/clients/";
|
|
10
|
-
const TeamsExtensionEndpoint = "/access/teamsPhone/:exchangeAccessToken";
|
|
11
|
-
const TeamsExtensionApiVersion = "2025-03-02-preview";
|
|
12
|
-
const ComunicationClientsEndpoint = "/access/entra/:exchangeAccessToken";
|
|
13
|
-
const ComunicationClientsApiVersion = "2024-04-01-preview";
|
|
14
|
-
/**
|
|
15
|
-
* Represents a credential that exchanges an Entra token for an Azure Communication Services (ACS) token, enabling access to ACS resources.
|
|
16
|
-
*/
|
|
17
|
-
class EntraTokenCredential {
|
|
18
|
-
constructor(options) {
|
|
19
|
-
this.options = options;
|
|
20
|
-
this.result = {
|
|
21
|
-
entraToken: undefined,
|
|
22
|
-
acsToken: { token: "", expiresOnTimestamp: 0 },
|
|
23
|
-
};
|
|
24
|
-
this.client = (0, core_client_1.getClient)(options.resourceEndpoint);
|
|
25
|
-
this.httpClient = (0, core_rest_pipeline_1.createDefaultHttpClient)();
|
|
26
|
-
this.options = options;
|
|
27
|
-
this.options.scopes = this.options.scopes || [
|
|
28
|
-
"https://communication.azure.com/clients/.default",
|
|
29
|
-
];
|
|
30
|
-
// immediately fetch the token to pre-warm
|
|
31
|
-
this.isPending = this.getToken();
|
|
32
|
-
}
|
|
33
|
-
async getToken(options) {
|
|
34
|
-
var _a;
|
|
35
|
-
if ((_a = options === null || options === void 0 ? void 0 : options.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) {
|
|
36
|
-
return { token: "", expiresOnTimestamp: 0 };
|
|
37
|
-
}
|
|
38
|
-
// we're awaiting the token fetch, so we don't want to start another one
|
|
39
|
-
// however, we're ignoring the new abortSignal, unfortunately
|
|
40
|
-
if (!this.isPending) {
|
|
41
|
-
this.isPending = this.getTokenInternal(options);
|
|
42
|
-
}
|
|
43
|
-
try {
|
|
44
|
-
await this.isPending;
|
|
45
|
-
}
|
|
46
|
-
finally {
|
|
47
|
-
this.isPending = null;
|
|
48
|
-
}
|
|
49
|
-
return this.result.acsToken;
|
|
50
|
-
}
|
|
51
|
-
async getTokenInternal(options) {
|
|
52
|
-
const getTokenOptions = (options === null || options === void 0 ? void 0 : options.abortSignal) ? { abortSignal: options.abortSignal } : undefined;
|
|
53
|
-
const token = await this.options.tokenCredential.getToken(this.options.scopes
|
|
54
|
-
? this.options.scopes
|
|
55
|
-
: ["https://communication.azure.com/clients/.default"], getTokenOptions);
|
|
56
|
-
const currentDateTime = new Date();
|
|
57
|
-
const tokenExpiresOn = new Date(this.result.acsToken.expiresOnTimestamp);
|
|
58
|
-
if (token === null) {
|
|
59
|
-
this.result = {
|
|
60
|
-
entraToken: undefined,
|
|
61
|
-
acsToken: { token: "", expiresOnTimestamp: 0 },
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
else if (this.result.acsToken.token === "" ||
|
|
65
|
-
token.token !== this.result.entraToken ||
|
|
66
|
-
tokenExpiresOn < currentDateTime) {
|
|
67
|
-
const acsToken = await this.exchangeEntraToken(this.options.resourceEndpoint, token.token, getTokenOptions);
|
|
68
|
-
this.result = {
|
|
69
|
-
entraToken: token.token,
|
|
70
|
-
acsToken,
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
|
-
return this.result.acsToken;
|
|
74
|
-
}
|
|
75
|
-
dispose() {
|
|
76
|
-
this.result = {
|
|
77
|
-
entraToken: undefined,
|
|
78
|
-
acsToken: { token: "", expiresOnTimestamp: 0 },
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
async exchangeEntraToken(resourceEndpoint, entraToken, options) {
|
|
82
|
-
const request = (0, core_rest_pipeline_1.createPipelineRequest)({
|
|
83
|
-
url: this.createRequestUri(resourceEndpoint),
|
|
84
|
-
method: "POST",
|
|
85
|
-
headers: (0, core_rest_pipeline_1.createHttpHeaders)({
|
|
86
|
-
Authorization: `Bearer ${entraToken}`,
|
|
87
|
-
"Content-Type": "application/json",
|
|
88
|
-
Accept: "application/json",
|
|
89
|
-
}),
|
|
90
|
-
abortSignal: options === null || options === void 0 ? void 0 : options.abortSignal,
|
|
91
|
-
body: JSON.stringify({}),
|
|
92
|
-
});
|
|
93
|
-
const response = await this.client.pipeline.sendRequest(this.httpClient, request);
|
|
94
|
-
if (response.status !== 200 || !response.bodyAsText) {
|
|
95
|
-
throw new Error(`Service request failed. Status: ${response.status}, Body: ${response.bodyAsText}`);
|
|
96
|
-
}
|
|
97
|
-
const json = JSON.parse(response.bodyAsText);
|
|
98
|
-
return {
|
|
99
|
-
token: json.accessToken.token,
|
|
100
|
-
expiresOnTimestamp: Date.parse(json.accessToken.expiresOn),
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
createRequestUri(resourceEndpoint) {
|
|
104
|
-
const [endpoint, apiVersion] = this.determineEndpointAndApiVersion();
|
|
105
|
-
const requestUri = `${resourceEndpoint}${endpoint}?api-version=${apiVersion}`;
|
|
106
|
-
return requestUri;
|
|
107
|
-
}
|
|
108
|
-
determineEndpointAndApiVersion() {
|
|
109
|
-
if (!this.options.scopes || this.options.scopes.length === 0) {
|
|
110
|
-
throw new Error(`Scopes validation failed. Ensure all scopes start with either {TeamsExtensionScopePrefix} or {ComunicationClientsScopePrefix}.`);
|
|
111
|
-
}
|
|
112
|
-
else if (this.options.scopes.every((scope) => scope.startsWith(TeamsExtensionScopePrefix))) {
|
|
113
|
-
return [TeamsExtensionEndpoint, TeamsExtensionApiVersion];
|
|
114
|
-
}
|
|
115
|
-
else if (this.options.scopes.every((scope) => scope.startsWith(ComunicationClientsScopePrefix))) {
|
|
116
|
-
return [ComunicationClientsEndpoint, ComunicationClientsApiVersion];
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
throw new Error(`Scopes validation failed. Ensure all scopes start with either {TeamsExtensionScopePrefix} or {ComunicationClientsScopePrefix}.`);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
exports.EntraTokenCredential = EntraTokenCredential;
|
|
124
|
-
//# sourceMappingURL=entraTokenCredential.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"entraTokenCredential.js","sourceRoot":"","sources":["../../src/entraTokenCredential.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\nimport { type AccessToken } from \"@azure/core-auth\";\nimport { type TokenCredential } from \"@azure/identity\";\nimport {\n type TokenCredential as AcsTokenCredential,\n type CommunicationGetTokenOptions,\n} from \"./communicationTokenCredential.js\";\nimport { type AbortSignalLike } from \"@azure/abort-controller\";\nimport { type Client, getClient } from \"@azure-rest/core-client\";\nimport {\n type HttpClient,\n createDefaultHttpClient,\n createHttpHeaders,\n createPipelineRequest,\n} from \"@azure/core-rest-pipeline\";\n\nconst TeamsExtensionScopePrefix = \"https://auth.msft.communication.azure.com/\";\nconst ComunicationClientsScopePrefix = \"https://communication.azure.com/clients/\";\nconst TeamsExtensionEndpoint = \"/access/teamsPhone/:exchangeAccessToken\";\nconst TeamsExtensionApiVersion = \"2025-03-02-preview\";\nconst ComunicationClientsEndpoint = \"/access/entra/:exchangeAccessToken\";\nconst ComunicationClientsApiVersion = \"2024-04-01-preview\";\n\nexport interface ExchangeTokenResponse {\n identity: string;\n accessToken: {\n token: string;\n expiresOn: string;\n };\n}\n\n/**\n * The Entra Communication Token Options.\n */\nexport interface EntraCommunicationTokenCredentialOptions {\n /**\n * The Azure Communication Service resource endpoint URL, e.g. https://myResource.communication.azure.com.\n */\n resourceEndpoint: string;\n /**\n * The Entra ID token credential.\n */\n tokenCredential: TokenCredential;\n /**\n * The scopes for retrieving the Entra ID access token.\n */\n scopes?: string[];\n}\n\n/**\n * Represents a credential that exchanges an Entra token for an Azure Communication Services (ACS) token, enabling access to ACS resources.\n */\nexport class EntraTokenCredential implements AcsTokenCredential {\n private isPending: Promise<AccessToken> | null;\n private result = {\n entraToken: undefined as string | undefined,\n acsToken: { token: \"\", expiresOnTimestamp: 0 },\n };\n private client: Client;\n private httpClient: HttpClient;\n\n constructor(private options: EntraCommunicationTokenCredentialOptions) {\n this.client = getClient(options.resourceEndpoint);\n this.httpClient = createDefaultHttpClient();\n this.options = options;\n this.options.scopes = this.options.scopes || [\n \"https://communication.azure.com/clients/.default\",\n ];\n\n // immediately fetch the token to pre-warm\n this.isPending = this.getToken();\n }\n\n public async getToken(options?: CommunicationGetTokenOptions): Promise<AccessToken> {\n if (options?.abortSignal?.aborted) {\n return { token: \"\", expiresOnTimestamp: 0 };\n }\n\n // we're awaiting the token fetch, so we don't want to start another one\n // however, we're ignoring the new abortSignal, unfortunately\n if (!this.isPending) {\n this.isPending = this.getTokenInternal(options);\n }\n\n try {\n await this.isPending;\n } finally {\n this.isPending = null;\n }\n\n return this.result.acsToken;\n }\n\n private async getTokenInternal(options?: CommunicationGetTokenOptions): Promise<AccessToken> {\n const getTokenOptions = options?.abortSignal ? { abortSignal: options.abortSignal } : undefined;\n const token = await this.options.tokenCredential.getToken(\n this.options.scopes\n ? this.options.scopes\n : [\"https://communication.azure.com/clients/.default\"],\n getTokenOptions,\n );\n const currentDateTime = new Date();\n const tokenExpiresOn = new Date(this.result.acsToken.expiresOnTimestamp);\n\n if (token === null) {\n this.result = {\n entraToken: undefined,\n acsToken: { token: \"\", expiresOnTimestamp: 0 },\n };\n } else if (\n this.result.acsToken.token === \"\" ||\n token.token !== this.result.entraToken ||\n tokenExpiresOn < currentDateTime\n ) {\n const acsToken = await this.exchangeEntraToken(\n this.options.resourceEndpoint,\n token.token,\n getTokenOptions,\n );\n this.result = {\n entraToken: token.token,\n acsToken,\n };\n }\n\n return this.result.acsToken;\n }\n\n public dispose(): void {\n this.result = {\n entraToken: undefined,\n acsToken: { token: \"\", expiresOnTimestamp: 0 },\n };\n }\n\n private async exchangeEntraToken(\n resourceEndpoint: string,\n entraToken: string,\n options?: { abortSignal: AbortSignalLike },\n ): Promise<AccessToken> {\n const request = createPipelineRequest({\n url: this.createRequestUri(resourceEndpoint),\n method: \"POST\",\n headers: createHttpHeaders({\n Authorization: `Bearer ${entraToken}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n }),\n abortSignal: options?.abortSignal,\n body: JSON.stringify({}),\n });\n const response = await this.client.pipeline.sendRequest(this.httpClient, request);\n\n if (response.status !== 200 || !response.bodyAsText) {\n throw new Error(\n `Service request failed. Status: ${response.status}, Body: ${response.bodyAsText}`,\n );\n }\n const json = JSON.parse(response.bodyAsText) as ExchangeTokenResponse;\n return {\n token: json.accessToken.token,\n expiresOnTimestamp: Date.parse(json.accessToken.expiresOn),\n };\n }\n\n private createRequestUri(resourceEndpoint: string): string {\n const [endpoint, apiVersion] = this.determineEndpointAndApiVersion();\n const requestUri = `${resourceEndpoint}${endpoint}?api-version=${apiVersion}`;\n return requestUri;\n }\n\n private determineEndpointAndApiVersion(): [string, string] {\n if (!this.options.scopes || this.options.scopes.length === 0) {\n throw new Error(\n `Scopes validation failed. Ensure all scopes start with either {TeamsExtensionScopePrefix} or {ComunicationClientsScopePrefix}.`,\n );\n } else if (this.options.scopes.every((scope) => scope.startsWith(TeamsExtensionScopePrefix))) {\n return [TeamsExtensionEndpoint, TeamsExtensionApiVersion];\n } else if (\n this.options.scopes.every((scope) => scope.startsWith(ComunicationClientsScopePrefix))\n ) {\n return [ComunicationClientsEndpoint, ComunicationClientsApiVersion];\n } else {\n throw new Error(\n `Scopes validation failed. Ensure all scopes start with either {TeamsExtensionScopePrefix} or {ComunicationClientsScopePrefix}.`,\n );\n }\n }\n}\n"]}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import { type AccessToken } from "@azure/core-auth";
|
|
2
|
-
import { type TokenCredential } from "@azure/identity";
|
|
3
|
-
import { type TokenCredential as AcsTokenCredential, type CommunicationGetTokenOptions } from "./communicationTokenCredential.js";
|
|
4
|
-
export interface ExchangeTokenResponse {
|
|
5
|
-
identity: string;
|
|
6
|
-
accessToken: {
|
|
7
|
-
token: string;
|
|
8
|
-
expiresOn: string;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* The Entra Communication Token Options.
|
|
13
|
-
*/
|
|
14
|
-
export interface EntraCommunicationTokenCredentialOptions {
|
|
15
|
-
/**
|
|
16
|
-
* The Azure Communication Service resource endpoint URL, e.g. https://myResource.communication.azure.com.
|
|
17
|
-
*/
|
|
18
|
-
resourceEndpoint: string;
|
|
19
|
-
/**
|
|
20
|
-
* The Entra ID token credential.
|
|
21
|
-
*/
|
|
22
|
-
tokenCredential: TokenCredential;
|
|
23
|
-
/**
|
|
24
|
-
* The scopes for retrieving the Entra ID access token.
|
|
25
|
-
*/
|
|
26
|
-
scopes?: string[];
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Represents a credential that exchanges an Entra token for an Azure Communication Services (ACS) token, enabling access to ACS resources.
|
|
30
|
-
*/
|
|
31
|
-
export declare class EntraTokenCredential implements AcsTokenCredential {
|
|
32
|
-
private options;
|
|
33
|
-
private isPending;
|
|
34
|
-
private result;
|
|
35
|
-
private client;
|
|
36
|
-
private httpClient;
|
|
37
|
-
constructor(options: EntraCommunicationTokenCredentialOptions);
|
|
38
|
-
getToken(options?: CommunicationGetTokenOptions): Promise<AccessToken>;
|
|
39
|
-
private getTokenInternal;
|
|
40
|
-
dispose(): void;
|
|
41
|
-
private exchangeEntraToken;
|
|
42
|
-
private createRequestUri;
|
|
43
|
-
private determineEndpointAndApiVersion;
|
|
44
|
-
}
|
|
45
|
-
//# sourceMappingURL=entraTokenCredential.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"entraTokenCredential.d.ts","sourceRoot":"","sources":["../../src/entraTokenCredential.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EACL,KAAK,eAAe,IAAI,kBAAkB,EAC1C,KAAK,4BAA4B,EAClC,MAAM,mCAAmC,CAAC;AAiB3C,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE;QACX,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,wCAAwC;IACvD;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,eAAe,EAAE,eAAe,CAAC;IACjC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,oBAAqB,YAAW,kBAAkB;IASjD,OAAO,CAAC,OAAO;IAR3B,OAAO,CAAC,SAAS,CAA8B;IAC/C,OAAO,CAAC,MAAM,CAGZ;IACF,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAAa;gBAEX,OAAO,EAAE,wCAAwC;IAYxD,QAAQ,CAAC,OAAO,CAAC,EAAE,4BAA4B,GAAG,OAAO,CAAC,WAAW,CAAC;YAoBrE,gBAAgB;IAmCvB,OAAO,IAAI,IAAI;YAOR,kBAAkB;IA8BhC,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,8BAA8B;CAiBvC"}
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Microsoft Corporation.
|
|
2
|
-
// Licensed under the MIT License.
|
|
3
|
-
import { getClient } from "@azure-rest/core-client";
|
|
4
|
-
import { createDefaultHttpClient, createHttpHeaders, createPipelineRequest, } from "@azure/core-rest-pipeline";
|
|
5
|
-
const TeamsExtensionScopePrefix = "https://auth.msft.communication.azure.com/";
|
|
6
|
-
const ComunicationClientsScopePrefix = "https://communication.azure.com/clients/";
|
|
7
|
-
const TeamsExtensionEndpoint = "/access/teamsPhone/:exchangeAccessToken";
|
|
8
|
-
const TeamsExtensionApiVersion = "2025-03-02-preview";
|
|
9
|
-
const ComunicationClientsEndpoint = "/access/entra/:exchangeAccessToken";
|
|
10
|
-
const ComunicationClientsApiVersion = "2024-04-01-preview";
|
|
11
|
-
/**
|
|
12
|
-
* Represents a credential that exchanges an Entra token for an Azure Communication Services (ACS) token, enabling access to ACS resources.
|
|
13
|
-
*/
|
|
14
|
-
export class EntraTokenCredential {
|
|
15
|
-
constructor(options) {
|
|
16
|
-
this.options = options;
|
|
17
|
-
this.result = {
|
|
18
|
-
entraToken: undefined,
|
|
19
|
-
acsToken: { token: "", expiresOnTimestamp: 0 },
|
|
20
|
-
};
|
|
21
|
-
this.client = getClient(options.resourceEndpoint);
|
|
22
|
-
this.httpClient = createDefaultHttpClient();
|
|
23
|
-
this.options = options;
|
|
24
|
-
this.options.scopes = this.options.scopes || [
|
|
25
|
-
"https://communication.azure.com/clients/.default",
|
|
26
|
-
];
|
|
27
|
-
// immediately fetch the token to pre-warm
|
|
28
|
-
this.isPending = this.getToken();
|
|
29
|
-
}
|
|
30
|
-
async getToken(options) {
|
|
31
|
-
var _a;
|
|
32
|
-
if ((_a = options === null || options === void 0 ? void 0 : options.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) {
|
|
33
|
-
return { token: "", expiresOnTimestamp: 0 };
|
|
34
|
-
}
|
|
35
|
-
// we're awaiting the token fetch, so we don't want to start another one
|
|
36
|
-
// however, we're ignoring the new abortSignal, unfortunately
|
|
37
|
-
if (!this.isPending) {
|
|
38
|
-
this.isPending = this.getTokenInternal(options);
|
|
39
|
-
}
|
|
40
|
-
try {
|
|
41
|
-
await this.isPending;
|
|
42
|
-
}
|
|
43
|
-
finally {
|
|
44
|
-
this.isPending = null;
|
|
45
|
-
}
|
|
46
|
-
return this.result.acsToken;
|
|
47
|
-
}
|
|
48
|
-
async getTokenInternal(options) {
|
|
49
|
-
const getTokenOptions = (options === null || options === void 0 ? void 0 : options.abortSignal) ? { abortSignal: options.abortSignal } : undefined;
|
|
50
|
-
const token = await this.options.tokenCredential.getToken(this.options.scopes
|
|
51
|
-
? this.options.scopes
|
|
52
|
-
: ["https://communication.azure.com/clients/.default"], getTokenOptions);
|
|
53
|
-
const currentDateTime = new Date();
|
|
54
|
-
const tokenExpiresOn = new Date(this.result.acsToken.expiresOnTimestamp);
|
|
55
|
-
if (token === null) {
|
|
56
|
-
this.result = {
|
|
57
|
-
entraToken: undefined,
|
|
58
|
-
acsToken: { token: "", expiresOnTimestamp: 0 },
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
else if (this.result.acsToken.token === "" ||
|
|
62
|
-
token.token !== this.result.entraToken ||
|
|
63
|
-
tokenExpiresOn < currentDateTime) {
|
|
64
|
-
const acsToken = await this.exchangeEntraToken(this.options.resourceEndpoint, token.token, getTokenOptions);
|
|
65
|
-
this.result = {
|
|
66
|
-
entraToken: token.token,
|
|
67
|
-
acsToken,
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
return this.result.acsToken;
|
|
71
|
-
}
|
|
72
|
-
dispose() {
|
|
73
|
-
this.result = {
|
|
74
|
-
entraToken: undefined,
|
|
75
|
-
acsToken: { token: "", expiresOnTimestamp: 0 },
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
async exchangeEntraToken(resourceEndpoint, entraToken, options) {
|
|
79
|
-
const request = createPipelineRequest({
|
|
80
|
-
url: this.createRequestUri(resourceEndpoint),
|
|
81
|
-
method: "POST",
|
|
82
|
-
headers: createHttpHeaders({
|
|
83
|
-
Authorization: `Bearer ${entraToken}`,
|
|
84
|
-
"Content-Type": "application/json",
|
|
85
|
-
Accept: "application/json",
|
|
86
|
-
}),
|
|
87
|
-
abortSignal: options === null || options === void 0 ? void 0 : options.abortSignal,
|
|
88
|
-
body: JSON.stringify({}),
|
|
89
|
-
});
|
|
90
|
-
const response = await this.client.pipeline.sendRequest(this.httpClient, request);
|
|
91
|
-
if (response.status !== 200 || !response.bodyAsText) {
|
|
92
|
-
throw new Error(`Service request failed. Status: ${response.status}, Body: ${response.bodyAsText}`);
|
|
93
|
-
}
|
|
94
|
-
const json = JSON.parse(response.bodyAsText);
|
|
95
|
-
return {
|
|
96
|
-
token: json.accessToken.token,
|
|
97
|
-
expiresOnTimestamp: Date.parse(json.accessToken.expiresOn),
|
|
98
|
-
};
|
|
99
|
-
}
|
|
100
|
-
createRequestUri(resourceEndpoint) {
|
|
101
|
-
const [endpoint, apiVersion] = this.determineEndpointAndApiVersion();
|
|
102
|
-
const requestUri = `${resourceEndpoint}${endpoint}?api-version=${apiVersion}`;
|
|
103
|
-
return requestUri;
|
|
104
|
-
}
|
|
105
|
-
determineEndpointAndApiVersion() {
|
|
106
|
-
if (!this.options.scopes || this.options.scopes.length === 0) {
|
|
107
|
-
throw new Error(`Scopes validation failed. Ensure all scopes start with either {TeamsExtensionScopePrefix} or {ComunicationClientsScopePrefix}.`);
|
|
108
|
-
}
|
|
109
|
-
else if (this.options.scopes.every((scope) => scope.startsWith(TeamsExtensionScopePrefix))) {
|
|
110
|
-
return [TeamsExtensionEndpoint, TeamsExtensionApiVersion];
|
|
111
|
-
}
|
|
112
|
-
else if (this.options.scopes.every((scope) => scope.startsWith(ComunicationClientsScopePrefix))) {
|
|
113
|
-
return [ComunicationClientsEndpoint, ComunicationClientsApiVersion];
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
throw new Error(`Scopes validation failed. Ensure all scopes start with either {TeamsExtensionScopePrefix} or {ComunicationClientsScopePrefix}.`);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
//# sourceMappingURL=entraTokenCredential.js.map
|