Authenticate with API tokens
Send an API token or a service account key with each REST API request, and learn what each credential can reach and why a request is refused.
Every REST API request carries a credential in the Authorization header. This article shows how to send it, what each kind of credential can reach, and what to do when a request is refused.
Before you begin
- Get a credential. Create an API token in Identity & AccessAPI tokens, or a key for a service account in Identity & AccessService Accounts. See Create an API token and Manage keys.
- To create API tokens, you need the Owner role, or a custom role that can manage API tokens. The Contributor and Reader roles can only view them.
- Store the secret when it's shown. The secret is shown once.
Choose a credential
| Credential | Starts with | Acts as | What it can do |
|---|---|---|---|
| API token | pc_live_ | The user who created it | What that user's role allows in each project, and only within the token's scopes |
| Service account key | sak_live_ | The service account | What the roles granted to the service account allow, and only within the key's scopes |
Use a service account key for automation that must keep working when people leave or change roles. A user's API tokens are revoked when the user is removed, and they stop working while the user's account is disabled.
Neither credential works with OpenStack tools, such as the openstack CLI or Terraform. Those tools use an OpenStack application credential. See OpenStack-compatible tools.
Send the credential
Put the credential in the Authorization header of every request, after Bearer. To check that it works, read your own identity:
curl "https://<api-host>/api/v1/account/whoami" \
-H "Authorization: Bearer $PC_TOKEN"<api-host>: the host name of the API.PC_TOKEN: an environment variable that holds the API token or the service account key.
A 200 OK response lists the tenants, subscriptions, and projects that the credential can reach. A 401 Unauthorized response means that the credential isn't valid. See Troubleshooting.
Keep credentials out of source code and out of version control. Load them from a secrets store or an environment variable, as in the example.
Token scopes
An API token is limited by two things: the role of the user who created it, and the scopes that you selected for it. A request passes only when both allow it. For example, a token with the compute:write scope can't create instances if its user has the Reader role in the project. A write scope doesn't include the matching read scope: select both if the token must change a resource and read it.
The catalog has 17 scopes: a read and a write scope for each of eight areas, and audit:read.
| Scope | Allows |
|---|---|
compute:read | Reading instances, sizes, key pairs, images, instance snapshots, and instance metrics. |
compute:write | Creating, changing, and deleting those resources, and instance actions such as start and stop. |
storage:read | Reading volumes, volume snapshots, volume transfers, backup plans, file shares, and buckets. |
storage:write | Creating, changing, and deleting those resources. |
network:read | Reading networks, subnets, routers, network interfaces, Floating IPs, security groups, and Site-to-Site VPN resources. |
network:write | Creating, changing, and deleting those resources. |
loadbalancer:read | Reading load balancers and the certificates that they use. |
loadbalancer:write | Creating, changing, and deleting those resources. |
kubernetes:read | Reading Kubernetes resources and following their operations and events. |
kubernetes:write | Creating, changing, and deleting those resources. |
observability:read | Reading alert rules, notification channels, and health events. |
observability:write | Creating, changing, and deleting alert rules and notification channels. |
billing:read | Reading cost data, budgets, commitments, invoices, credits, payment methods, and quotas. |
billing:write | Changing billing and cost data, such as creating a budget, redeeming a coupon, or requesting a quota increase. |
iam:read | Reading users, roles, service accounts, and API tokens, and the activity records of the Activity Log. |
iam:write | Changing identity and access: inviting users, granting roles, managing service accounts and API tokens, and changing the sign-in policy and single sign-on. |
audit:read | Reading the activity records of the Activity Log. |
The Activity Log accepts iam:read or audit:read: a token needs only one of them.
Deleting a subscription or a project needs iam:write and the write scope of every resource area: compute:write, storage:write, network:write, loadbalancer:write, kubernetes:write, and observability:write.
Creating a subscription needs iam:write and billing:write, because a subscription is a billing account.
In the console, you select scopes when you create an API token or a service account key. In the API, you send them in the scopes field when you create a token.
What an API token can't call
A token can call every area of the API for which it holds the scope, including changes in Identity & Access Management and billing. These limits apply to every token:
- Console-only operations. Some operations never accept a token. See Operations that need a console session.
- No credential above the token. A token can create a token or a service account key only with scopes that it has itself. A scope that it lacks is refused with
403 Forbiddenand the reasonTOKEN_SCOPE_MISSING. - No credential that outlives the token. A token that expires can't create or rotate a token that expires later or never expires. A service account key that such a token creates ends no later than the token. The refusal is
403 Forbiddenwith the reasonTOKEN_FENCE_EXCEEDED. - No credential outside the token's IP allowlist. A token that has an IP allowlist can create or rotate only tokens whose non-empty allowlist lies within its own. It can't create a service account key, because a key has no allowlist. The refusal is
403 Forbiddenwith the reasonTOKEN_FENCE_EXCEEDED.
Service account key scopes
A service account key has scopes too, and it passes the same scope check as an API token, on top of the roles of its service account. When you create a key, you select its scopes from the catalog without iam:write. A key created without scopes gets every scope except iam:write. A request that asks for iam:write is refused with 422 Unprocessable Entity.
A key is refused on every operation that needs iam:write, with 403 Forbidden and the code INTERACTIVE_SESSION_REQUIRED, whatever its scopes are. Examples are inviting users, granting roles, and creating tokens or keys. Do these changes in the console, or with an API token that has iam:write.
Where a credential works
- One tenant. A credential works only in the tenant where it was created. A request for a project of another tenant returns
404 Not Found, as if the project didn't exist. - Every project of that tenant. An API token isn't tied to the project where you created it. It works in every project of the tenant where its user has a role.
- IP allowlist. If you set IP allowlist on a token, requests from other addresses are refused with
401 Unauthorized. - Expiry and revocation. An expired or revoked token is refused with
401 Unauthorized. The platform checks every bearer request against the current state of the token, so revoking a token takes effect on its next request. - Lifetime. When you create a token, you set an expiry of 30, 60, or 90 days, a custom date, or no expiry. A custom date can be at most 365 days from today (UTC). A later date is refused with
422 Unprocessable Entityand the reasontoken_lifetime_exceeds_maximum. - Rotation. When you rotate an API token, the previous secret keeps working for 24 hours, so you can replace it in your clients. See Rotate an API token.
- Idempotency keys. With an API token or a service account key, a
POSTrequest that creates a resource and answers202 Accepted, such as creating an instance or a volume, must carry anIdempotency-Keyheader. Without it, the request is refused with400 Bad Requestand the codeIDEMPOTENCY_KEY_REQUIRED. On other writes the header is optional, but a retry without it can apply the change again. See Idempotent requests. - Rate limits. Each credential has a rate limit, and so does each tenant, over all of its credentials together. Responses carry
X-RateLimit-Limit,X-RateLimit-Remaining, andX-RateLimit-Reset, the number of seconds until the limit resets. A request over the limit gets429 Too Many Requestswith the codeRATE_LIMITEDand aRetry-Afterheader. See Rate limiting.
Operations that need a console session
These operations require a signed-in console session with a recent two-factor verification:
- Creating an OpenStack credential.
- Rotating an OpenStack credential.
- Turning the organization's OpenStack API access on or off.
With an API token or a service account key, they're refused with 403 Forbidden and the code INTERACTIVE_SESSION_REQUIRED. See Step-up verification.
Troubleshooting
A 403 Forbidden response with the code FORBIDDEN can carry details.reason, which says why the request was refused. A refusal from the API gateway has no details. The table lists both cases.
| Response | Cause | Resolution |
|---|---|---|
401, UNAUTHENTICATED | The credential is wrong, expired, or revoked; the request comes from an address outside the token's IP allowlist; or the token's user is disabled. | Check the value and its status in Identity & AccessAPI tokens. Create a new token if needed. |
403, reason TOKEN_SCOPE_MISSING | The token or key lacks a scope that the operation needs. details.missingTokenScopes lists the missing scopes. | Create a token or a key with those scopes. A service account key can't have iam:write: use an API token or the console for those operations. |
403, reason TOKEN_FENCE_EXCEEDED | A token tried to create or rotate a credential that would outlive it or reach beyond its IP allowlist. details.tokenFence names the limit: expiry, ipAllowlist, or identity. | Give the new credential an earlier expiry and an IP allowlist within the token's own, or create it in the console. |
403, FORBIDDEN without details | The role in the project doesn't allow the operation. | Ask an owner for a role that grants it. |
403, reason ROLE_PERMISSION_MISSING | The role doesn't allow this specific operation. details.requiredPermission and details.requiredLevel name what's needed. | Ask an owner for a role that grants it. |
403, reason SUBSCRIPTION_ROLE_REQUIRED | The resource belongs to the subscription, and the role is granted only on a project. | Ask for a role on the subscription. |
403, INTERACTIVE_SESSION_REQUIRED | The operation needs a console session, or it needs iam:write and the caller is a service account key. | Do it in the console. For an operation that needs iam:write, you can also use an API token that has that scope. |
404, NOT_FOUND | The project or resource doesn't exist, belongs to another tenant, or isn't visible to the credential. | Check the project ID with GET /account/whoami. |
For all error codes, see Errors.