Skip to content

feat: add OAuth credential provider creation during deploy#407

Merged
aidandaly24 merged 4 commits intoaws:feat/gateway-integrationfrom
aidandaly24:feat/batch-3-oauth-credential-deploy
Feb 23, 2026
Merged

feat: add OAuth credential provider creation during deploy#407
aidandaly24 merged 4 commits intoaws:feat/gateway-integrationfrom
aidandaly24:feat/batch-3-oauth-credential-deploy

Conversation

@aidandaly24
Copy link
Contributor

Description

Implement OAuth credential provider creation during the deploy pipeline, running before CDK synth so credential ARNs are available in deployed-state.json for CDK to reference.

  • OAuth2 credential operations (oauth2-credential-provider.ts): Create/Get/Update operations for OAuth2 credential providers via AgentCore Identity APIs, with defensive ARN field extraction handling API response inconsistencies (credentialProviderArn vs oAuth2CredentialProviderArn)
  • Deploy pipeline integration: setupOAuth2Providers() reads client credentials from .env.local (AGENTCORE_CREDENTIAL_{NAME}_CLIENT_ID/CLIENT_SECRET), creates/updates providers, and handles "already exists" conflicts by falling back to GET
  • State persistence: Credential ARNs and callbackUrl written to deployed-state.json via buildDeployedState()
  • Deployed state schema: Added CredentialDeployedStateSchema with credentialProviderArn, clientSecretArn, and callbackUrl fields

Note: TUI deploy flow (useDeployFlow.ts) does not yet include OAuth credential setup — tracked as a follow-up task.

Related Issue

Closes #

Documentation PR

N/A

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Documentation update
  • Other (please describe):

Testing

How have you tested the change?

  • I ran npm run test:unit and npm run test:integ
  • I ran npm run typecheck
  • I ran npm run lint
  • If I modified src/assets/, I ran npm run test:update-snapshots and committed the updated snapshots

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

@github-actions github-actions bot added the size/l PR size: L label Feb 23, 2026
@aidandaly24 aidandaly24 force-pushed the feat/batch-3-oauth-credential-deploy branch from 5d184ae to 8829e3e Compare February 23, 2026 21:08
@github-actions github-actions bot added size/m PR size: M and removed size/l PR size: L labels Feb 23, 2026
@notgitika
Copy link
Contributor

/strands review

@github-actions
Copy link
Contributor

Code Review Summary

I've reviewed PR #407 which adds OAuth credential provider creation during the deploy pipeline. The implementation follows good patterns from the existing API key credential provider code, but there are some blocking issues that need to be addressed before this can be merged.


⛔ Blocking Issues

1. Missing Unit Tests for oauth2-credential-provider.ts

Location: src/cli/operations/identity/oauth2-credential-provider.ts (160 lines, no tests)

Issue: The new OAuth2 credential provider module has no unit tests, while the similar api-key-credential-provider.ts has comprehensive test coverage at src/cli/operations/identity/__tests__/api-key-credential-provider.test.ts.

Required tests:

  • oAuth2ProviderExists() - should handle exists, not found, and error cases
  • createOAuth2Provider() - should test success, conflict fallback to GET, and error cases
  • getOAuth2Provider() - should test success and error cases
  • updateOAuth2Provider() - should test success and error cases
  • extractArn() - should handle both credentialProviderArn and oAuth2CredentialProviderArn field names
  • extractResult() - should handle response parsing and missing ARN case

Reference: See api-key-credential-provider.test.ts for the testing pattern to follow.


2. Missing Tests for setupOAuth2Providers

Location: src/cli/operations/deploy/pre-deploy-identity.ts lines 276-372

Issue: The setupOAuth2Providers() function and hasOwnedIdentityOAuthProviders() helper have no test coverage. The file src/cli/operations/deploy/__tests__/pre-deploy-identity.test.ts exists but doesn't cover the new OAuth functionality.

Required tests:

  • setupOAuth2Providers() - success case with valid credentials
  • setupOAuth2Providers() - skipped case with missing env vars
  • setupOAuth2Providers() - error handling for API failures
  • setupOAuth2Providers() - merge of runtime and env credentials
  • hasOwnedIdentityOAuthProviders() - true/false cases
  • setupSingleOAuth2Provider() - create vs update logic

3. Type Safety Issue in extractResult

Location: src/cli/operations/identity/oauth2-credential-provider.ts line 49

const clientSecretArn = response.clientSecretArn as { secretArn?: string } | undefined;
return {
  credentialProviderArn,
  clientSecretArn: clientSecretArn?.secretArn,  // ⚠️ Unsafe access
  callbackUrl: response.callbackUrl as string | undefined,
};

Issue: The type cast assumes clientSecretArn is an object with a secretArn property, but if the API returns it as a string or other type, this will cause a runtime error or silently return undefined.

Fix: Add a type guard:

function extractResult(response: Record<string, unknown>): OAuth2ProviderResult | undefined {
  const credentialProviderArn = extractArn(response);
  if (!credentialProviderArn) return undefined;

  const clientSecretArnRaw = response.clientSecretArn;
  const clientSecretArn = 
    clientSecretArnRaw && typeof clientSecretArnRaw === 'object' && 'secretArn' in clientSecretArnRaw
      ? (clientSecretArnRaw as { secretArn?: string }).secretArn
      : undefined;
      
  return {
    credentialProviderArn,
    clientSecretArn,
    callbackUrl: response.callbackUrl as string | undefined,
  };
}

💡 Suggestions

4. Code Duplication Between OAuth and API Key Setup

Location: src/cli/operations/deploy/pre-deploy-identity.ts

Observation: setupOAuth2Providers() (lines 276-298) and setupApiKeyProviders() (lines 45-89) share a very similar structure:

  1. Read env file
  2. Merge with runtime credentials
  3. Create client
  4. Loop through credentials
  5. Return results with error flag

Suggestion: Consider extracting common logic into a shared helper:

async function setupCredentialProviders<TResult>(
  options: {
    projectSpec: AgentCoreProjectSpec;
    configBaseDir: string;
    region: string;
    runtimeCredentials?: SecureCredentials;
  },
  filter: (c: Credential) => boolean,
  setupFn: (client: BedrockAgentCoreControlClient, credential: Credential, creds: SecureCredentials) => Promise<TResult>
): Promise<{ results: TResult[]; hasErrors: boolean }>

This would make it easier to add future credential types and reduce maintenance burden.


5. Inconsistent Error Handling Between Create Functions

Location: oauth2-credential-provider.ts vs api-key-credential-provider.ts

Observation:

  • createOAuth2Provider() on conflict: Falls back to getOAuth2Provider() to retrieve provider data
  • createApiKeyProvider() on conflict: Returns { success: true } immediately (no data)

Question: Why does OAuth need to fetch the ARN back on conflict while API key doesn't? Is this because the ARN is needed in deployed-state.json?

Suggestion: Add a comment explaining this difference, or unify the behavior if possible. The current difference might confuse future maintainers.


6. Missing Validation for OAuth Credential Fields

Location: src/cli/operations/deploy/pre-deploy-identity.ts lines 331-337

const params = {
  name: credential.name,
  vendor: credential.vendor,          // ⚠️ Not validated
  discoveryUrl: credential.discoveryUrl,  // ⚠️ Not validated
  clientId,
  clientSecret,
};

Issue: While the schema validates these fields when the credential is added, there's no runtime validation before passing to the AWS SDK.

Suggestion: Add validation or at least a type assertion:

const params: OAuth2ProviderParams = {
  name: credential.name,
  vendor: credential.vendor,  // Type system ensures this is string from schema
  discoveryUrl: credential.discoveryUrl,
  clientId,
  clientSecret,
};

Consider validating that vendor is a valid CredentialProviderVendorType at runtime if the AWS SDK provides an enum.


❓ Questions

7. TUI Deploy Flow Not Updated

From PR Description:

Note: TUI deploy flow (useDeployFlow.ts) does not yet include OAuth credential setup — tracked as a follow-up task.

Question: Is it acceptable to merge this without TUI support? This means:

  • agentcore deploy (CLI) will support OAuth credential setup ✅
  • agentcore (TUI) → Deploy will NOT support OAuth credential setup ❌

Impact: Users who rely on the TUI will not be able to deploy projects with OAuth credentials until the follow-up is completed.

Recommendation: Either:

  1. Update TUI in this PR to maintain feature parity, OR
  2. Add a clear warning in the TUI when OAuth credentials are detected, OR
  3. Document this limitation in the PR and ensure the follow-up task is tracked

8. Missing Related Issue Number

Location: PR description

Issue: The "Related Issue" section shows "Closes #" with no issue number.

Per CONTRIBUTING.md line 25:

Every PR must be linked to an issue. Open an issue first (or find an existing one) and reference it in your PR using Closes #issue-number.

Question: What issue does this PR close? Please update the PR description.


🎨 Nits

9. Naming Inconsistency

Observation:

  • Function names: oAuth2ProviderExists, setupOAuth2Providers (mixed case)
  • AWS SDK: CreateOauth2CredentialProviderCommand (camelCase)
  • Type names: OAuth2ProviderResult, OAuth2ProviderParams (PascalCase)

Suggestion: For consistency:

  • Types and exports: OAuth2 (PascalCase with uppercase OAuth)
  • Internal functions: oauth2 (camelCase)
  • This aligns with TypeScript naming conventions

✅ Positive Observations

  • Defensive programming: The extractArn() function handles API response field inconsistencies well
  • Error handling: Good use of isNoCredentialsError() for clear error messages
  • Documentation: JSDoc comments clearly explain why this code exists (Identity not yet modeled as CDK constructs)
  • Consistency: Follows patterns from existing api-key-credential-provider.ts
  • Schema design: CredentialDeployedStateSchema is clean and extensible
  • Export organization: Proper updates to index files for clean API surface

Recommendation

Do not merge until:

  1. ✅ Unit tests added for oauth2-credential-provider.ts
  2. ✅ Tests added for setupOAuth2Providers and related functions
  3. ✅ Type safety issue fixed in extractResult
  4. ✅ Related issue number added to PR description

Once blocking issues are resolved, the suggestions and questions can be addressed in follow-up PRs if preferred.

@github-actions
Copy link
Contributor

Additional Finding: OAuth Credentials Not Read from process.env

🐛 Bug: Runtime OAuth Credentials Not Supported

Location: src/cli/commands/deploy/actions.ts lines 172-182

Issue: The code reads runtime credentials from process.env for non-interactive deploy (with -y flag), but it only collects API key credentials:

// Read runtime credentials from process.env (enables non-interactive deploy with -y)
const neededCredentials = getAllCredentials(context.projectSpec);  // ⚠️ Only returns API key creds
const envCredentials: Record<string, string> = {};
for (const cred of neededCredentials) {
  const value = process.env[cred.envVarName];
  if (value) {
    envCredentials[cred.envVarName] = value;
  }
}
const runtimeCredentials =
  Object.keys(envCredentials).length > 0 ? new SecureCredentials(envCredentials) : undefined;

Root cause: getAllCredentials() in pre-deploy-identity.ts line 232 only checks for ApiKeyCredentialProvider:

export function getAllCredentials(projectSpec: AgentCoreProjectSpec): MissingCredential[] {
  const credentials: MissingCredential[] = [];

  for (const credential of projectSpec.credentials) {
    if (credential.type === 'ApiKeyCredentialProvider') {  // ⚠️ Doesn't handle OAuth
      credentials.push({
        providerName: credential.name,
        envVarName: computeDefaultCredentialEnvVarName(credential.name),
      });
    }
  }

  return credentials;
}

Impact:

  • OAuth credentials from process.env are NOT passed to setupOAuth2Providers as runtimeCredentials
  • Non-interactive deploy with -y flag will fail for OAuth credentials if they're only in environment variables
  • Works if credentials are in .env.local, but not for CI/CD scenarios where credentials come from environment

Fix: Update getAllCredentials to also collect OAuth credentials:

export function getAllCredentials(projectSpec: AgentCoreProjectSpec): MissingCredential[] {
  const credentials: MissingCredential[] = [];

  for (const credential of projectSpec.credentials) {
    if (credential.type === 'ApiKeyCredentialProvider') {
      credentials.push({
        providerName: credential.name,
        envVarName: computeDefaultCredentialEnvVarName(credential.name),
      });
    } else if (credential.type === 'OAuthCredentialProvider') {
      const nameKey = credential.name.toUpperCase().replace(/-/g, '_');
      credentials.push(
        {
          providerName: credential.name,
          envVarName: `AGENTCORE_CREDENTIAL_${nameKey}_CLIENT_ID`,
        },
        {
          providerName: credential.name,
          envVarName: `AGENTCORE_CREDENTIAL_${nameKey}_CLIENT_SECRET`,
        }
      );
    }
  }

  return credentials;
}

Alternatively, you might want to create a separate function getAllOAuthCredentials() and call it separately if the logic becomes too complex.


This should be considered blocking as it breaks non-interactive OAuth credential deployments.

@github-actions
Copy link
Contributor

Review Complete ✅

I've finished reviewing PR #407. Here's the summary:

📊 Review Stats

  • Files changed: 7
  • Lines added: ~290
  • Blocking issues: 4
  • Suggestions: 3
  • Questions: 2
  • Nits: 1

🚫 Blocking Issues Summary

  1. Missing unit tests for oauth2-credential-provider.ts (160 lines, 0 tests)
  2. Missing tests for setupOAuth2Providers() and related functions
  3. Type safety issue in extractResult() - unsafe object property access
  4. OAuth credentials not read from process.env - breaks non-interactive deploy with -y flag

⏭️ Next Steps

Before this PR can be merged:

  1. Add unit tests for all new functions in oauth2-credential-provider.ts
  2. Add tests for OAuth setup functions in pre-deploy-identity.test.ts
  3. Fix type safety issue in extractResult() with proper type guard
  4. Update getAllCredentials() to include OAuth CLIENT_ID and CLIENT_SECRET env vars
  5. Add related issue number to PR description (required by CONTRIBUTING.md)

The suggestions and questions can be addressed in follow-up PRs if needed, but the blocking issues should be resolved before merge.

💚 What's Good

The implementation shows solid engineering:

  • Follows existing patterns consistently
  • Good defensive programming (ARN field extraction)
  • Clear documentation explaining architectural decisions
  • Proper error handling throughout
  • Clean schema design

Once the blocking issues are addressed, this will be a solid addition to the codebase! 🚀

@aidandaly24 aidandaly24 force-pushed the feat/batch-3-oauth-credential-deploy branch from 8829e3e to a717414 Compare February 23, 2026 21:31
@github-actions github-actions bot added size/m PR size: M and removed size/m PR size: M labels Feb 23, 2026

// Add credential state if credentials exist
if (credentials && Object.keys(credentials).length > 0) {
targetState.resources!.credentials = credentials;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is ! needed? we just checked for it above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ! is required — resources is typed as optional in TargetDeployedState even though we initialize it in the literal above. TypeScript can't narrow it.

Comment on lines +276 to +298
export async function setupOAuth2Providers(options: SetupOAuth2ProvidersOptions): Promise<PreDeployOAuth2Result> {
const { projectSpec, configBaseDir, region, runtimeCredentials } = options;
const results: OAuth2ProviderSetupResult[] = [];
const credentials = getCredentialProvider();

const envVars = await readEnvFile(configBaseDir);
const envCredentials = SecureCredentials.fromEnvVars(envVars);
const allCredentials = runtimeCredentials ? envCredentials.merge(runtimeCredentials) : envCredentials;

const client = new BedrockAgentCoreControlClient({ region, credentials });

for (const credential of projectSpec.credentials) {
if (credential.type === 'OAuthCredentialProvider') {
const result = await setupSingleOAuth2Provider(client, credential, allCredentials);
results.push(result);
}
}

return {
results,
hasErrors: results.some(r => r.status === 'error'),
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Client is created per-call to setupOAuth2Providers but not shared with setupApiKeyProviders.

Both functions create their own BedrockAgentCoreControlClient. If credentials or region config diverge between the two calls, you'd get inconsistent behavior.

This adds another duplicated client instance. We have an existing issue: #342

Maybe this can be addressed in a diff PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, the duplicate client is a known issue tracked in #342. Happy to address here if you'd prefer, but keeping it consistent with the existing setupApiKeyProviders pattern for now.

Comment on lines +75 to +89
function buildOAuth2Config(params: OAuth2ProviderParams) {
return {
name: params.name,
credentialProviderVendor: params.vendor as CredentialProviderVendorType,
oauth2ProviderConfigInput: {
customOauth2ProviderConfig: {
clientId: params.clientId,
clientSecret: params.clientSecret,
oauthDiscovery: {
discoveryUrl: params.discoveryUrl,
},
},
},
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The vendor field is cast to CredentialProviderVendorType, which suggests there are known vendor presets. But the config always builds a customOauth2ProviderConfig regardless of the vendor value. If a vendor like "Google" or "Microsoft" has a dedicated config path in the API, this would send it through the wrong config shape. Is this intentional?

Copy link
Contributor Author

@aidandaly24 aidandaly24 Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. The API does have vendor-specific config paths (googleOauth2ProviderConfig, githubOauth2ProviderConfig, etc.) with simpler shapes (just clientId/clientSecret, no discovery URL). Our schema defaults vendor to 'CustomOauth2' and the CLI doesn't expose vendor selection yet, so this works for Phase 1. When we add vendor selection in a future task, we'll need to route to the correct config path based on vendor. Added a comment noting this.

Comment on lines +103 to +109
return { success: false, error: 'No credential provider ARN in response' };
}
return { success: true, result };
} catch (error) {
const errorName = (error as { name?: string }).name;
if (errorName === 'ConflictException' || errorName === 'ResourceAlreadyExistsException') {
return getOAuth2Provider(client, params.name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When createOAuth2Provider catches a ConflictException, it falls back to getOAuth2Provider returning the existing provider without updating it.

But the caller in setupSingleOAuth2Provider (pre-deploy-identity.ts:340) already checks existence and routes to update. So this fallback only triggers in a race condition where another process created the provider between the exists-check and the create call. In that case, the user's new clientId/clientSecret would be silently ignored. Should this fall back to updateOAuth2Provider instead?

Comment on lines +35 to +40
function extractArn(response: Record<string, unknown>): string | undefined {
return (
(response.credentialProviderArn as string | undefined) ??
(response.oAuth2CredentialProviderArn as string | undefined)
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Casting to Record<string, unknown> everywhere bypasses the SDK types — if the field name changes again we won't get a compile error, it'll just silently return undefined. Can we at least add a comment noting which SDK version has the credentialProviderArn vs oAuth2CredentialProviderArn inconsistency? That way someone can clean this up once the API stabilizes instead of it living forever.

@github-actions github-actions bot added size/m PR size: M and removed size/m PR size: M labels Feb 23, 2026
@github-actions github-actions bot added size/m PR size: M and removed size/m PR size: M labels Feb 23, 2026
@github-actions github-actions bot added size/m PR size: M and removed size/m PR size: M labels Feb 23, 2026
Copy link
Contributor

@notgitika notgitika left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM thank you!

@aidandaly24 aidandaly24 merged commit ab4b481 into aws:feat/gateway-integration Feb 23, 2026
15 of 16 checks passed
aidandaly24 added a commit that referenced this pull request Mar 2, 2026
* feat: add OAuth credential provider creation during deploy

* fix: address review comments — add clarifying comments for vendor config, race condition, and ARN inconsistency

* fix: use typed SDK responses instead of Record<string, unknown> casts

* fix: on conflict, update OAuth provider instead of GET to avoid silently ignoring new credentials
aidandaly24 added a commit that referenced this pull request Mar 2, 2026
* feat: mcp gateway schema types (auth, outbound auth, OAuth credentials) (#375)

* ci: add feat/gateway-integration branch to workflow triggers (#376)

* feat: mcp gateway schema types (auth, outbound auth, OAuth credentials)

* fix: address CR feedback — scopes optional, specific validation errors

* refactor: rename mcp-tool to gateway-target across CLI (#377)

* feat: enable gateway commands, UI updates, deploy pipeline, credential validation (#382)

* feat: add external MCP server target support and unassigned targets (#406)

* feat: add OAuth credential provider creation during deploy (#407)

* feat: add OAuth credential provider creation during deploy

* fix: address review comments — add clarifying comments for vendor config, race condition, and ARN inconsistency

* fix: use typed SDK responses instead of Record<string, unknown> casts

* fix: on conflict, update OAuth provider instead of GET to avoid silently ignoring new credentials

* refactor: remove exposure/mcp-runtime mode from gateway-target command (#414)

* refactor: remove exposure/mcp-runtime mode from gateway-target command

All gateway targets are now behind-gateway only. The mcp-runtime
exposure mode was disabled and never used by customers.

- Remove ExposureMode type, EXPOSURE_MODE_OPTIONS, --exposure and --agents CLI flags
- Simplify wizard flow: name → source → language → gateway → host → confirm
- Remove mcp-runtime code paths from create-mcp, remove-gateway-target, McpGuidedEditor
- Remove existingAgents prop chain (only used for mcp-runtime agent selection)
- Clean up unused imports (ViewMode, AgentCoreMcpRuntimeTool, WizardMultiSelect)

* test: update tests for exposure removal

- Remove mcp-runtime validation tests and fixtures
- Remove mcp-runtime integration tests (add and remove)
- Simplify gateway target test fixtures to behind-gateway only

* style: fix formatting

* test: add unit tests for Batches 1-3 gateway functionality (#415)

Comprehensive test coverage for MCP Gateway Phase 1 Batches 1-3:

- Schema validation: gateway targets, outbound auth, credentials, deployed state
- OAuth credential provider: CRUD operations, conflict handling, error paths
- Pre-deploy identity: OAuth setup, credential collection, env var mapping
- CLI validation: existing-endpoint path, credential validation
- Deploy outputs: buildDeployedState with credentials, parseGatewayOutputs
- External target creation: assignment, unassigned, duplicates, outboundAuth
- Gateway target removal: listing, preview, removal operations
- Preflight: gateway-only deploy validation
- Credential references: cross-gateway warning on removal
- Add command actions: buildGatewayTargetConfig mapping
- UI: AddScreen/RemoveScreen enablement, ResourceGraph unassigned targets
- Types: constants validation (AUTHORIZER_TYPE_OPTIONS, SKIP_FOR_NOW, SOURCE_OPTIONS)

Adds 86 new test cases across 17 files.

* feat: assign unassigned targets to gateways and preserve targets on removal (#410)

* feat: assign unassigned targets to gateways and preserve targets on removal

* test: add unit tests for unassigned target assignment and gateway removal

- getUnassignedTargets: returns targets, empty when no config, empty when field missing
- createGatewayFromWizard: moves selected targets to new gateway, removes from unassigned
- removeGateway: preserves targets as unassigned on removal, no-op for empty gateways
- previewRemoveGateway: shows 'will become unassigned' warning

* style: fix formatting and merge duplicate imports

* docs: add comment explaining unassigned targets preservation

* feat: add OAuth credential support to add identity and outbound auth CLI flags (#416)

* feat: add OAuth credential support to add identity and outbound auth CLI flags

Extend createCredential to support OAuth credentials alongside API keys:
- CreateCredentialConfig is now a discriminated union (ApiKey vs OAuth)
- OAuth writes CLIENT_ID and CLIENT_SECRET to .env.local
- OAuth writes OAuthCredentialProvider config to agentcore.json

Add CLI flags for non-interactive workflows:
- add identity: --type oauth, --discovery-url, --client-id, --client-secret, --scopes
- add gateway-target: --outbound-auth, --credential-name, --oauth-client-id,
  --oauth-client-secret, --oauth-discovery-url, --oauth-scopes
- Inline OAuth credential creation when --oauth-* fields provided without --credential-name

Adds 15 new tests covering OAuth credential creation, validation, and edge cases.

* fix: use || instead of ?? for empty string handling and add discoveryUrl validation

* fix: sanitize hyphens in credential env var names for POSIX compliance

* test: update env var expectations for hyphen-to-underscore sanitization

* fix: use nullish coalescing operator in validate.ts (#429)

Fix ESLint prefer-nullish-coalescing errors.

* feat: add OAuth credential setup and gateway output parsing to TUI deploy flow (#411)

* feat: add OAuth credential setup and gateway output parsing to TUI deploy flow

* refactor: rename hasOwned* to has* identity provider helpers

* fix: log gateway config errors instead of silently catching

* feat: display gateway target sync status after deploy (#419)

Query ListGatewayTargets after successful deployment and display
sync status for each target:
- READY: ✓ synced
- SYNCHRONIZING: ⟳ syncing...
- FAILED: ✗ failed

Integrated into both CLI and TUI deploy paths. TUI uses React state
for proper rendering. API errors are non-blocking — deploy succeeds
regardless of status query result.

* refactor: remove gateway bind flow from add gateway TUI (#431)

Gateways are project-level in Phase 1 — all agents get all gateways
automatically via CDK env vars. The bind-agent-to-gateway flow was
pre-Phase 1 code that is no longer needed.

Add gateway now goes straight to the create wizard.

* fix: prettier formatting for gateway-status.ts (#449)

* feat: add gateway auth and multi-gateway support to agent templates (#427)

* feat: add gateway auth support to agent templates

Add SigV4 authentication to MCP client templates so agents can
authenticate with AWS_IAM gateways. Each framework's client.py
uses Handlebars conditionals to include auth when gateways exist.

SigV4HTTPXAuth class signs HTTP requests using botocore SigV4Auth,
passed to the MCP client via httpx.AsyncClient. Templates read
gateway URLs from AGENTCORE_GATEWAY_{NAME}_URL env vars and handle
missing vars gracefully (warn, don't crash).

Updated all 5 frameworks: Strands, LangChain, OpenAI Agents,
Google ADK, AutoGen. Schema mapper reads mcp.json to populate
gateway config for template rendering. All gateways are auto-
included when creating an agent.

* feat: add multi-gateway support and fix template rendering

Replace single-gateway [0] indexing with {{#each gatewayProviders}}
loops. Each gateway gets its own client function (Strands) or entry
in the servers dict (LangChain/OpenAI/AutoGen/ADK).

Add snakeCase Handlebars helper for gateway function names.
Add gatewayAuthTypes array for conditional SigV4 imports.
Fix @index parse error by using plain variable names.

* fix: update main.py files with gateway conditional imports

All 5 framework main.py files now use Handlebars conditionals to
import the correct MCP client function based on hasGateway flag.
Fix snakeCase helper to handle all special characters.

* style: fix formatting

* refactor: use mcp-proxy-for-aws for gateway auth, remove AutoGen gateway support

Replace custom SigV4HTTPXAuth class with official mcp-proxy-for-aws package:
- Strands: aws_iam_streamablehttp_client factory pattern
- LangChain: SigV4HTTPXAuth via auth param in MultiServerMCPClient config
- OpenAI Agents: SigV4HTTPXAuth via httpx_client_factory param
- Google ADK: SigV4HTTPXAuth via httpx_client_factory in StreamableHTTPConnectionParams

Revert AutoGen to original upstream — SDK doesn't support custom
httpx auth (no httpx_client_factory param).

* fix: pass AWS region to aws_iam_streamablehttp_client in Strands template

* refactor: remove dead agent binding step from add gateway wizard (#456)

* feat: wire existing-endpoint flow for gateway targets (#455)

* feat: wire existing-endpoint flow for gateway targets

* test: add routing and validation tests for existing-endpoint flow

* refactor: remove source/language/host steps, existing-endpoint is the only flow

* fix: CDK template types and credential ARN passthrough for gateway deploy (#432)

* fix: correct CDK template type names and prop names

The CDK stack template used McpSpec (doesn't exist) instead of
AgentCoreMcpSpec, and passed wrong prop names to AgentCoreMcp:
- spec → mcpSpec
- application → agentCoreApplication
- Added missing projectName prop

* fix: collect API key credential ARNs and write to deployed state before CDK synth

API key credential providers were created during deploy but their ARNs
were not stored in deployed state, causing CDK to fail with 'Credential
not found in deployed state' for gateway targets with API key auth.

- Return credentialProviderArn from create/update API key providers
- Unify API key and OAuth credential ARNs into single deployed state map
- Move credential setup before CDK synth so template can read ARNs
- Write partial deployed state with credentials before synth

* fix: pass credential ARNs from deployed state to CDK gateway construct

CDK template now reads deployed-state.json and extracts credential
provider ARNs per target, passing them to AgentCoreMcp so gateway
targets can reference outbound auth credentials.

* fix: reorder TUI preflight to create credentials before CDK synth

* fix: fetch OAuth credential ARN via Get after create/update

* fix: handle Mcp prefix in gateway output key parsing

* fix: bump CDK version to 2.239.0 in project template

* fix: lint errors in deploy actions and preflight hook

* feat: set gateway env vars in agentcore dev for local testing (#428)

Read deployed-state.json for gateway URLs and mcp.json for auth types,
then set AGENTCORE_GATEWAY_{NAME}_URL and AGENTCORE_GATEWAY_{NAME}_AUTH_TYPE
env vars when running agentcore dev locally.

- New gateway-env.ts helper iterates all deployment targets
- Integrated in both CLI dev command and TUI dev hook
- .env.local values take precedence over gateway env vars
- Graceful fallback when no deployed state exists
- Fixed parseGatewayOutputs to parse Id, Arn, and Url outputs separately
- Added gatewayUrl field to deployed-state schema (optional, backward compat)

* fix: prettier formatting for upstream files (#461)

* refactor: remove dead bind flow and rename MCP Tool to Gateway Target (#459)

* refactor: remove mode selection and bind flow from gateway target wizard

* fix: rename 'MCP Tool' to 'Gateway Target' in UI labels, CLI output, and comments

* fix: update CDK asset snapshot for cdk/bin/cdk.ts

* fix: prettier formatting for AddGatewayTargetFlow.tsx

* feat: add outbound auth wizard step with inline credential creation (#417)

* fix: require gateway when creating a gateway target (#469)

* fix: require gateway when creating a gateway target

A gateway target must always be attached to a gateway. Previously it was
possible to create unassigned targets via "Skip for now" in the TUI or
by omitting --gateway in non-interactive mode.

- Validation now requires --gateway and verifies the gateway exists
- TUI removes the "Skip for now" option from gateway selection
- createExternalGatewayTarget rejects missing gateway at operations layer
- Updated tests to cover all new validation paths

* style: fix prettier formatting

* fix: correct gateway success message to reference gateway-target command (#468)

* feat: add OAuth credential type to add identity TUI wizard (#464)

* feat: add OAuth credential type to add identity TUI wizard

* fix: add OIDC well-known suffix validation to identity TUI discovery URL

* refactor: reuse identity screen for OAuth credential creation in gateway target flow

* fix: correct deploy step ordering and credential count display

* fix: allow identity creation without existing agents

* fix: rename MCP gateway references to gateway in UI text

* fix: add missing newline to identity types

* feat: implement inbound auth (#467)

* feat: extend JWT wizard with allowedScopes and agent OAuth credential inputs

* feat: auto-create managed OAuth credential for CUSTOM_JWT gateway

* feat: add CLI flags for CUSTOM_JWT agent OAuth credentials

* feat: add CUSTOM_JWT Bearer token auth to agent templates (Strands, LangChain, OpenAI, Google ADK)

* feat: protect managed credentials from accidental deletion

* test: add tests for CUSTOM_JWT CLI validation and managed credential protection

* fix: resolve httpx import collision between AWS_IAM and CUSTOM_JWT templates

* fix: use placeholder instead of initialValue for gateway discovery URL

* feat: wire CUSTOM_JWT inbound auth through AgentCore identity system

* fix: prettier formatting and remove redundant condition

* fix: sanitize OAuth error to prevent clear-text logging of sensitive data

---------

Co-authored-by: Tejas Kashinath <42380254+tejaskash@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants