← Cloudflare One / cloudflare-one / access-controls / service-credentials
Service tokens
You can provide automated systems with service tokens to authenticate against your Cloudflare One policies. Cloudflare Access will generate service tokens that consist of a Client ID and a Client Secret. Automated systems or applications can then use these values to reach an application protected by Access.
This section covers how to create, rotate, renew, disable, and revoke a service token.
Create a service token
-
In the Cloudflare dashboard ↗, go to Zero Trust > Access controls > Service credentials > Service Tokens.
-
Select Create Service Token.
-
Name the service token. The name allows you to easily identify events related to the token in the logs and to revoke the token individually.
-
Choose a Service Token Duration. This sets the expiration date for the token.
-
Select Generate token. You will see the generated Client ID and Client Secret for the service token, as well as their respective request headers.
-
Copy the Client Secret.
-
Make a
POSTrequest to the Access Service Tokens endpoint:
At least one of the following token permissions is required:Required API token permissions
Access: Service Tokens Write
Create a service tokencurl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/service_tokens" \ --request POST \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ --json '{ "name": "CI/CD token", "duration": "8760h" }' -
Copy the
client_idandclient_secretvalues returned in the response.Response"result": { "client_id": "88bf3b6d86161464f6509f7219099e57.access", "client_secret": "bdd31cbc4dec990953e39163fbbb194c93313ca9f0a6e420346af9d326b1d2a5", "created_at": "2025-09-25T22:26:26Z", "expires_at": "2026-09-25T22:26:26Z", "id": "3537a672-e4d8-4d89-aab9-26cb622918a1", "name": "CI/CD token", "updated_at": "2025-09-25T22:26:26Z", "duration": "8760h", "client_secret_version": 1 }
-
Add the following permission to your
cloudflare_api_token↗:Access: Service Tokens Write
-
Configure the
cloudflare_zero_trust_access_service_token↗ resource:resource "cloudflare_zero_trust_access_service_token" "example_service_token" { account_id = var.cloudflare_account_id name = "Example service token" duration = "8760h" lifecycle { create_before_destroy = true } } -
Get the Client ID and Client Secret of the service token:
Example: Output to CLI
- Output the Client ID and Client Secret to the Terraform state file:
output "example_service_token_client_id" { value = cloudflare_zero_trust_access_service_token.example_service_token.client_id } output "example_service_token_client_secret" { value = cloudflare_zero_trust_access_service_token.example_service_token.client_secret sensitive = true } - Apply the configuration:
terraform apply - Read the Client ID and Client Secret:
terraform output -raw example_service_token_client_idterraform output -raw example_service_token_client_secret
Example: Store in HashiCorp Vault
resource "vault_generic_secret" "example_service_token" { path = "kv/cloudflare/example_service_token" data_json = jsonencode({ "CLIENT_ID" = cloudflare_access_service_token.example_service_token.client_id "CLIENT_SECRET" = cloudflare_access_service_token.example_service_token.client_secret }) } - Output the Client ID and Client Secret to the Terraform state file:
You can now configure your Access applications and device enrollment permissions to accept this service token. Make sure to set the policy action to Service Auth; otherwise, Access will prompt for an identity provider login.
Client Secret format
As of August 26, 2026, new service token Client Secrets use the format cfast_[40 alphanumeric characters][8-character checksum]. The prefix and checksum make the secrets easier for credential scanning tools to identify.
Existing Client Secrets use a 64-character hexadecimal format. These secrets continue to work and do not require rotation. Both formats use the same Client ID and authentication headers.
Connect your service to Access
Request
To authenticate to an Access application using your service token, add the following to the headers of any HTTP request:
CF-Access-Client-Id: <CLIENT_ID>
CF-Access-Client-Secret: <CLIENT_SECRET>
For example,
curl -H "CF-Access-Client-Id: <CLIENT_ID>" -H "CF-Access-Client-Secret: <CLIENT_SECRET>" https://app.example.comAuthenticate with a single header
You can configure a self-hosted Access application to accept a service token in a single HTTP header, as an alternative to the CF-Access-Client-Id and CF-Access-Client-Secret pair of headers. This is useful for authenticating SaaS services that only support sending one custom header in a request (for example, the Authorization header).
To authenticate using a single header:
-
Get your existing Access application configuration:
At least one of the following token permissions is required:Required API token permissions
Access: Apps and Policies WriteAccess: Apps and Policies Read
Get an Access applicationcurl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps/$APP_ID" \ --request GET \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" -
Make a
PUTrequest with the name of the header you want to use for service token authentication. To avoid overwriting your existing configuration, thePUTrequest body should contain all fields returned by the previousGETrequest.
At least one of the following token permissions is required:Required API token permissions
Access: Apps and Policies Write
Update an Access applicationcurl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/apps/$APP_ID" \ --request PUT \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ --json '{ "domain": "app.example.com", "type": "self_hosted", "read_service_tokens_from_header": "Authorization" }' -
Add the header to any HTTP request. For example,
curl -H "Authorization: {\"cf-access-client-id\": \"<CLIENT_ID>\", \"cf-access-client-secret\": \"<CLIENT_SECRET>\"}" https://app.example.com
Rotate service token secrets
Rotate a service token secret when you suspect exposure or as part of regular credential rotation. The Client ID remains the same, but Access generates a new Client Secret.
You can set a grace period during which both secrets work. Use this period to update your services before Access revokes the previous secret.
-
In the Cloudflare dashboard ↗, go to Zero Trust > Access controls > Service credentials > Service Tokens.
Go to ↗ -
Locate the token and select the three dots > Rotate secret.
-
In Keep the current secret valid for, choose when Access should revoke the current secret. Available grace periods range from one hour to 30 days. To revoke it when you rotate, select Revoke immediately.
-
Select Rotate.
-
Copy the new Client Secret and update your services before the grace period ends.
Make a POST request to the Rotate a service token endpoint. Set previous_client_secret_expires_at to an RFC 3339 timestamp when the previous secret should expire:
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/service_tokens/$SERVICE_TOKEN_ID/rotate" \
--request POST \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--json '{
"previous_client_secret_expires_at": "2030-01-01T00:00:00Z"
}'To revoke the previous secret immediately, omit previous_client_secret_expires_at from the request.
Renew service tokens
Service tokens expire according to the token duration you selected when you created the token.
- In the Cloudflare dashboard ↗, go to Zero Trust > Access controls > Service credentials > Service Tokens.
- Locate the token you want to renew.
- To extend the token's lifetime by one year, select Refresh.
- To extend the token's lifetime by more than a year:
- Select Edit.
- Choose a new Service Token Duration.
- Select Save. The expiration date will be extended by the selected amount of time.
To extend the token's lifetime by one year, make a POST request to the Refresh a service token endpoint:
Required API token permissions
At least one of the following token permissions is required:Access: Service Tokens Write
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/service_tokens/$SERVICE_TOKEN_ID/refresh" \
--request POST \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"To extend the token's lifetime by a custom duration, make a PUT request to the Update a service token endpoint with the new duration:
Required API token permissions
At least one of the following token permissions is required:Access: Service Tokens Write
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/service_tokens/$SERVICE_TOKEN_ID" \
--request PUT \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--json '{
"duration": "17520h"
}'To renew the service token, update the duration attribute on the cloudflare_zero_trust_access_service_token ↗ resource and apply the change. Cloudflare resets the expiration relative to the time of the update.
resource "cloudflare_zero_trust_access_service_token" "example_service_token" {
account_id = var.cloudflare_account_id
name = "Example service token"
duration = "17520h"
lifecycle {
create_before_destroy = true
}
}Turn a service token on or off
Turn off a service token to temporarily prevent it from authenticating. Access preserves the token so you can turn it on again later.
Turning off a token also stops its previous secret from working during an active rotation grace period.
-
In the Cloudflare dashboard ↗, go to Zero Trust > Access controls > Service credentials > Service Tokens.
Go to ↗ -
Locate the token and select the three dots.
-
To stop the token from authenticating, select Disable token > Disable.
-
To restore authentication, select Enable token > Enable.
Make a PUT request to the Update a service token endpoint. Set enabled to false to turn off the token:
Required API token permissions
At least one of the following token permissions is required:Access: Service Tokens Write
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/service_tokens/$SERVICE_TOKEN_ID" \
--request PUT \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
--json '{
"name": "<TOKEN_NAME>",
"enabled": false
}'To turn the token on again, set enabled to true.
Revoke service tokens
If you need to revoke access before the token expires, delete the token. Services that rely on a deleted service token can no longer reach your application.
- In the Cloudflare dashboard ↗, go to Zero Trust > Access controls > Service credentials > Service Tokens.
- Delete the token you need to revoke.
Make a DELETE request to the Delete a service token endpoint:
Required API token permissions
At least one of the following token permissions is required:Access: Service Tokens Write
curl "https://api.cloudflare.com/client/v4/accounts/$ACCOUNT_ID/access/service_tokens/$SERVICE_TOKEN_ID" \
--request DELETE \
--header "Authorization: Bearer $CLOUDFLARE_API_TOKEN"To revoke the service token, remove the cloudflare_zero_trust_access_service_token ↗ resource from your configuration and run terraform apply, or target the resource for destruction:
terraform destroy -target=cloudflare_zero_trust_access_service_token.example_service_tokenSet a token expiration alert
An alert can be configured to notify a week before a service token expires to allow an administrator to invoke a token refresh.
Expiring Access Service Token Alert
Who is it for?Access customers who want to receive a notification when their service token is about to expire.
Other options / filtersNone.
Included withPurchase of Access
What should you do if you receive one?Extend the expiration date of the service token. For more details, refer to Renew your service token.
To configure a service token expiration alert:
- In the Cloudflare dashboard ↗, go to the Notifications page. Go to Notifications ↗
- Select Add.
- Select Expiring Access Service Token.
- Enter a name for your alert and an optional description.
- (Optional) Add other recipients for the notification email.
- Select Save.
Your alert has been set and is now visible on the Notifications page.