@@ -13,175 +13,59 @@ governing permissions and limitations under the License.
1313/* eslint-disable camelcase */
1414
1515const fetch = require ( 'node-fetch' )
16- const jwt = require ( 'jsonwebtoken' )
1716const FormData = require ( 'form-data' )
1817
19- const JWT_EXPIRY_SECONDS = 1200 // 20 minutes
20-
2118/**
22- * Create a jwt payload.
23- *
24- * @param {object } options see getSignedJwt
25- * @param {number } millisecondsSinceEpoch the date in ms since epoch
26- * @returns {object } the payload
19+ * @param {string } env ims env
20+ * @param {string } clientId clientId
21+ * @param {string } clientSecret clientSecret
22+ * @param {string } orgId imsOrgId
23+ * @param {string } scopes coma separated string
24+ * @returns {{ access_token: string } } ims response
2725 */
28- function createJwtPayload ( options , millisecondsSinceEpoch = Date . now ( ) ) {
29- let m = options . metaScopes
30- if ( ! Array . isArray ( m ) ) {
31- m = m . split ( ',' )
32- }
33-
34- const metaScopes = { }
35- m . forEach ( m => {
36- if ( m . startsWith ( 'https' ) ) {
37- metaScopes [ m ] = true
38- } else {
39- metaScopes [ `${ options . ims } /s/${ m } ` ] = true
40- }
41- } )
42-
43- return {
44- aud : `${ options . ims } /c/${ options . clientId } ` ,
45- exp : Math . round ( JWT_EXPIRY_SECONDS + millisecondsSinceEpoch / 1000 ) ,
46- ...metaScopes ,
47- iss : options . orgId ,
48- sub : options . technicalAccountId
26+ async function getAccessTokenByClientCredentials ( env , clientId , clientSecret , orgId , scopes ) {
27+ const IMS_ENDPOINTS = {
28+ stage : 'https://ims-na1-stg1.adobelogin.com' ,
29+ prod : 'https://ims-na1.adobelogin.com'
4930 }
50- }
51-
52- /**
53- * Gets an OAuth token.
54- *
55- * @param {string } actionURL the url to fetch the token from
56- * @returns {object } the token data
57- */
58- async function getOauthToken ( actionURL ) {
59- const postOptions = {
60- method : 'POST'
61- }
62-
63- const res = await fetch ( actionURL , postOptions )
64- const json = await res . json ( )
65- const { access_token, error, error_description } = json
66- if ( ! access_token ) {
67- if ( error && error_description ) {
68- throw new Error ( `${ error } : ${ error_description } ` )
69- } else {
70- throw new Error ( `An unknown error occurred fetching oauth token. The response is as follows: ${ JSON . stringify ( json ) } ` )
71- }
72- }
73- return json
74- }
75-
76- /**
77- * Gets a signed JWT.
78- *
79- * @param {object } options all the options for generating the JWT
80- * @param {string } options.clientId the jwt client id
81- * @param {string } options.technicalAccountId the technical account id of the credential
82- * @param {string } options.orgId the org id of the credential
83- * @param {string } options.clientSecret the jwt client secret
84- * @param {string } options.privateKey the jwt private key
85- * @param {string } [options.passphrase=''] the passphrase for private key, if set
86- * @param {Array<string> } options.metaScopes all the metascopes for the services tied to the credential
87- * @param {string } [options.ims='https://ims-na1.adobelogin.com'] the IMS endpoint
88- * @returns {string } the signed jwt
89- */
90- async function getSignedJwt ( options ) {
91- const {
92- clientId,
93- technicalAccountId,
94- orgId,
95- clientSecret,
96- privateKey,
97- passphrase = '' ,
98- metaScopes = [
99- 'https://ims-na1.adobelogin.com/s/ent_analytics_bulk_ingest_sdk' ,
100- 'https://ims-na1.adobelogin.com/s/ent_marketing_sdk' ,
101- 'https://ims-na1.adobelogin.com/s/ent_campaign_sdk' ,
102- 'https://ims-na1.adobelogin.com/s/ent_adobeio_sdk' ,
103- 'https://ims-na1.adobelogin.com/s/ent_audiencemanagerplatform_sdk'
104- ] ,
105- ims = 'https://ims-na1.adobelogin.com'
106- } = options
107-
108- const errors = [ ]
109- if ( ! clientId ) { errors . push ( 'clientId' ) }
110- if ( ! technicalAccountId ) { errors . push ( 'technicalAccountId' ) }
111- if ( ! orgId ) { errors . push ( 'orgId' ) }
112- if ( ! clientSecret ) { errors . push ( 'clientSecret' ) }
113- if ( ! privateKey ) { errors . push ( 'privateKey' ) }
114- if ( ! metaScopes || metaScopes . length === 0 ) { errors . push ( 'metaScopes' ) }
115- if ( ! ims ) { errors . push ( 'ims' ) }
116- if ( errors . length > 0 ) {
117- throw new Error ( `Required parameter(s) ${ errors . join ( ', ' ) } are missing` )
31+ const endpoint = IMS_ENDPOINTS [ env ]
32+ if ( ! endpoint ) {
33+ throw new Error ( `IMS_ENV must be one of "${ Object . keys ( IMS_ENDPOINTS ) } "` )
11834 }
11935
120- const jwtPayload = createJwtPayload ( { // potentially add the defaults, to options
121- ...options ,
122- passphrase,
123- metaScopes,
124- ims
125- } )
126-
127- const token = jwt . sign (
128- jwtPayload ,
129- { key : privateKey , passphrase } ,
130- { algorithm : 'RS256' }
131- )
132-
133- return token
134- }
135-
136- /**
137- * Gets an OAuth token by exchanging a JWT.
138- *
139- * @param {object } options the parameters to send to the jwt exchange endpoint
140- * @param {string } options.clientId the jwt client id
141- * @param {string } options.clientSecret the jwt client secret
142- * @param {string } [options.ims='https://ims-na1.adobelogin.com'] the IMS endpoint
143- * @param {string } signedJwt the signed JWT
144- * @returns {object } the access token
145- */
146- async function getJWTToken ( options , signedJwt ) {
147- const {
148- clientId,
149- clientSecret,
150- ims = 'https://ims-na1.adobelogin.com'
151- } = options
152-
153- if ( ! signedJwt ) {
154- signedJwt = await getSignedJwt ( options )
36+ // prepare the data with common data
37+ const postData = {
38+ grant_type : 'client_credentials' ,
39+ client_id : clientId ,
40+ client_secret : clientSecret ,
41+ org_id : orgId ,
42+ scope : scopes
15543 }
156-
15744 const form = new FormData ( )
158- form . append ( 'client_id' , clientId )
159- form . append ( 'client_secret' , clientSecret )
160- form . append ( 'jwt_token' , signedJwt )
45+ Object . entries ( postData ) . forEach ( ( [ k , v ] ) =>
46+ form . append ( k , v )
47+ )
16148
162- const postOptions = {
163- method : 'POST' ,
164- body : form ,
165- headers : form . getHeaders ( )
49+ let res
50+ try {
51+ res = await fetch (
52+ IMS_ENDPOINTS [ env ] + '/ims/token/v2' ,
53+ {
54+ method : 'POST' ,
55+ headers : form . getHeaders ( ) ,
56+ body : form
57+ }
58+ )
59+ } catch ( e ) {
60+ throw new Error ( `cannot send request to IMS: ${ e . message } ` )
16661 }
16762
168- const res = await fetch ( `${ ims } /ims/exchange/jwt/` , postOptions )
169- const json = await res . json ( )
170- const { access_token, error, error_description } = json
171- if ( ! access_token ) {
172- if ( error && error_description ) {
173- throw new Error ( `${ error } : ${ error_description } ` )
174- } else {
175- throw new Error ( `An unknown error occurred while swapping jwt. The response is as follows: ${ JSON . stringify ( json ) } ` )
176- }
63+ if ( res . ok ) {
64+ return res . json ( )
17765 }
178- return json
66+ throw new Error ( `error response from IMS with status: ${ res . status } and body: ${ await res . text ( ) } ` )
17967}
18068
18169module . exports = {
182- JWT_EXPIRY_SECONDS ,
183- createJwtPayload,
184- getSignedJwt,
185- getJWTToken,
186- getOauthToken
70+ getAccessTokenByClientCredentials
18771}
0 commit comments