@dvsa/appdev-api-common 1.2.0 → 2.0.0-canary.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/auth/oidc.d.ts ADDED
@@ -0,0 +1,39 @@
1
+ export interface AzureTokenResponse {
2
+ token_type: string;
3
+ expires_in: number;
4
+ ext_expires_in?: number;
5
+ access_token: string;
6
+ }
7
+ export declare class AwsToAzureFederatedCredentials {
8
+ private readonly tenantId;
9
+ private readonly clientID;
10
+ private readonly tokenDurationSeconds;
11
+ private readonly debugMode;
12
+ private static accessToken;
13
+ private static readonly stsClient;
14
+ /**
15
+ * Create a new instance of the AwsToAzureFederatedCredentials class
16
+ * @param tenantId - The Azure AD tenant ID
17
+ * @param clientID - The Azure AD application (client) ID
18
+ * @param tokenDurationSeconds - Duration for the AWS token (default: 300)
19
+ * @param debugMode - Whether to log debug messages
20
+ */
21
+ constructor(tenantId: string, clientID: string, tokenDurationSeconds?: number, debugMode?: boolean);
22
+ /**
23
+ * Get the Azure access token, fetching a new one if needed
24
+ * @returns {Promise<string>} - The Azure access token
25
+ */
26
+ getAccessToken(): Promise<string>;
27
+ /**
28
+ * Fetch the AWS JWT and exchange it for an Azure token
29
+ * @returns {Promise<AzureTokenResponse>} - The Azure token response
30
+ * @private
31
+ */
32
+ private fetchFederatedCredentials;
33
+ /**
34
+ * Check if the access token is expired
35
+ * @returns {boolean} - Whether the access token is expired
36
+ * @private
37
+ */
38
+ private isAccessTokenExpired;
39
+ }
package/auth/oidc.js ADDED
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AwsToAzureFederatedCredentials = void 0;
4
+ const client_sts_1 = require("@aws-sdk/client-sts");
5
+ const jose_1 = require("jose");
6
+ class AwsToAzureFederatedCredentials {
7
+ tenantId;
8
+ clientID;
9
+ tokenDurationSeconds;
10
+ debugMode;
11
+ static accessToken;
12
+ static stsClient = new client_sts_1.STSClient();
13
+ /**
14
+ * Create a new instance of the AwsToAzureFederatedCredentials class
15
+ * @param tenantId - The Azure AD tenant ID
16
+ * @param clientID - The Azure AD application (client) ID
17
+ * @param tokenDurationSeconds - Duration for the AWS token (default: 300)
18
+ * @param debugMode - Whether to log debug messages
19
+ */
20
+ constructor(tenantId, clientID, tokenDurationSeconds = 300, debugMode = false) {
21
+ this.tenantId = tenantId;
22
+ this.clientID = clientID;
23
+ this.tokenDurationSeconds = tokenDurationSeconds;
24
+ this.debugMode = debugMode;
25
+ }
26
+ /**
27
+ * Get the Azure access token, fetching a new one if needed
28
+ * @returns {Promise<string>} - The Azure access token
29
+ */
30
+ async getAccessToken() {
31
+ if (!AwsToAzureFederatedCredentials.accessToken || this.isAccessTokenExpired()) {
32
+ const { access_token } = await this.fetchFederatedCredentials();
33
+ if (this.debugMode) {
34
+ console.log('[DEBUG] New Azure access token fetched:', access_token);
35
+ }
36
+ AwsToAzureFederatedCredentials.accessToken = access_token;
37
+ }
38
+ else if (this.debugMode) {
39
+ console.log("[DEBUG] Using existing Azure access token:", AwsToAzureFederatedCredentials.accessToken);
40
+ }
41
+ return AwsToAzureFederatedCredentials.accessToken;
42
+ }
43
+ /**
44
+ * Fetch the AWS JWT and exchange it for an Azure token
45
+ * @returns {Promise<AzureTokenResponse>} - The Azure token response
46
+ * @private
47
+ */
48
+ async fetchFederatedCredentials() {
49
+ const tokenResp = await AwsToAzureFederatedCredentials.stsClient.send(new client_sts_1.GetWebIdentityTokenCommand({
50
+ Audience: [this.clientID],
51
+ SigningAlgorithm: "RS256",
52
+ DurationSeconds: this.tokenDurationSeconds,
53
+ }));
54
+ const awsJwt = tokenResp?.WebIdentityToken;
55
+ if (!awsJwt) {
56
+ throw new Error("STS did not return a WebIdentityToken");
57
+ }
58
+ if (this.debugMode)
59
+ console.log("[DEBUG] AWS JWT obtained");
60
+ const response = await fetch(`https://login.microsoftonline.com/${this.tenantId}/oauth2/v2.0/token`, {
61
+ method: "POST",
62
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
63
+ body: new URLSearchParams({
64
+ grant_type: "client_credentials",
65
+ client_id: this.clientID,
66
+ client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
67
+ client_assertion: awsJwt,
68
+ scope: `api://${this.clientID}/.default`,
69
+ }).toString(),
70
+ });
71
+ if (!response.ok) {
72
+ const errorBody = await response.text();
73
+ console.error("Error exchanging AWS JWT for Azure token:", response.status, errorBody);
74
+ throw new Error(`Azure token endpoint error: HTTP ${response.status} - ${errorBody}`);
75
+ }
76
+ return (await response.json());
77
+ }
78
+ /**
79
+ * Check if the access token is expired
80
+ * @returns {boolean} - Whether the access token is expired
81
+ * @private
82
+ */
83
+ isAccessTokenExpired() {
84
+ try {
85
+ const decodedAccessToken = (0, jose_1.decodeJwt)(AwsToAzureFederatedCredentials.accessToken);
86
+ const currentTime = Date.now() / 1000;
87
+ if (!decodedAccessToken?.exp) {
88
+ return true;
89
+ }
90
+ return currentTime > decodedAccessToken.exp;
91
+ }
92
+ catch (err) {
93
+ console.error("Error decoding access token:", err);
94
+ return true;
95
+ }
96
+ }
97
+ }
98
+ exports.AwsToAzureFederatedCredentials = AwsToAzureFederatedCredentials;
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@dvsa/appdev-api-common",
3
- "version": "1.2.0",
4
- "keywords": ["dvsa", "nodejs", "typescript"],
3
+ "version": "2.0.0-canary.0",
4
+ "keywords": [
5
+ "dvsa",
6
+ "nodejs",
7
+ "typescript"
8
+ ],
5
9
  "author": "DVSA",
6
10
  "repository": {
7
11
  "type": "git",
@@ -28,6 +32,7 @@
28
32
  "gitSecrets": "git secrets --scan . && git log -p -- . | scanrepo"
29
33
  },
30
34
  "dependencies": {
35
+ "@aws-sdk/client-sts": "^3.989.0",
31
36
  "ajv": "^8.17.1",
32
37
  "ajv-formats": "^3.0.1",
33
38
  "dayjs": "^1.11.13",