@@ -4,6 +4,11 @@ import { getCredentialProvider } from '../../aws';
44import { isNoCredentialsError } from '../../errors' ;
55import { apiKeyProviderExists , createApiKeyProvider , setTokenVaultKmsKey , updateApiKeyProvider } from '../identity' ;
66import { computeDefaultCredentialEnvVarName } from '../identity/create-identity' ;
7+ import {
8+ createOAuth2Provider ,
9+ oAuth2ProviderExists ,
10+ updateOAuth2Provider ,
11+ } from '../identity/oauth2-credential-provider' ;
712import { BedrockAgentCoreControlClient , GetTokenVaultCommand } from '@aws-sdk/client-bedrock-agentcore-control' ;
813import { CreateKeyCommand , KMSClient } from '@aws-sdk/client-kms' ;
914
@@ -222,7 +227,7 @@ export async function getMissingCredentials(
222227}
223228
224229/**
225- * Get list of all API key credentials in the project (for manual entry prompt).
230+ * Get list of all credentials in the project that need env vars (for manual entry prompt and runtime credential reading ).
226231 */
227232export function getAllCredentials ( projectSpec : AgentCoreProjectSpec ) : MissingCredential [ ] {
228233 const credentials : MissingCredential [ ] = [ ] ;
@@ -233,8 +238,141 @@ export function getAllCredentials(projectSpec: AgentCoreProjectSpec): MissingCre
233238 providerName : credential . name ,
234239 envVarName : computeDefaultCredentialEnvVarName ( credential . name ) ,
235240 } ) ;
241+ } else if ( credential . type === 'OAuthCredentialProvider' ) {
242+ const nameKey = credential . name . toUpperCase ( ) . replace ( / - / g, '_' ) ;
243+ credentials . push (
244+ { providerName : credential . name , envVarName : `AGENTCORE_CREDENTIAL_${ nameKey } _CLIENT_ID` } ,
245+ { providerName : credential . name , envVarName : `AGENTCORE_CREDENTIAL_${ nameKey } _CLIENT_SECRET` }
246+ ) ;
236247 }
237248 }
238249
239250 return credentials ;
240251}
252+
253+ // ─────────────────────────────────────────────────────────────────────────────
254+ // OAuth2 Credential Provider Setup
255+ // ─────────────────────────────────────────────────────────────────────────────
256+
257+ export interface OAuth2ProviderSetupResult {
258+ providerName : string ;
259+ status : 'created' | 'updated' | 'skipped' | 'error' ;
260+ error ?: string ;
261+ credentialProviderArn ?: string ;
262+ clientSecretArn ?: string ;
263+ callbackUrl ?: string ;
264+ }
265+
266+ export interface SetupOAuth2ProvidersOptions {
267+ projectSpec : AgentCoreProjectSpec ;
268+ configBaseDir : string ;
269+ region : string ;
270+ runtimeCredentials ?: SecureCredentials ;
271+ }
272+
273+ export interface PreDeployOAuth2Result {
274+ results : OAuth2ProviderSetupResult [ ] ;
275+ hasErrors : boolean ;
276+ }
277+
278+ /**
279+ * Set up OAuth2 credential providers for all OAuth credentials in the project.
280+ * Reads client credentials from agentcore/.env.local and creates providers in AgentCore Identity.
281+ */
282+ export async function setupOAuth2Providers ( options : SetupOAuth2ProvidersOptions ) : Promise < PreDeployOAuth2Result > {
283+ const { projectSpec, configBaseDir, region, runtimeCredentials } = options ;
284+ const results : OAuth2ProviderSetupResult [ ] = [ ] ;
285+ const credentials = getCredentialProvider ( ) ;
286+
287+ const envVars = await readEnvFile ( configBaseDir ) ;
288+ const envCredentials = SecureCredentials . fromEnvVars ( envVars ) ;
289+ const allCredentials = runtimeCredentials ? envCredentials . merge ( runtimeCredentials ) : envCredentials ;
290+
291+ const client = new BedrockAgentCoreControlClient ( { region, credentials } ) ;
292+
293+ for ( const credential of projectSpec . credentials ) {
294+ if ( credential . type === 'OAuthCredentialProvider' ) {
295+ const result = await setupSingleOAuth2Provider ( client , credential , allCredentials ) ;
296+ results . push ( result ) ;
297+ }
298+ }
299+
300+ return {
301+ results,
302+ hasErrors : results . some ( r => r . status === 'error' ) ,
303+ } ;
304+ }
305+
306+ /**
307+ * Check if the project has any OAuth credentials that need setup.
308+ */
309+ export function hasOwnedIdentityOAuthProviders ( projectSpec : AgentCoreProjectSpec ) : boolean {
310+ return projectSpec . credentials . some ( c => c . type === 'OAuthCredentialProvider' ) ;
311+ }
312+
313+ async function setupSingleOAuth2Provider (
314+ client : BedrockAgentCoreControlClient ,
315+ credential : Credential ,
316+ credentials : SecureCredentials
317+ ) : Promise < OAuth2ProviderSetupResult > {
318+ if ( credential . type !== 'OAuthCredentialProvider' ) {
319+ return { providerName : credential . name , status : 'error' , error : 'Invalid credential type' } ;
320+ }
321+
322+ const nameKey = credential . name . toUpperCase ( ) . replace ( / - / g, '_' ) ;
323+ const clientIdEnvVar = `AGENTCORE_CREDENTIAL_${ nameKey } _CLIENT_ID` ;
324+ const clientSecretEnvVar = `AGENTCORE_CREDENTIAL_${ nameKey } _CLIENT_SECRET` ;
325+
326+ const clientId = credentials . get ( clientIdEnvVar ) ;
327+ const clientSecret = credentials . get ( clientSecretEnvVar ) ;
328+
329+ if ( ! clientId || ! clientSecret ) {
330+ return {
331+ providerName : credential . name ,
332+ status : 'skipped' ,
333+ error : `Missing ${ clientIdEnvVar } or ${ clientSecretEnvVar } in agentcore/.env.local` ,
334+ } ;
335+ }
336+
337+ const params = {
338+ name : credential . name ,
339+ vendor : credential . vendor ,
340+ discoveryUrl : credential . discoveryUrl ,
341+ clientId,
342+ clientSecret,
343+ } ;
344+
345+ try {
346+ const exists = await oAuth2ProviderExists ( client , credential . name ) ;
347+
348+ if ( exists ) {
349+ const updateResult = await updateOAuth2Provider ( client , params ) ;
350+ return {
351+ providerName : credential . name ,
352+ status : updateResult . success ? 'updated' : 'error' ,
353+ error : updateResult . error ,
354+ credentialProviderArn : updateResult . result ?. credentialProviderArn ,
355+ clientSecretArn : updateResult . result ?. clientSecretArn ,
356+ callbackUrl : updateResult . result ?. callbackUrl ,
357+ } ;
358+ }
359+
360+ const createResult = await createOAuth2Provider ( client , params ) ;
361+ return {
362+ providerName : credential . name ,
363+ status : createResult . success ? 'created' : 'error' ,
364+ error : createResult . error ,
365+ credentialProviderArn : createResult . result ?. credentialProviderArn ,
366+ clientSecretArn : createResult . result ?. clientSecretArn ,
367+ callbackUrl : createResult . result ?. callbackUrl ,
368+ } ;
369+ } catch ( error ) {
370+ let errorMessage : string ;
371+ if ( isNoCredentialsError ( error ) ) {
372+ errorMessage = 'AWS credentials not found. Run `aws sso login` or set AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY.' ;
373+ } else {
374+ errorMessage = error instanceof Error ? error . message : String ( error ) ;
375+ }
376+ return { providerName : credential . name , status : 'error' , error : errorMessage } ;
377+ }
378+ }
0 commit comments