-
Notifications
You must be signed in to change notification settings - Fork 10
feat(llmo-3954): add IMS service principal token for CDN routing API calls #2175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -34,7 +34,7 @@ import { Entitlement as EntitlementModel } from '@adobe/spacecat-shared-data-acc | |||||||||||||
| import TokowakaClient, { calculateForwardedHost } from '@adobe/spacecat-shared-tokowaka-client'; | ||||||||||||||
| import AccessControlUtil from '../../support/access-control-util.js'; | ||||||||||||||
| import { UnauthorizedProductError } from '../../support/errors.js'; | ||||||||||||||
| import { exchangePromiseToken } from '../../support/utils.js'; | ||||||||||||||
| import { exchangePromiseToken, getServicePrincipalToken } from '../../support/utils.js'; | ||||||||||||||
| import { triggerBrandProfileAgent } from '../../support/brand-profile-trigger.js'; | ||||||||||||||
| import { | ||||||||||||||
| applyFilters, | ||||||||||||||
|
|
@@ -1614,12 +1614,19 @@ function LlmoController(ctx) { | |||||||||||||
|
|
||||||||||||||
| let imsUserToken; | ||||||||||||||
| try { | ||||||||||||||
| log.debug(`Getting IMS user token for site ${siteId}`); | ||||||||||||||
| imsUserToken = await exchangePromiseToken(context, promiseToken); | ||||||||||||||
| log.info('IMS user token obtained successfully'); | ||||||||||||||
| } catch (tokenError) { | ||||||||||||||
| log.warn(`Fetching IMS user token for site ${siteId} failed: ${tokenError.status} ${tokenError.message}`); | ||||||||||||||
| return createResponse({ message: 'Authentication failed with upstream IMS service' }, 401); | ||||||||||||||
| log.debug(`Getting IMS service principal token for site ${siteId}`); | ||||||||||||||
| imsUserToken = await getServicePrincipalToken(context); | ||||||||||||||
| log.info('IMS service principal token obtained successfully'); | ||||||||||||||
| } catch (spTokenError) { | ||||||||||||||
| log.warn(`Service principal token unavailable for site ${siteId}: ${spTokenError.message}; falling back to promise token`); | ||||||||||||||
|
||||||||||||||
| log.warn(`Service principal token unavailable for site ${siteId}: ${spTokenError.message}; falling back to promise token`); | |
| log.warn(`Service principal token unavailable for site ${siteId}: ${spTokenError.message}; falling back to promise token`); | |
| if (!hasText(promiseToken)) { | |
| log.warn(`No promise token provided for site ${siteId}; unable to use fallback authentication`); | |
| return createResponse({ message: 'Authentication failed with upstream IMS service' }, 401); | |
| } |
Copilot
AI
Apr 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fallback currently triggers on any service-principal token error, even when IMS credentials are configured. If fallback is only intended when env vars are missing (per PR description), consider checking required env vars before calling IMS or narrowing the catch to “not configured” errors so misconfigurations/outages don’t get silently masked.
Copilot
AI
Apr 10, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change introduces a new token acquisition path (getServicePrincipalToken) and changes the controller’s behavior, but no tests are updated/added in this PR. Please update test/controllers/llmo/llmo.test.js to stub/assert the SP-token path (including the “no x-promise-token needed” case) and the fallback-to-promise-token case.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,7 +12,7 @@ | |
| import { Site as SiteModel } from '@adobe/spacecat-shared-data-access'; | ||
| import { Entitlement as EntitlementModel } from '@adobe/spacecat-shared-data-access/src/models/entitlement/index.js'; | ||
| import { Config } from '@adobe/spacecat-shared-data-access/src/models/site/config.js'; | ||
| import { ImsPromiseClient } from '@adobe/spacecat-shared-ims-client'; | ||
| import { ImsPromiseClient, ImsClient } from '@adobe/spacecat-shared-ims-client'; | ||
| import URI from 'urijs'; | ||
| import { | ||
| hasText, | ||
|
|
@@ -709,6 +709,22 @@ export async function exchangePromiseToken(context, promiseToken) { | |
| return accessToken; | ||
| } | ||
|
|
||
| /** | ||
| * Obtains an IMS Service Principal (client_credentials) access token for the | ||
| * LLMO backend service. Uses the IMS v3 token endpoint. | ||
| * | ||
| * Required env vars: IMS_HOST, IMS_CLIENT_ID, IMS_CLIENT_CODE, IMS_CLIENT_SECRET | ||
| * | ||
| * @param {Object} context - The request context (provides env + log). | ||
| * @returns {Promise<string>} The IMS access token string. | ||
| * @throws {Error} If env vars are missing or the IMS call fails. | ||
| */ | ||
| export async function getServicePrincipalToken(context) { | ||
| const imsClient = ImsClient.createFrom(context); | ||
| const { access_token: accessToken } = await imsClient.getServiceAccessTokenV3(); | ||
| return accessToken; | ||
|
Comment on lines
+722
to
+725
|
||
| } | ||
|
|
||
| /** | ||
| * Parses and retrieves a specific cookie value by name from the request context. | ||
| * Uses indexOf-based splitting to correctly handle values containing '=' | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imsUserTokennow holds either a service-principal token or a user-exchanged token. Renaming this variable to something neutral (e.g.,imsAccessToken) would avoid confusion in logs/debugging and reduce the chance of future misuse.