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
| Variable | What it does | Where it comes from |
|---|---|---|
AUTHSEC_ISSUER | The 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_ID | The 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_SECRET | The 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_URL | The 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
- Grant access — required before the first token request
- Verify — prove the token works
- Troubleshooting — every error we hit while building this SDK