API keys - Temporal Cloud feature guide
API key authentication for Temporal Cloud, tcld
, Namespace authentication, SDK-based API calls, and Terraform provider is currently in Public Preview.
Temporal Cloud API keys offer industry-standard identity-based authentication for Temporal users and Service Accounts. This document introduces Temporal Cloud's API key features:
- API key overview
- API key best practices
- Global Administrator and Account Owner API key management
- User API key management
- Manage API keys for Service Accounts
- API keys for Namespace authentication
- Use API keys to authenticate
- Troubleshoot your API key use
- API keys: Frequently Asked Questions
API key overview
Each Temporal Cloud API key is a unique identity linked to role-based access control (RBAC) settings to ensure secure and appropriate access.
The authentication process follows this pathway:
API key best practices
- Keep it secret; keep it safe: Treat your API key like a password. Do not expose it in client-side code, public repositories, or other easily accessible locations.
- Rotate keys regularly: Change your API keys periodically to reduce risks from potential leaks. Keys must be rotated every at least every 90 days.
- Design your code for key updates: Use key management practices that retrieve your API keys without hard-coding them into your apps. This lets you restart your Workers to refresh your rotated keys without recompiling your code.
- Monitor API key usage: Check usage metrics and logs regularly. Revoke the key immediately if you detect any unexpected or unauthorized activity.
- Use a Key Management System (KMS): Employ a Key Management System to minimize the risk of key leaks.
API key use cases
API keys are well suited for the following scenarios:
- Cloud operations automation:
API keys work with most Temporal Cloud operational tools, including
tcld
, Cloud Ops APIs, and the Terraform provider. Use them to manage your Temporal Cloud account, Namespaces, certificates, and user identities.- API keys for Cloud operations tools are in Public Preview.
- Namespace authentication:
API keys serve as an authentication mechanism for executing and managing Workflows via the SDK and Temporal CLI, offering an alternative to mTLS-based authentication.
- API keys for Namespace authentication are currently in Pre-release.
API keys are an opt-in feature that must be enabled by a Global Administrator or Account Owner. For instructions on managing API keys for your organization, see Global Administrator and Account Owner API key management.
API key permissions
API keys support both users and Service Accounts. Here are the differences in their permissions:
- Normal users, Global Administrators, and Account Owners can create, delete, and update API key access using the Cloud UI or
tcld
. - Only Global Administrators and Account Owners can create, delete, and update access to API keys for Service Accounts.
API key supported tooling
Use API keys to authenticate with:
- The Temporal CLI v 0.12 or higher
- Temporal SDKs (latest recommended)
tcld
- The Cloud Operations API
- Temporalʼs Terraform provider
API key prerequisites
Check these setup details before using API keys:
- The Global Administrator or Account Owner must enable API keys access for your Temporal Account.
- Have access to the Temporal Cloud UI or Temporal Cloud CLI (tcld) to create an API key.
Global Administrator and Account Owner API key management
Global Administrators and Account Owners can monitor, manage, disable, and delete API keys for any user or Service Account within their account. To manage your account’s API keys:
- Log in to the Temporal Cloud UI.
- Select Settings and choose API keys.
API keys are not enabled by default. The Global Administrator or Account Owner must enable access to allow the creation and use of API keys.
Administrators can disable or delete an individual API key using the vertical ellipsis next to the API key row. Disabling the API keys feature stops the creation of new API keys, but existing API keys can still be used to authenticate into Temporal Cloud until they are either disabled, deleted, or expire.
To find an API key, you can filter by API key state and identity type (Global Administrators and Account Owners only).
Deleting or disabling a key removes its ability to authenticate into Temporal Cloud. If you delete or disable an API key for a running Workflow, that Workflow will fail until a new API key secret is created and configured.
User API key management
Manage your personal API keys with the Temporal Cloud UI or tcld
.
These sections show you how to generate, manage, and remove API keys for a user.
Generate an API key
Create API keys using one of the following methods:
- Once generated, copy and securely save the API key. It will be displayed only once for security purposes.
- Temporal supports API keys lifespans up to 90 days. Your key will be valid during this period unless it is revoked or the account is deactivated.
Generate API keys with the Temporal Cloud UI
Log in to the Temporal Cloud UI and navigate to your Profile Page → API keys. Then select Create API key and provide the following information:
- API key name: a short identifiable name for the key
- API key description: a longer form description of the key's use
- Expiration date: the end-date for the API key (max 90 days)
Finish by selecting Generate API key.
Generate API keys with tcld
To generate an API key, log into your account and issue the following command:
tcld login
tcld apikey create \
--name "<key-name>" \
--description "<key-description>" \
--duration "<key-duration>"
Duration specifies the time until the API key expires, for example: "30d", "4d12h", etc.
Enable or Disable an API Key
You can enable or disable API keys. When disabled, an API key cannot authenticate with Temporal Cloud.
Manage API Key State with the Temporal Cloud UI
Follow these steps:
- Log in to the Temporal Cloud UI.
- Go to your Profile Page → API Keys.
- Select the three vertical dots next to the API key’s row.
- Choose Enable or Disable.
Manage API Key State with tcld
To manage an API key, log into your account and use one of the following commands to enable or disable it:
tcld login
tcld apikey disable --id <api-key-id>
tcld apikey enable --id <api-key-id>
Delete an API key
Deleting an API key stops it from authenticating with Temporal Cloud.
Deleting an API key for a running Workflow will cause it to fail unless you rotate the key with a new one. This can affect long-running Workflows that outlast the API key's lifetime.
Delete API keys with the Temporal Cloud UI
Follow these steps to remove API keys:
- Log in to the Temporal Cloud UI.
- Navigate to your Profile Page → API keys.
- Select the three vertical dots next to the API key's row.
- Choose Delete.
Delete API keys with tcld
To delete an API key, log into your account and issue the following:
tcld login
tcld apikey delete --id <api-key-id>
Rotate an API key
Temporal API keys automatically expire. Their maximum life is 90 days. Follow these steps to rotate API keys:
- Create a new key. You may reuse key names if that helps.
- Ensure that both the original key and new key function properly before moving to the next step.
- Switch clients to load the new key and start using it.
- Delete the old key after it is no longer in use.
Manage API keys for Service Accounts
Global Administrators and Account Owners can manage API keys for all Service Accounts in their account and generate API keys for Service Accounts. This is different for users, who generate their own API keys.
Generate an API Key for a Service Account
Create API keys for Service Accounts using one of the following methods:
- Once generated, copy and securely save the API key. It will be displayed only once for security purposes.
- Temporal supports API keys with lifespans up to 90 days. Your key will be valid during this period unless it is revoked or the account is deactivated.
Generate API Keys with the Temporal Cloud UI
Log in to the Temporal Cloud UI and go to API keys settings. Select Create API key, then choose Service Account from the "Create an API key for" dropdown. In the "Mapped to identity" input box, select a Service account and provide the following information:
- API key name: A short, identifiable name for the key
- API key description: A longer description of the key's use
- Expiration date: The end date for the API key (max 90 days)
Finish by selecting Generate API key.
Generate API keys with tcld
To create an API key for a Service Account, use tcld apikey create
with the --service-account-id
flag:
tcld apikey create --namespace <namespace_id>.<account_id> \
--description "<api-key-description>" \
--duration <api-key-duration> \
--service-account-id <service-account-id>
Enable or disable an API key
Global Administrators and Account Owners can manage API key access for any user in their account using the Temporal Cloud UI or tcld
.
Manage keys with Temporal Cloud UI
Follow these steps:
- Log into Temporal Cloud.
- Go to https://cloud.temporal.io/settings/api-keys and find the identity that owns the API key.
- Click the Disable/Enable button to perform the action. There may be a delay after changing the status. Once successful, the updated API key status will be shown in the row.
Manage keys with tcld
Use the tcld apikey disable
or tcld apikey enable
command to disable or enable an API key:
tcld login
tcld apikey disable --id <api-key-id>
tcld apikey enable --id <api-key-id>
This command is the same for users and Service Accounts.
Delete an API key for a Service Account
Global Administrators and Account Owners can delete API keys for any user or Service Account in their account using the Temporal Cloud UI or tcld
.
Deleting a key removes its ability to authenticate with Temporal Cloud.
If you delete an API key for a running Workflow, that Workflow will fail unless you rotate the API key with a new one.
Delete a Service Account API key with Temporal Cloud UI
Follow these steps:
- Navigate to https://cloud.temporal.io/settings/api-keys.
- Locate the identity that owns the API key and click on the row to view the API keys associated with that identity.
- Click the Delete button. There may be a delay after deleting the API key.
- Once successful, the updated API key status will be reflected in the row.
Delete a Service Account API key with tcld
Use the tcld apikey delete
command to delete an API key.
The process for deleting an API key is the same for a user or Service Account.
tcld login
tcld apikey delete --id <api-key-id>
Rotate a Service Account API key
Temporal API keys automatically expire. Their maximum life is 90 days. Follow these steps to rotate API keys:
- Create a new key. You may reuse key names if that helps.
- Ensure that both the original key and new key function properly before moving to the next step.
- Switch clients to load the new key and start using it.
- Delete the old key after it is no longer in use.
API keys for Namespace authentication
Create a Namespace with API key authentication as an alternative to mTLS-based authentication by selecting "Allow API key authentication" during setup. The gRPC endpoint format for the Namespace depends on the authentication method:
- For mTLS connections, use
<namespace>.<account>.tmprl.cloud:7233
. - For API key connections, use
<region>.<cloud_provider>.api.temporal.io:7233
.
Use this gRPC endpoint in the Temporal CLI or SDK to connect to Temporal Cloud with an API key.
Use API keys to authenticate
Authenticate with Temporal Cloud using API keys with the following clients:
- Temporal CLI v0.12 or higher
- SDKs (latest recommended)
- Temporal Cloud CLI
tcld
- The Cloud Operations API
- Temporal’s Terraform Provider
Temporal CLI
To use your API key with the Temporal CLI, either pass it with the --api-key
flag or set an environment variable (recommended).
The tcld
tool automatically picks up the TEMPORAL_CLOUD_API_KEY
environment variable.
tcld <command> <subcommand> --api-key YourAPIKey <other flags and options>
In addition to the API key, the following client options are required:
--address
: Provide the Namespace's gRPC endpoint from the Namespace UI's gRPC endpoint box.- For API key connections, use the format
<region>.<cloud_provider>.api.temporal.io:7233
. - You can set the address using an environment variable.
- For API key connections, use the format
--namespace
: Provide thenamespace.accountId
from the top of the Namespace page in the UI.- Use the format
<namespace_id>.<account_id>
. - This can be set using an environment variable.
- Use the format
--grpc-meta "temporal-namespace="
: Provide thenamespace.accountId
again as grpc-metadata.--tls
: Use for a secure connection with the appropriate options.- This can be set using an environment variable.
For example, to connect to Temporal Cloud from the CLI using an environment variable for the API key:
export TEMPORAL_API_KEY=<key-secret>
temporal workflow list \
--address <endpoint> \
--namespace <namespace_id>.<account_id> \
--grpc-meta "temporal-namespace=<namespace_id>.<account_id>" \
--tls
SDK
To use your API key with a Temporal SDK, include the API key in the Bearer token header and specify the Namespace header. The Bearer token header indicates the authentication type, while the Namespace header routes the request.
Go SDK (v 1.26.0+)
Create an initial connection:
clientOptions := client.Options{
HostPort: <endpoint>,
Namespace: <namespace_id>.<account_id>,
ConnectionOptions: client.ConnectionOptions{
TLS: &tls.Config{},
DialOptions: []grpc.DialOption{
grpc.WithUnaryInterceptor(
func(ctx context.Context, method string, req any, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
return invoker(
metadata.AppendToOutgoingContext(ctx, "temporal-namespace", <namespace_id>.<account_id>),
method,
req,
reply,
cc,
opts...,
)
},
),
},
},
Credentials: client.NewAPIKeyStaticCredentials(apiKey),
}
c, err := client.Dial(clientOptions)
if err != nil {
log.Fatalf("error creating temporal client: %v", err)
}
Update an API key:
// Assuming client Credentials created with
var myKey string
creds := client.NewAPIKeyDynamicCredentials(
func(context.Context) (string, error) { return myKey, nil })
// Just update by replacing
myKey = myKeyUpdated
Go SDK (pre v 1.26.0)
Create an initial connection:
// Create headers provider
type APIKeyProvider struct {
APIKey string
Namespace string
}
func (a *APIKeyProvider) GetHeaders(context.Context) (map[string]string, error) {
return map[string]string{"Authorization": "Bearer " + a.APIKey, "temporal-namespace": a.Namespace}, nil
}
// Use headers provider
apiKeyProvider := &APIKeyProvider{APIKey: <APIKey>, Namespace: <namespace_id>.<account_id>}
c, err := client.Dial(client.Options{
HostPort: <endpoint>,
Namespace: <namespace_id>.<account_id>,
HeadersProvider: apiKeyProvider,
ConnectionOptions: client.ConnectionOptions{TLS: &tls.Config{
}},
})
Update an API key:
apiKeyProvider.APIKey = myKeyUpdated
Java SDK
At a client level:
// Create a Metadata object with the Temporal namespace header key.
Metadata.Key<String> TEMPORAL_NAMESPACE_HEADER_KEY =
Metadata.Key.of("temporal-namespace", Metadata.ASCII_STRING_MARSHALLER);
Metadata metadata = new Metadata();
metadata.put(TEMPORAL_NAMESPACE_HEADER_KEY, <namespace_id>.<account_id>);
// Create the Workflow service stub.
WorkflowServiceStubsOptions.Builder stubOptions =
WorkflowServiceStubsOptions.newBuilder()
.setChannelInitializer(
(channel) -> {
channel.intercept(MetadataUtils.newAttachHeadersInterceptor(metadata));
})
.addGrpcMetadataProvider(
new AuthorizationGrpcMetadataProvider(() -> "Bearer " + <APIKey>))
.setTarget(<endpoint>);
stubOptions.setSslContext(SimpleSslContextBuilder.noKeyOrCertChain().setUseInsecureTrustManager(false).build());
WorkflowServiceStubs service = WorkflowServiceStubs.newServiceStubs(stubOptions.build());
/*
* Get a Workflow service client which can be used to start, Signal, and Query Workflow Executions.
*/
WorkflowClient client =
WorkflowClient.newInstance(
service, WorkflowClientOptions.newBuilder().setNamespace(<namespace_id>.<account_id>).build());
At a per-call level:
String myKey = "Bearer " + <APIKey>;
WorkflowServiceStubsOptions stubOptions =
WorkflowServiceStubsOptions.newBuilder()
.addGrpcMetadataProvider(new AuthorizationGrpcMetadataProvider(() -> myKey))
.build();
// Just update by replacing, this must be done in a thread safe way
myKey = "Bearer " + <new APIKey>;
Python SDK (v 1.6.0+)
Create an initial connection:
client = await Client.connect(
<endpoint>,
namespace=<namespace_id>.<account_id>,
rpc_metadata={"temporal-namespace": <namespace_id>.<account_id>},
api_key=<APIKey>,
tls=True,
)
Update an API key (newer SDK):
my_client.api_key = my_key_updated
Python SDK (pre v 1.6.0)
Create an initial connection:
client = await Client.connect(
<endpoint>,
namespace=<namespace_id>.<account_id>,
rpc_metadata={"temporal-namespace": <namespace_id>.<account_id>, "Authorization": f"Bearer {<APIKey>}"},
tls=True,
)
Update an API key:
my_client.rpc_metadata = {"Authorization": f"Bearer {<my_key_updated>}"}
.NET SDK (v 1.1.0+)
Create an initial connection:
var myClient = TemporalClient.ConnectAsync(new(<endpoint>)
{
Namespace = <namespace_id>.<account_id>,
ApiKey = <APIKey>,
RpcMetadata = new Dictionary<string, string>()
{
["temporal-namespace"] = "${<namespace_id>.<account_id>}",
},
Tls = new(),
});
Update an API key:
myClient.Connection.ApiKey = myKeyUpdated;
.NET SDK (pre v 1.1.0)
Create an initial connection:
var myClient = TemporalClient.ConnectAsync(new(<endpoint>)
{
Namespace = <namespace_id>.<account_id>,
RpcMetadata = new Dictionary<string, string>()
{
["Authorization"] = $"Bearer {<APIKey>}",
["temporal-namespace"] = "${<namespace_id>.<account_id>}",
},
Tls = new(),
});
Update an API key:
myClient.Connection.RpcMetadata = new Dictionary<string, string>()
{
["Authorization"] = $"Bearer {myKeyUpdated}",
};
TypeScript SDK (v 1.10.0+)
Create an initial Connection
(for use with Client
):
const connection = await Connection.connect(
address: <endpoint>,
tls: true,
apiKey: <APIKey>,
metadata: {
'temporal-namespace': <namespace_id>.<account_id>,
},
)
const client = new Client({
connection,
namespace: <namespace_id>.<account_id>,
});
Create an initial Worker NativeConnection
(for use with Worker
):
const connection = await NativeConnection.connect(
address: <endpoint>,
tls: true,
apiKey: <APIKey>,
metadata: {
'temporal-namespace': <namespace_id>.<account_id>,
},
)
const worker = await Worker.create({
connection,
namespace: <namespace_id>.<account_id>,
// ...
});
Update the API key on an existing Connection
or NativeConnection
:
connection.setApiKey(<APIKey>);
TypeScript SDK (pre v 1.10.0)
Create an initial Connection
(for use with Client
):
const connection = await Connection.connect(
address: <endpoint>,
tls: true,
metadata: {
'Authorization': `Bearer ${<APIKey>}`,
'temporal-namespace': <namespace_id>.<account_id>,
},
)
const client = new Client({
connection,
namespace: <namespace_id>.<account_id>,
});
Create an initial Worker NativeConnection
(for use with Worker
):
const connection = await NativeConnection.connect(
address: <endpoint>,
tls: true,
metadata: {
'Authorization': `Bearer ${<APIKey>}`
'temporal-namespace': <namespace_id>.<account_id>,
},
)
const worker = await Worker.create({
connection,
namespace: <namespace_id>.<account_id>,
// ...
});
tcld
To use an API key with tcld
, choose one of these methods:
- Use the
--api-key
flag. - Set the
TEMPORAL_CLOUD_API_KEY
environment variable.
Cloud Ops API
To use an API key with the Cloud Ops API, securely pass the API key in your API client. For a complete example, see Cloud Samples in Go.
Terraform Provider
To use an API key with the Temporal Terraform Provider, pass the API key as a provider argument.
Troubleshoot your API key use
Invalid API key errors: Check that you copied the key correctly and that it hasn't been revoked or expired.
API keys: Frequently Asked Questions
Q: Can I issue and use multiple API keys for the same account?
A: Yes, you can generate multiple API keys for different services or team members.
Q: How many API keys can be issued at once?
A: Up to 10 active, enabled keys per Identity (user or Service Account).
Q: Do API keys expire?
A: Yes, API keys expire after up to 90 days. Temporal recommends rotating API keys periodically.
Q: What happens if I misplace or lose my API bearer token/secret key?
A: The full key is displayed only once upon creation for security reasons. If you lose it, generate a new one.