@@ -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
@@ -238,3 +243,130 @@ export function getAllCredentials(projectSpec: AgentCoreProjectSpec): MissingCre
238243
239244 return credentials ;
240245}
246+
247+ // ─────────────────────────────────────────────────────────────────────────────
248+ // OAuth2 Credential Provider Setup
249+ // ─────────────────────────────────────────────────────────────────────────────
250+
251+ export interface OAuth2ProviderSetupResult {
252+ providerName : string ;
253+ status : 'created' | 'updated' | 'skipped' | 'error' ;
254+ error ?: string ;
255+ credentialProviderArn ?: string ;
256+ clientSecretArn ?: string ;
257+ callbackUrl ?: string ;
258+ }
259+
260+ export interface SetupOAuth2ProvidersOptions {
261+ projectSpec : AgentCoreProjectSpec ;
262+ configBaseDir : string ;
263+ region : string ;
264+ runtimeCredentials ?: SecureCredentials ;
265+ }
266+
267+ export interface PreDeployOAuth2Result {
268+ results : OAuth2ProviderSetupResult [ ] ;
269+ hasErrors : boolean ;
270+ }
271+
272+ /**
273+ * Set up OAuth2 credential providers for all OAuth credentials in the project.
274+ * Reads client credentials from agentcore/.env.local and creates providers in AgentCore Identity.
275+ */
276+ export async function setupOAuth2Providers ( options : SetupOAuth2ProvidersOptions ) : Promise < PreDeployOAuth2Result > {
277+ const { projectSpec, configBaseDir, region, runtimeCredentials } = options ;
278+ const results : OAuth2ProviderSetupResult [ ] = [ ] ;
279+ const credentials = getCredentialProvider ( ) ;
280+
281+ const envVars = await readEnvFile ( configBaseDir ) ;
282+ const envCredentials = SecureCredentials . fromEnvVars ( envVars ) ;
283+ const allCredentials = runtimeCredentials ? envCredentials . merge ( runtimeCredentials ) : envCredentials ;
284+
285+ const client = new BedrockAgentCoreControlClient ( { region, credentials } ) ;
286+
287+ for ( const credential of projectSpec . credentials ) {
288+ if ( credential . type === 'OAuthCredentialProvider' ) {
289+ const result = await setupSingleOAuth2Provider ( client , credential , allCredentials ) ;
290+ results . push ( result ) ;
291+ }
292+ }
293+
294+ return {
295+ results,
296+ hasErrors : results . some ( r => r . status === 'error' ) ,
297+ } ;
298+ }
299+
300+ /**
301+ * Check if the project has any OAuth credentials that need setup.
302+ */
303+ export function hasOwnedIdentityOAuthProviders ( projectSpec : AgentCoreProjectSpec ) : boolean {
304+ return projectSpec . credentials . some ( c => c . type === 'OAuthCredentialProvider' ) ;
305+ }
306+
307+ async function setupSingleOAuth2Provider (
308+ client : BedrockAgentCoreControlClient ,
309+ credential : Credential ,
310+ credentials : SecureCredentials
311+ ) : Promise < OAuth2ProviderSetupResult > {
312+ if ( credential . type !== 'OAuthCredentialProvider' ) {
313+ return { providerName : credential . name , status : 'error' , error : 'Invalid credential type' } ;
314+ }
315+
316+ const nameKey = credential . name . toUpperCase ( ) . replace ( / - / g, '_' ) ;
317+ const clientIdEnvVar = `AGENTCORE_CREDENTIAL_${ nameKey } _CLIENT_ID` ;
318+ const clientSecretEnvVar = `AGENTCORE_CREDENTIAL_${ nameKey } _CLIENT_SECRET` ;
319+
320+ const clientId = credentials . get ( clientIdEnvVar ) ;
321+ const clientSecret = credentials . get ( clientSecretEnvVar ) ;
322+
323+ if ( ! clientId || ! clientSecret ) {
324+ return {
325+ providerName : credential . name ,
326+ status : 'skipped' ,
327+ error : `Missing ${ clientIdEnvVar } or ${ clientSecretEnvVar } in agentcore/.env.local` ,
328+ } ;
329+ }
330+
331+ const params = {
332+ name : credential . name ,
333+ vendor : credential . vendor ,
334+ discoveryUrl : credential . discoveryUrl ,
335+ clientId,
336+ clientSecret,
337+ } ;
338+
339+ try {
340+ const exists = await oAuth2ProviderExists ( client , credential . name ) ;
341+
342+ if ( exists ) {
343+ const updateResult = await updateOAuth2Provider ( client , params ) ;
344+ return {
345+ providerName : credential . name ,
346+ status : updateResult . success ? 'updated' : 'error' ,
347+ error : updateResult . error ,
348+ credentialProviderArn : updateResult . result ?. credentialProviderArn ,
349+ clientSecretArn : updateResult . result ?. clientSecretArn ,
350+ callbackUrl : updateResult . result ?. callbackUrl ,
351+ } ;
352+ }
353+
354+ const createResult = await createOAuth2Provider ( client , params ) ;
355+ return {
356+ providerName : credential . name ,
357+ status : createResult . success ? 'created' : 'error' ,
358+ error : createResult . error ,
359+ credentialProviderArn : createResult . result ?. credentialProviderArn ,
360+ clientSecretArn : createResult . result ?. clientSecretArn ,
361+ callbackUrl : createResult . result ?. callbackUrl ,
362+ } ;
363+ } catch ( error ) {
364+ let errorMessage : string ;
365+ if ( isNoCredentialsError ( error ) ) {
366+ errorMessage = 'AWS credentials not found. Run `aws sso login` or set AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY.' ;
367+ } else {
368+ errorMessage = error instanceof Error ? error . message : String ( error ) ;
369+ }
370+ return { providerName : credential . name , status : 'error' , error : errorMessage } ;
371+ }
372+ }
0 commit comments