Skip to main content

Method A — Client secret (Python SDK)

The simplest credential: ID + shared secret, sent via HTTP Basic on each token request.

Dashboard walkthrough

For creating the service account and granting access with screenshots, see Client secret (dashboard guide).

Environment

AUTHSEC_ISSUER=https://app.authsec.ai
SA_CLIENT_ID=<from the create dialog>
SA_CLIENT_SECRET=<the one-time secret>
MCP_URL=https://your-mcp-server.example.com/mcp
VariableWhat it doesWhere it comes from
AUTHSEC_ISSUERThe OAuth issuer. The SDK uses it to discover the token endpoint (<issuer>/oauth/token) for the client_credentials grant.Always https://app.authsec.ai
SA_CLIENT_IDThe service account's unique ID. Sent as the client_id in the token request.Shown in the create-service-account dialog (dashboard guide)
SA_CLIENT_SECRETThe shared secret. Sent via HTTP Basic auth on every token request. 64 hex characters -- copy-paste, never retype. Shown once at creation; rotate from the dashboard if lost.Shown once in the credentials dialog
MCP_URLThe target MCP server's Resource URI. The SDK requests a token scoped to this audience. Must match the server's registered AUTHSEC_RESOURCE_URI exactly.The Resource URI from registration

Full program

import asyncio, os
from dotenv import load_dotenv
from authsec_sdk import AgentIdentity, ClientSecretAuth

load_dotenv()

async def main():
agent = AgentIdentity(
os.environ["AUTHSEC_ISSUER"],
os.environ["SA_CLIENT_ID"],
auth=ClientSecretAuth(os.environ["SA_CLIENT_SECRET"]),
)
async with agent:
token = await agent.access_for(
os.environ["MCP_URL"],
requested_scopes=["my_mcp:read", "my_mcp:tools:read"],
)
print("token:", token[:25], "…") # → Authorization: Bearer {token}

asyncio.run(main())

How ClientSecretAuth works

Each access_for() call sends a client_credentials grant with client_secret_basic authentication (the client ID and secret as HTTP Basic credentials). AuthSec returns a short-lived, scoped access token.

The token is cached by AgentIdentity until near expiry — repeated access_for() calls don't hit the token endpoint every time.

Shared steps