Configure AWS Bedrock OAuth2 Credential Providers

The aws:bedrock/agentcoreOauth2CredentialProvider:AgentcoreOauth2CredentialProvider resource, part of the Pulumi AWS provider, configures OAuth2 credential providers that enable Bedrock agents to authenticate with external identity providers. This guide focuses on three approaches: GitHub’s managed OAuth2 service, custom OAuth2 with OpenID Connect discovery, and explicit authorization server metadata.

All configurations require OAuth2 applications registered with your identity provider, along with client credentials. The examples are intentionally small. Combine them with your own agent configurations and secret management.

Connect to GitHub’s OAuth2 service

Teams building agents that interact with GitHub repositories use OAuth2 to access private resources without embedding personal access tokens.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const github = new aws.bedrock.AgentcoreOauth2CredentialProvider("github", {
    name: "github-oauth-provider",
    credentialProviderVendor: "GithubOauth2",
    oauth2ProviderConfig: {
        githubOauth2ProviderConfig: {
            clientId: "your-github-client-id",
            clientSecret: "your-github-client-secret",
        },
    },
});
import pulumi
import pulumi_aws as aws

github = aws.bedrock.AgentcoreOauth2CredentialProvider("github",
    name="github-oauth-provider",
    credential_provider_vendor="GithubOauth2",
    oauth2_provider_config={
        "github_oauth2_provider_config": {
            "client_id": "your-github-client-id",
            "client_secret": "your-github-client-secret",
        },
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/bedrock"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := bedrock.NewAgentcoreOauth2CredentialProvider(ctx, "github", &bedrock.AgentcoreOauth2CredentialProviderArgs{
			Name:                     pulumi.String("github-oauth-provider"),
			CredentialProviderVendor: pulumi.String("GithubOauth2"),
			Oauth2ProviderConfig: &bedrock.AgentcoreOauth2CredentialProviderOauth2ProviderConfigArgs{
				GithubOauth2ProviderConfig: &bedrock.AgentcoreOauth2CredentialProviderOauth2ProviderConfigGithubOauth2ProviderConfigArgs{
					ClientId:     pulumi.String("your-github-client-id"),
					ClientSecret: pulumi.String("your-github-client-secret"),
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var github = new Aws.Bedrock.AgentcoreOauth2CredentialProvider("github", new()
    {
        Name = "github-oauth-provider",
        CredentialProviderVendor = "GithubOauth2",
        Oauth2ProviderConfig = new Aws.Bedrock.Inputs.AgentcoreOauth2CredentialProviderOauth2ProviderConfigArgs
        {
            GithubOauth2ProviderConfig = new Aws.Bedrock.Inputs.AgentcoreOauth2CredentialProviderOauth2ProviderConfigGithubOauth2ProviderConfigArgs
            {
                ClientId = "your-github-client-id",
                ClientSecret = "your-github-client-secret",
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.bedrock.AgentcoreOauth2CredentialProvider;
import com.pulumi.aws.bedrock.AgentcoreOauth2CredentialProviderArgs;
import com.pulumi.aws.bedrock.inputs.AgentcoreOauth2CredentialProviderOauth2ProviderConfigArgs;
import com.pulumi.aws.bedrock.inputs.AgentcoreOauth2CredentialProviderOauth2ProviderConfigGithubOauth2ProviderConfigArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var github = new AgentcoreOauth2CredentialProvider("github", AgentcoreOauth2CredentialProviderArgs.builder()
            .name("github-oauth-provider")
            .credentialProviderVendor("GithubOauth2")
            .oauth2ProviderConfig(AgentcoreOauth2CredentialProviderOauth2ProviderConfigArgs.builder()
                .githubOauth2ProviderConfig(AgentcoreOauth2CredentialProviderOauth2ProviderConfigGithubOauth2ProviderConfigArgs.builder()
                    .clientId("your-github-client-id")
                    .clientSecret("your-github-client-secret")
                    .build())
                .build())
            .build());

    }
}
resources:
  github:
    type: aws:bedrock:AgentcoreOauth2CredentialProvider
    properties:
      name: github-oauth-provider
      credentialProviderVendor: GithubOauth2
      oauth2ProviderConfig:
        githubOauth2ProviderConfig:
          clientId: your-github-client-id
          clientSecret: your-github-client-secret

The credentialProviderVendor property set to “GithubOauth2” tells Bedrock to use GitHub’s managed OAuth2 endpoints. The githubOauth2ProviderConfig block contains your GitHub OAuth App credentials. Bedrock handles token exchange and refresh automatically.

Configure custom OAuth2 with discovery URL

Organizations using Auth0, Okta, or other OpenID Connect providers can leverage discovery URLs to fetch OAuth2 configuration automatically.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const auth0 = new aws.bedrock.AgentcoreOauth2CredentialProvider("auth0", {
    name: "auth0-oauth-provider",
    credentialProviderVendor: "CustomOauth2",
    customOauth2ProviderConfig: [{
        custom: [{
            clientIdWo: "auth0-client-id",
            clientSecretWo: "auth0-client-secret",
            clientCredentialsWoVersion: 1,
            oauthDiscovery: [{
                discoveryUrl: "https://dev-company.auth0.com/.well-known/openid-configuration",
            }],
        }],
    }],
});
import pulumi
import pulumi_aws as aws

auth0 = aws.bedrock.AgentcoreOauth2CredentialProvider("auth0",
    name="auth0-oauth-provider",
    credential_provider_vendor="CustomOauth2",
    custom_oauth2_provider_config=[{
        "custom": [{
            "clientIdWo": "auth0-client-id",
            "clientSecretWo": "auth0-client-secret",
            "clientCredentialsWoVersion": 1,
            "oauthDiscovery": [{
                "discoveryUrl": "https://dev-company.auth0.com/.well-known/openid-configuration",
            }],
        }],
    }])
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/bedrock"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := bedrock.NewAgentcoreOauth2CredentialProvider(ctx, "auth0", &bedrock.AgentcoreOauth2CredentialProviderArgs{
			Name:                     pulumi.String("auth0-oauth-provider"),
			CredentialProviderVendor: pulumi.String("CustomOauth2"),
			CustomOauth2ProviderConfig: []map[string]interface{}{
				map[string]interface{}{
					"custom": []map[string]interface{}{
						map[string]interface{}{
							"clientIdWo":                 "auth0-client-id",
							"clientSecretWo":             "auth0-client-secret",
							"clientCredentialsWoVersion": 1,
							"oauthDiscovery": []map[string]interface{}{
								map[string]interface{}{
									"discoveryUrl": "https://dev-company.auth0.com/.well-known/openid-configuration",
								},
							},
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var auth0 = new Aws.Bedrock.AgentcoreOauth2CredentialProvider("auth0", new()
    {
        Name = "auth0-oauth-provider",
        CredentialProviderVendor = "CustomOauth2",
        CustomOauth2ProviderConfig = new[]
        {
            
            {
                { "custom", new[]
                {
                    
                    {
                        { "clientIdWo", "auth0-client-id" },
                        { "clientSecretWo", "auth0-client-secret" },
                        { "clientCredentialsWoVersion", 1 },
                        { "oauthDiscovery", new[]
                        {
                            
                            {
                                { "discoveryUrl", "https://dev-company.auth0.com/.well-known/openid-configuration" },
                            },
                        } },
                    },
                } },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.bedrock.AgentcoreOauth2CredentialProvider;
import com.pulumi.aws.bedrock.AgentcoreOauth2CredentialProviderArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var auth0 = new AgentcoreOauth2CredentialProvider("auth0", AgentcoreOauth2CredentialProviderArgs.builder()
            .name("auth0-oauth-provider")
            .credentialProviderVendor("CustomOauth2")
            .customOauth2ProviderConfig(List.of(Map.of("custom", List.of(Map.ofEntries(
                Map.entry("clientIdWo", "auth0-client-id"),
                Map.entry("clientSecretWo", "auth0-client-secret"),
                Map.entry("clientCredentialsWoVersion", 1),
                Map.entry("oauthDiscovery", List.of(Map.of("discoveryUrl", "https://dev-company.auth0.com/.well-known/openid-configuration")))
            )))))
            .build());

    }
}
resources:
  auth0:
    type: aws:bedrock:AgentcoreOauth2CredentialProvider
    properties:
      name: auth0-oauth-provider
      credentialProviderVendor: CustomOauth2
      customOauth2ProviderConfig:
        - custom:
            - clientIdWo: auth0-client-id
              clientSecretWo: auth0-client-secret
              clientCredentialsWoVersion: 1
              oauthDiscovery:
                - discoveryUrl: https://dev-company.auth0.com/.well-known/openid-configuration

The discoveryUrl points to your provider’s OpenID Connect discovery document, which contains authorization and token endpoints. Bedrock fetches this configuration at runtime. The clientIdWo and clientSecretWo properties are write-only variants that prevent credentials from appearing in state files (requires Terraform 1.11.0+).

Define OAuth2 endpoints explicitly

When discovery URLs aren’t available or you need explicit control, specify authorization server metadata directly.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const keycloak = new aws.bedrock.AgentcoreOauth2CredentialProvider("keycloak", {
    name: "keycloak-oauth-provider",
    credentialProviderVendor: "CustomOauth2",
    oauth2ProviderConfig: {
        customOauth2ProviderConfig: {
            clientIdWo: "keycloak-client-id",
            clientSecretWo: "keycloak-client-secret",
            clientCredentialsWoVersion: 1,
            oauthDiscovery: {
                authorizationServerMetadata: {
                    issuer: "https://auth.company.com/realms/production",
                    authorizationEndpoint: "https://auth.company.com/realms/production/protocol/openid-connect/auth",
                    tokenEndpoint: "https://auth.company.com/realms/production/protocol/openid-connect/token",
                    responseTypes: [
                        "code",
                        "id_token",
                    ],
                },
            },
        },
    },
});
import pulumi
import pulumi_aws as aws

keycloak = aws.bedrock.AgentcoreOauth2CredentialProvider("keycloak",
    name="keycloak-oauth-provider",
    credential_provider_vendor="CustomOauth2",
    oauth2_provider_config={
        "custom_oauth2_provider_config": {
            "client_id_wo": "keycloak-client-id",
            "client_secret_wo": "keycloak-client-secret",
            "client_credentials_wo_version": 1,
            "oauth_discovery": {
                "authorization_server_metadata": {
                    "issuer": "https://auth.company.com/realms/production",
                    "authorization_endpoint": "https://auth.company.com/realms/production/protocol/openid-connect/auth",
                    "token_endpoint": "https://auth.company.com/realms/production/protocol/openid-connect/token",
                    "response_types": [
                        "code",
                        "id_token",
                    ],
                },
            },
        },
    })
package main

import (
	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/bedrock"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		_, err := bedrock.NewAgentcoreOauth2CredentialProvider(ctx, "keycloak", &bedrock.AgentcoreOauth2CredentialProviderArgs{
			Name:                     pulumi.String("keycloak-oauth-provider"),
			CredentialProviderVendor: pulumi.String("CustomOauth2"),
			Oauth2ProviderConfig: &bedrock.AgentcoreOauth2CredentialProviderOauth2ProviderConfigArgs{
				CustomOauth2ProviderConfig: &bedrock.AgentcoreOauth2CredentialProviderOauth2ProviderConfigCustomOauth2ProviderConfigArgs{
					ClientIdWo:                 pulumi.String("keycloak-client-id"),
					ClientSecretWo:             pulumi.String("keycloak-client-secret"),
					ClientCredentialsWoVersion: pulumi.Int(1),
					OauthDiscovery: &bedrock.AgentcoreOauth2CredentialProviderOauth2ProviderConfigCustomOauth2ProviderConfigOauthDiscoveryArgs{
						AuthorizationServerMetadata: &bedrock.AgentcoreOauth2CredentialProviderOauth2ProviderConfigCustomOauth2ProviderConfigOauthDiscoveryAuthorizationServerMetadataArgs{
							Issuer:                pulumi.String("https://auth.company.com/realms/production"),
							AuthorizationEndpoint: pulumi.String("https://auth.company.com/realms/production/protocol/openid-connect/auth"),
							TokenEndpoint:         pulumi.String("https://auth.company.com/realms/production/protocol/openid-connect/token"),
							ResponseTypes: pulumi.StringArray{
								pulumi.String("code"),
								pulumi.String("id_token"),
							},
						},
					},
				},
			},
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var keycloak = new Aws.Bedrock.AgentcoreOauth2CredentialProvider("keycloak", new()
    {
        Name = "keycloak-oauth-provider",
        CredentialProviderVendor = "CustomOauth2",
        Oauth2ProviderConfig = new Aws.Bedrock.Inputs.AgentcoreOauth2CredentialProviderOauth2ProviderConfigArgs
        {
            CustomOauth2ProviderConfig = new Aws.Bedrock.Inputs.AgentcoreOauth2CredentialProviderOauth2ProviderConfigCustomOauth2ProviderConfigArgs
            {
                ClientIdWo = "keycloak-client-id",
                ClientSecretWo = "keycloak-client-secret",
                ClientCredentialsWoVersion = 1,
                OauthDiscovery = new Aws.Bedrock.Inputs.AgentcoreOauth2CredentialProviderOauth2ProviderConfigCustomOauth2ProviderConfigOauthDiscoveryArgs
                {
                    AuthorizationServerMetadata = new Aws.Bedrock.Inputs.AgentcoreOauth2CredentialProviderOauth2ProviderConfigCustomOauth2ProviderConfigOauthDiscoveryAuthorizationServerMetadataArgs
                    {
                        Issuer = "https://auth.company.com/realms/production",
                        AuthorizationEndpoint = "https://auth.company.com/realms/production/protocol/openid-connect/auth",
                        TokenEndpoint = "https://auth.company.com/realms/production/protocol/openid-connect/token",
                        ResponseTypes = new[]
                        {
                            "code",
                            "id_token",
                        },
                    },
                },
            },
        },
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.bedrock.AgentcoreOauth2CredentialProvider;
import com.pulumi.aws.bedrock.AgentcoreOauth2CredentialProviderArgs;
import com.pulumi.aws.bedrock.inputs.AgentcoreOauth2CredentialProviderOauth2ProviderConfigArgs;
import com.pulumi.aws.bedrock.inputs.AgentcoreOauth2CredentialProviderOauth2ProviderConfigCustomOauth2ProviderConfigArgs;
import com.pulumi.aws.bedrock.inputs.AgentcoreOauth2CredentialProviderOauth2ProviderConfigCustomOauth2ProviderConfigOauthDiscoveryArgs;
import com.pulumi.aws.bedrock.inputs.AgentcoreOauth2CredentialProviderOauth2ProviderConfigCustomOauth2ProviderConfigOauthDiscoveryAuthorizationServerMetadataArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var keycloak = new AgentcoreOauth2CredentialProvider("keycloak", AgentcoreOauth2CredentialProviderArgs.builder()
            .name("keycloak-oauth-provider")
            .credentialProviderVendor("CustomOauth2")
            .oauth2ProviderConfig(AgentcoreOauth2CredentialProviderOauth2ProviderConfigArgs.builder()
                .customOauth2ProviderConfig(AgentcoreOauth2CredentialProviderOauth2ProviderConfigCustomOauth2ProviderConfigArgs.builder()
                    .clientIdWo("keycloak-client-id")
                    .clientSecretWo("keycloak-client-secret")
                    .clientCredentialsWoVersion(1)
                    .oauthDiscovery(AgentcoreOauth2CredentialProviderOauth2ProviderConfigCustomOauth2ProviderConfigOauthDiscoveryArgs.builder()
                        .authorizationServerMetadata(AgentcoreOauth2CredentialProviderOauth2ProviderConfigCustomOauth2ProviderConfigOauthDiscoveryAuthorizationServerMetadataArgs.builder()
                            .issuer("https://auth.company.com/realms/production")
                            .authorizationEndpoint("https://auth.company.com/realms/production/protocol/openid-connect/auth")
                            .tokenEndpoint("https://auth.company.com/realms/production/protocol/openid-connect/token")
                            .responseTypes(                            
                                "code",
                                "id_token")
                            .build())
                        .build())
                    .build())
                .build())
            .build());

    }
}
resources:
  keycloak:
    type: aws:bedrock:AgentcoreOauth2CredentialProvider
    properties:
      name: keycloak-oauth-provider
      credentialProviderVendor: CustomOauth2
      oauth2ProviderConfig:
        customOauth2ProviderConfig:
          clientIdWo: keycloak-client-id
          clientSecretWo: keycloak-client-secret
          clientCredentialsWoVersion: 1
          oauthDiscovery:
            authorizationServerMetadata:
              issuer: https://auth.company.com/realms/production
              authorizationEndpoint: https://auth.company.com/realms/production/protocol/openid-connect/auth
              tokenEndpoint: https://auth.company.com/realms/production/protocol/openid-connect/token
              responseTypes:
                - code
                - id_token

The authorizationServerMetadata block defines the issuer, authorization endpoint, token endpoint, and supported response types. This approach gives you full control over endpoint URLs, useful for custom OAuth2 implementations or when discovery isn’t supported. This is an alternative to the discovery URL approach shown earlier.

Beyond these examples

These snippets focus on specific credential provider features: managed OAuth2 providers (GitHub), custom OAuth2 with discovery, and explicit endpoint configuration. They’re intentionally minimal rather than full agent authentication systems.

The examples assume pre-existing infrastructure such as OAuth2 applications registered with identity providers, and client credentials (ID and secret) from OAuth2 apps. They focus on configuring the credential provider rather than provisioning the OAuth2 applications themselves.

To keep things focused, common credential provider patterns are omitted, including:

  • Write-only vs standard credential properties (clientIdWo vs clientId)
  • Resource tagging for organization and cost tracking
  • Regional deployment considerations
  • Secrets Manager integration for credential storage

These omissions are intentional: the goal is to illustrate how each OAuth2 configuration is wired, not provide drop-in authentication modules. See the Bedrock AgentCore OAuth2 Credential Provider resource reference for all available configuration options.

Let's configure AWS Bedrock OAuth2 Credential Providers

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Configuration & Setup
Which OAuth providers are supported?
Six providers are supported: CustomOauth2, GithubOauth2, GoogleOauth2, Microsoft, SalesforceOauth2, and SlackOauth2. Specify your choice using the credentialProviderVendor property.
Can I configure multiple OAuth provider types in one resource?
No, the oauth2ProviderConfig must contain exactly one provider type. Choose either a built-in provider like GitHub or a custom OAuth2 configuration, but not both.
What's required to create an OAuth2 credential provider?
You must provide credentialProviderVendor, name, and oauth2ProviderConfig. The region property is also required but defaults to your provider configuration.
How do I import an existing OAuth2 credential provider?
Use pulumi import aws:bedrock/agentcoreOauth2CredentialProvider:AgentcoreOauth2CredentialProvider example oauth2-provider-name with the provider’s name.
Authentication & Credentials
What's the difference between client_id and client_id_wo?
client_id_wo and client_secret_wo are write-only arguments that don’t expose values in state. They require Terraform 1.11.0 or later, while client_id and client_secret work with earlier versions.
When should I use write-only credential arguments?
Use client_id_wo and client_secret_wo when you need write-only semantics to avoid storing credentials in Terraform state. This requires Terraform 1.11.0 or later.
Where are client secrets stored?
Client secrets are stored in AWS Secrets Manager. The clientSecretArns output property contains the ARN of the secret.
Provider-Specific Configuration
How do I configure a GitHub OAuth provider?
Set credentialProviderVendor to GithubOauth2 and provide your GitHub client ID and secret in the githubOauth2ProviderConfig block.
What's the difference between using a discovery URL and manual authorization server metadata?
A discovery URL automatically fetches OAuth configuration from a well-known OpenID Connect endpoint (like /.well-known/openid-configuration), while manual metadata requires you to explicitly specify the issuer, authorization endpoint, token endpoint, and response types.
How do I configure a custom OAuth provider?
Set credentialProviderVendor to CustomOauth2 and provide either a discoveryUrl for automatic configuration or manual authorizationServerMetadata with issuer, endpoints, and response types.

Using a different cloud?

Explore security guides for other cloud providers: