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