Skip to content

Commit 69b644b

Browse files
committed
feat(auth): add support for MCSP V2 authentication
This commit adds the McspV2Authenticator implementation. This authenticator will invoke the MCSP V2 POST /api/2.0/{scopeCollectionType}/{scopeId}/apikeys/token operation to obtain an access token for an apikey. Signed-off-by: Phil Adams <[email protected]>
1 parent 2fe879d commit 69b644b

21 files changed

+5606
-4284
lines changed

.github/workflows/build.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ on:
1616
jobs:
1717
detect-secrets:
1818
if: "!contains(github.event.head_commit.message, '[skip ci]')"
19-
name: Detect-Secrets
19+
name: detect-secrets
2020
runs-on: ubuntu-latest
2121

2222
steps:
@@ -38,8 +38,8 @@ jobs:
3838
detect-secrets -v audit --report --fail-on-unaudited --fail-on-live --fail-on-audited-real .secrets.baseline
3939
4040
build:
41+
name: build-test (node v${{ matrix.node-version }})
4142
needs: detect-secrets
42-
name: Build/Test (Node v${{ matrix.node-version }})
4343
runs-on: ubuntu-latest
4444
strategy:
4545
matrix:
@@ -64,7 +64,7 @@ jobs:
6464
6565
publish-release:
6666
needs: build
67-
name: Semantic-Release
67+
name: semantic-release
6868
if: "github.ref_name == 'main' && github.event_name != 'pull_request'"
6969
runs-on: ubuntu-latest
7070

.secrets.baseline

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"files": "package-lock.json|^.secrets.baseline$",
44
"lines": null
55
},
6-
"generated_at": "2025-01-10T16:03:07Z",
6+
"generated_at": "2025-05-29T22:01:37Z",
77
"plugins_used": [
88
{
99
"name": "AWSKeyDetector"
@@ -70,55 +70,55 @@
7070
"hashed_secret": "91dfd9ddb4198affc5c194cd8ce6d338fde470e2",
7171
"is_secret": false,
7272
"is_verified": false,
73-
"line_number": 75,
73+
"line_number": 76,
7474
"type": "Secret Keyword",
7575
"verified_result": null
7676
},
7777
{
7878
"hashed_secret": "4f51cde3ac0a5504afa4bc06859b098366592c19",
7979
"is_secret": false,
8080
"is_verified": false,
81-
"line_number": 236,
81+
"line_number": 237,
8282
"type": "Secret Keyword",
8383
"verified_result": null
8484
},
8585
{
8686
"hashed_secret": "e87559ed7decb62d0733ae251ae58d42a55291d8",
8787
"is_secret": false,
8888
"is_verified": false,
89-
"line_number": 238,
89+
"line_number": 239,
9090
"type": "Secret Keyword",
9191
"verified_result": null
9292
},
9393
{
9494
"hashed_secret": "12f4a68ed3d0863e56497c9cdb1e2e4e91d5cb68",
9595
"is_secret": false,
9696
"is_verified": false,
97-
"line_number": 302,
97+
"line_number": 303,
9898
"type": "Secret Keyword",
9999
"verified_result": null
100100
},
101101
{
102102
"hashed_secret": "c837b75d7cd93ef9c2243ca28d6e5156259fd253",
103103
"is_secret": false,
104104
"is_verified": false,
105-
"line_number": 306,
105+
"line_number": 307,
106106
"type": "Secret Keyword",
107107
"verified_result": null
108108
},
109109
{
110110
"hashed_secret": "98635b2eaa2379f28cd6d72a38299f286b81b459",
111111
"is_secret": false,
112112
"is_verified": false,
113-
"line_number": 558,
113+
"line_number": 561,
114114
"type": "Secret Keyword",
115115
"verified_result": null
116116
},
117117
{
118118
"hashed_secret": "47fcf185ee7e15fe05cae31fbe9e4ebe4a06a40d",
119119
"is_secret": false,
120120
"is_verified": false,
121-
"line_number": 668,
121+
"line_number": 770,
122122
"type": "Secret Keyword",
123123
"verified_result": null
124124
}
@@ -128,7 +128,7 @@
128128
"hashed_secret": "bc2f74c22f98f7b6ffbc2f67453dbfa99bce9a32",
129129
"is_secret": false,
130130
"is_verified": false,
131-
"line_number": 221,
131+
"line_number": 277,
132132
"type": "Secret Keyword",
133133
"verified_result": null
134134
}
@@ -224,7 +224,7 @@
224224
"hashed_secret": "8f4bfc22c4fd7cb884f94ec175ff4a3284a174a1",
225225
"is_secret": false,
226226
"is_verified": false,
227-
"line_number": 60,
227+
"line_number": 58,
228228
"type": "Secret Keyword",
229229
"verified_result": null
230230
}
@@ -234,7 +234,7 @@
234234
"hashed_secret": "184ee1f04a018aa3b897e085516a9b657fea0f6b",
235235
"is_secret": false,
236236
"is_verified": false,
237-
"line_number": 86,
237+
"line_number": 88,
238238
"type": "Secret Keyword",
239239
"verified_result": null
240240
}
@@ -369,6 +369,24 @@
369369
"verified_result": null
370370
}
371371
],
372+
"auth/token-managers/mcspv2-token-manager.ts": [
373+
{
374+
"hashed_secret": "8f4bfc22c4fd7cb884f94ec175ff4a3284a174a1",
375+
"is_secret": false,
376+
"is_verified": false,
377+
"line_number": 125,
378+
"type": "Secret Keyword",
379+
"verified_result": null
380+
},
381+
{
382+
"hashed_secret": "65e622227634e8876cfa733000233fb80c6f0473",
383+
"is_secret": false,
384+
"is_verified": false,
385+
"line_number": 194,
386+
"type": "Secret Keyword",
387+
"verified_result": null
388+
}
389+
],
372390
"auth/utils/get-authenticator-from-environment.ts": [
373391
{
374392
"hashed_secret": "6947818ac409551f11fbaa78f0ea6391960aa5b8",
@@ -394,7 +412,7 @@
394412
"hashed_secret": "45c43fe97e3a06ab078b0eeff6fbe622cc417a25",
395413
"is_secret": false,
396414
"is_verified": false,
397-
"line_number": 292,
415+
"line_number": 297,
398416
"type": "Secret Keyword",
399417
"verified_result": null
400418
}
@@ -651,6 +669,26 @@
651669
"verified_result": null
652670
}
653671
],
672+
"test/unit/mcspv2-authenticator.test.js": [
673+
{
674+
"hashed_secret": "fd08cd887ed1de2f2d3e175117ff607ca65187ae",
675+
"is_secret": false,
676+
"is_verified": false,
677+
"line_number": 21,
678+
"type": "Secret Keyword",
679+
"verified_result": null
680+
}
681+
],
682+
"test/unit/mcspv2-token-manager.test.js": [
683+
{
684+
"hashed_secret": "fd08cd887ed1de2f2d3e175117ff607ca65187ae",
685+
"is_secret": false,
686+
"is_verified": false,
687+
"line_number": 32,
688+
"type": "Secret Keyword",
689+
"verified_result": null
690+
}
691+
],
654692
"test/unit/read-external-sources.test.js": [
655693
{
656694
"hashed_secret": "4c65cd3f160d60f7ca28ca04fa60b9035132781c",

Authentication.md

Lines changed: 110 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ The node-sdk-core project supports the following types of authentication:
77
- Container Authentication
88
- VPC Instance Authentication
99
- Cloud Pak for Data Authentication
10-
- Multi-Cloud Saas Platform (MCSP) Authentication
10+
- Multi-Cloud Saas Platform (MCSP) V1 Authentication
11+
- Multi-Cloud Saas Platform (MCSP) V2 Authentication
1112
- No Authentication (for testing)
1213

1314
The SDK user configures the appropriate type of authentication for use with service instances.
@@ -280,14 +281,14 @@ However, if your application is using an instance of a service in the "staging"
280281
then you would also need to configure the authenticator to use the IAM token service "staging"
281282
endpoint as well (`https://iam.test.cloud.ibm.com`).
282283

283-
- clientId/clientSecret: (optional) The `clientId` and `clientSecret` fields are used to form a
284+
- clientId/clientSecret: (optional) The `clientId` and `clientSecret` fields are used to form a
284285
"basic auth" Authorization header for interactions with the IAM token server when fetching the
285286
initial IAM access token. These fields are optional, but must be specified together.
286287

287288
- scope: (optional) the scope to be used when obtaining the initial IAM access token.
288289
If not specified, then no scope will be associated with the access token.
289290

290-
- disableSslVerification: (optional) A flag that indicates whether verification of the server's SSL
291+
- disableSslVerification: (optional) A flag that indicates whether verification of the server's SSL
291292
certificate should be disabled or not. The default value is `false`.
292293

293294
- headers: (optional) A set of key/value pairs that will be sent as HTTP headers in requests
@@ -612,11 +613,11 @@ const service = ExampleServiceV1.newInstance(options);
612613
```
613614

614615

615-
## Multi-Cloud Saas Platform (MCSP) Authentication
616+
## Multi-Cloud Saas Platform (MCSP) V1 Authentication
616617
The `McspAuthenticator` can be used in scenarios where an application needs to
617618
interact with an IBM Cloud service that has been deployed to a non-IBM Cloud environment (e.g. AWS).
618-
It accepts a user-supplied apikey and performs the necessary interactions with the
619-
Multi-Cloud Saas Platform token service to obtain a suitable MCSP access token (a bearer token)
619+
It accepts a user-supplied apikey and invokes the Multi-Cloud Saas Platform token service's
620+
`POST /siusermgr/api/1.0/apikeys/token` operation to obtain a suitable MCSP access token (a bearer token)
620621
for the specified apikey.
621622
The authenticator will also obtain a new bearer token when the current token expires.
622623
The bearer token is then added to each outbound request in the `Authorization` header in the
@@ -684,6 +685,109 @@ const service = ExampleServiceV1.newInstance(options);
684685
```
685686

686687

688+
## Multi-Cloud Saas Platform (MCSP) V2 Authentication
689+
The `McspV2Authenticator` can be used in scenarios where an application needs to
690+
interact with an IBM Cloud service that has been deployed to a non-IBM Cloud environment (e.g. AWS).
691+
It accepts a user-supplied apikey and invokes the Multi-Cloud Saas Platform token service's
692+
`POST /api/2.0/{scopeCollectionType}/{scopeId}/apikeys/token` operation to obtain a suitable MCSP access token (a bearer token)
693+
for the specified apikey.
694+
The authenticator will also obtain a new bearer token when the current token expires.
695+
The bearer token is then added to each outbound request in the `Authorization` header in the
696+
form:
697+
```
698+
Authorization: Bearer <bearer-token>
699+
```
700+
701+
### Properties
702+
703+
- apikey: (required) The apikey to be used to obtain an MCSP access token.
704+
705+
- url: (required) The URL representing the MCSP token service endpoint's base URL string. Do not include the
706+
operation path (e.g. `/api/2.0/{scopeCollectionType}/{scopeId}/apikeys/token`) as part of this property's value.
707+
708+
- scopeCollectionType: (required) The scope collection type of item(s).
709+
The valid values are: `accounts`, `subscriptions`, `services`.
710+
711+
- scopeId: (required) The scope identifier of item(s).
712+
713+
- includeBuiltinActions: (optional) A flag to include builtin actions in the `actions` claim in the MCSP token (default: false).
714+
715+
- includeCustomActions: (optional) A flag to include custom actions in the `actions` claim in the MCSP token (default: false).
716+
717+
- includeRoles: (optional) A flag to include the `roles` claim in the MCSP token (default: true).
718+
719+
- prefixRoles: (optional) A flag to add a prefix with the scope level where
720+
the role is defined in the `roles` claim (default: false).
721+
722+
- callerExtClaim: (optional) A map containing keys and values to be injected into the returned access token
723+
as the `callerExt` claim. The keys used in this map must be enabled in the apikey by setting the
724+
`callerExtClaimNames` property when the apikey is created.
725+
This property is typically only used in scenarios involving an apikey with identityType `SERVICEID`.
726+
727+
- disableSSLVerification: (optional) A flag that indicates whether verification of the server's SSL
728+
certificate should be disabled or not. The default value is `false`.
729+
730+
- headers: (optional) A set of key/value pairs that will be sent as HTTP headers in requests
731+
made to the MCSP token service.
732+
733+
### Usage Notes
734+
- When constructing an McspV2Authenticator instance, the apikey, url, scopeCollectionType, and scopeId properties are required.
735+
736+
- If you specify the callerExtClaim map, the keys used in the map must have been previously enabled in the apikey
737+
by setting the `callerExtClaimNames` property when you created the apikey.
738+
The entries contained in this map will appear in the `callerExt` field (claim) of the returned access token.
739+
740+
- The authenticator will invoke the token server's `POST /api/2.0/{scopeCollectionType}/{scopeId}/apikeys/token` operation to
741+
exchange the apikey for an MCSP access token (the bearer token).
742+
743+
### Programming example
744+
```js
745+
const { McspV2Authenticator } = require('ibm-cloud-sdk-core');
746+
const ExampleServiceV1 = require('<sdk-package-name>/example-service/v1');
747+
748+
const authenticator = new McspV2Authenticator({
749+
apikey: 'myapikey',
750+
url: 'https://example.mcsp.token-exchange.com',
751+
scopeCollectionType: 'accounts',
752+
scopeId: '20250519-2128-3755-60b3-103e01c509e8',
753+
includeBuiltinActions: true,
754+
callerExtClaim: {'productID': 'prod-123'},
755+
});
756+
757+
const options = {
758+
authenticator,
759+
};
760+
761+
const service = new ExampleServiceV1(options);
762+
763+
// 'service' can now be used to invoke operations.
764+
```
765+
766+
### Configuration example
767+
External configuration:
768+
```
769+
export EXAMPLE_SERVICE_AUTH_TYPE=mcspv2
770+
export EXAMPLE_SERVICE_APIKEY=myapikey
771+
export EXAMPLE_SERVICE_AUTH_URL=https://example.mcspv2.token-exchange.com
772+
export EXAMPLE_SERVICE_SCOPE_COLLECTION_TYPE=accounts
773+
export EXAMPLE_SERVICE_SCOPE_ID=20250519-2128-3755-60b3-103e01c509e8
774+
export EXAMPLE_SERVICE_INCLUDE_BUILTIN_ACTIONS=true
775+
export EXAMPLE_SERVICE_CALLER_EXT_CLAIM={"productID":"prod-123"}
776+
```
777+
Application code:
778+
```js
779+
const ExampleServiceV1 = require('<sdk-package-name>/example-service/v1');
780+
781+
const options = {
782+
serviceName: 'example_service',
783+
};
784+
785+
const service = ExampleServiceV1.newInstance(options);
786+
787+
// 'service' can now be used to invoke operations.
788+
```
789+
790+
687791
## No Auth Authentication
688792
The `NoAuthAuthenticator` is a placeholder authenticator which performs no actual authentication function.
689793
It can be used in situations where authentication needs to be bypassed, perhaps while developing

auth/authenticators/authenticator.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable @typescript-eslint/no-unused-vars, class-methods-use-this */
22

33
/**
4-
* (C) Copyright IBM Corp. 2019, 2023.
4+
* (C) Copyright IBM Corp. 2019, 2025.
55
*
66
* Licensed under the Apache License, Version 2.0 (the "License");
77
* you may not use this file except in compliance with the License.
@@ -44,6 +44,8 @@ export class Authenticator implements AuthenticatorInterface {
4444

4545
static AUTHTYPE_MCSP = 'mcsp';
4646

47+
static AUTHTYPE_MCSPV2 = 'mcspv2';
48+
4749
static AUTHTYPE_UNKNOWN = 'unknown';
4850

4951
/**

auth/authenticators/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
* IAMAssumeAuthenticator: Authenticator for passing IAM authentication information to service endpoint, assuming a trusted profile.
4141
* ContainerAuthenticator: Authenticator for passing IAM authentication to a service, based on a token living on the container.
4242
* VpcInstanceAuthenticator: Authenticator that uses the VPC Instance Metadata Service API to retrieve an IAM token.
43-
* McspAuthenticator: Authenticator for passing MCSP authentication to a service endpoint.
43+
* McspAuthenticator: Authenticator for passing MCSP v1 authentication to a service endpoint.
44+
* McspV2Authenticator: Authenticator for passing MCSP v2 authentication to a service endpoint.
4445
* NoAuthAuthenticator: Performs no authentication. Useful for testing purposes.
4546
*/
4647

@@ -56,4 +57,5 @@ export { IamRequestBasedAuthenticator } from './iam-request-based-authenticator'
5657
export { TokenRequestBasedAuthenticator } from './token-request-based-authenticator';
5758
export { VpcInstanceAuthenticator } from './vpc-instance-authenticator';
5859
export { McspAuthenticator } from './mcsp-authenticator';
60+
export { McspV2Authenticator } from './mcspv2-authenticator';
5961
export { IamAssumeAuthenticator } from './iam-assume-authenticator';

auth/authenticators/mcsp-authenticator.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* (C) Copyright IBM Corp. 2023.
2+
* (C) Copyright IBM Corp. 2023, 2025.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -45,8 +45,6 @@ export class McspAuthenticator extends TokenRequestBasedAuthenticator {
4545
* @param options - Configuration options for CloudPakForData authentication.
4646
* This should be an object containing these fields:
4747
* - url: (required) the endpoint URL for the CloudPakForData token service
48-
* - username: (required) the username used to obtain a bearer token
49-
* - password: (optional) the password used to obtain a bearer token (required if apikey is not specified)
5048
* - apikey: (optional) the API key used to obtain a bearer token (required if password is not specified)
5149
* - disableSslVerification: (optional) a flag that indicates whether verification of the token server's SSL certificate
5250
* should be disabled or not
@@ -67,7 +65,7 @@ export class McspAuthenticator extends TokenRequestBasedAuthenticator {
6765
}
6866

6967
/**
70-
* Returns the authenticator's type ('cp4d').
68+
* Returns the authenticator's type ('mcsp').
7169
*
7270
* @returns a string that indicates the authenticator's type
7371
*/

0 commit comments

Comments
 (0)