Skip to main content

Service accounts: client secret

~5 minutes. The simplest machine credential: ID plus shared secret. Right for quick starts and simple deployments. If the caller runs in Kubernetes or your security posture forbids shared secrets, start at the comparison instead.

Full SDK code

For the complete runnable program and API details, see Client secret (Python SDK).

How it works

Step 1 -- Create the service account

Open WORKSPACE -> Service Accounts in the sidebar. Each service account is a machine principal with one credential, granted access to MCP servers independently of any user session. Click + Create service account:

Service Accounts page

Name it after the workload (reporting-pipeline, ci-deployer), keep Client secret selected (the default), and click Create service account:

Create service account -- client secret

Step 2 -- Save the credentials (shown once)

Client secret credentials

Copy both values into the caller's environment -- the secret is not shown again. Copy-paste the 64-hex-character secret; never retype it.

AUTHSEC_ISSUER=https://app.authsec.ai
SA_CLIENT_ID=<client id from the dialog>
SA_CLIENT_SECRET=<the secret you copied>
MCP_URL=https://your-mcp-server.example.com/mcp

Step 3 -- Grant access (identity does not equal permission)

Creating the account gives it an identity, not permissions. Without a role, every token request fails with access_denied: client not authorized for this resource server.

Open your application -> Access tab -> Add access -> Machine credential (secret/key) -> pick this service account and the role it should hold (e.g. Readonly). The account appears in Who has access with its role and effective scopes.

Step 4 -- Get a token and call the server

Trade the credential for a short-lived, scoped access token:

from authsec_sdk import AgentIdentity, ClientSecretAuth

agent = AgentIdentity(ISSUER, SA_CLIENT_ID, auth=ClientSecretAuth(SA_CLIENT_SECRET))
async with agent:
token = await agent.access_for(MCP_URL, requested_scopes=["my_mcp:read"])
# → Authorization: Bearer {token} on MCP requests

Full runnable program and details: Python SDK -- client secret.

Verify

  • Application -> Connections tab shows the account as an active (m2m) connection with its role and scopes.
  • MONITOR -> M2M Logs shows each token grant as it happens.
  • A tools/list call with the token returns only the tools the granted scopes allow.

Revoking

Application -> Access tab -> Who has access -> the account's ... menu -> Revoke access. This removes access to this application only; other grants are untouched.

Troubleshooting

ErrorCauseFix
invalid_client: invalid client secretTypo'd or rotated secretCopy-paste from the dashboard, never retype
access_denied: client not authorized for this resource serverCredential is valid but no grant existsStep 3 -- assign a role on the target application

Next

A shared secret is the floor, not the ceiling:

-> Upgrade to Private-key JWT -- no secret ever crosses the wire.