Skip to main content

Frequently Asked Questions

Common questions and answers about the AuthSec SDK.

General Questions

What packages do I need to install?

Use the package for your language. The source repository is named sdk-authsec, but package managers use language-specific names.

PackageUse case
@authsec/sdkTypeScript / JavaScript MCP servers, APIs, and agents
authsec-sdkPython MCP servers, APIs, agents, CIBA, and workload helpers
github.com/authsec-ai/sdk-authsec/packages/go-sdkGo MCP servers, APIs, and agents

The older authz-sdk package was a separate RBAC helper surface. New MCP protection work should start with the runtime SDK pages: Python, TypeScript, or Go.


Is TypeScript/JavaScript support available?

Yes. Install @authsec/sdk and use the runtime-first mountMCP API. See the TypeScript SDK guide.


How do I get the SDK client credentials?

Create an Application in the AuthSec admin UI. The Application UUID is AUTHSEC_RESOURCE_SERVER_ID and AUTHSEC_INTROSPECTION_CLIENT_ID; the one-time secret is AUTHSEC_INTROSPECTION_CLIENT_SECRET.


MCP Servers & Clients

What does mount_mcp / mountMCP / MountMCP do?

The runtime mount wraps your existing MCP HTTP handler. It serves protected-resource metadata, validates bearer tokens, checks tool access against AuthSec's policy, publishes the SDK manifest, and attaches a principal to the downstream request.

from authsec_sdk import from_env, mount_mcp

cfg = from_env()
mount_mcp(app, "/mcp", existing_handler, cfg)

For new servers, prefer the runtime mount APIs. The legacy decorators still exist for older projects.


What about protected_by_AuthSec and run_mcp_server_with_oauth?

They are legacy compatibility APIs — since Python SDK v4.7 they live in authsec_sdk._legacy (still importable from the top level). They remain available for older integrations, but new Applications should use mount_mcp in Python, mountMCP in TypeScript, or MountMCP in Go.


How does a service or agent get a token to CALL a protected server? (Python)

Use AgentIdentity with one of three credential types:

from authsec_sdk import AgentIdentity, ClientSecretAuth, PrivateKeyJwtAuth, SpiffeSvidAuth

agent = AgentIdentity(ISSUER, CLIENT_ID, auth=ClientSecretAuth("sec_...")) # shared secret
agent = AgentIdentity(ISSUER, CLIENT_ID, auth=PrivateKeyJwtAuth("key.pem", kid="key-1")) # RFC 7523, no shared secret
agent = AgentIdentity(ISSUER, CLIENT_ID, auth=SpiffeSvidAuth(svid)) # SPIFFE JWT-SVID

async with agent:
token = await agent.access_for(MCP_URL, requested_scopes=["myapp:read"])

Full guide: M2M auth — three methods. For acting on behalf of a signed-in user, see ID-JAG delegation.


What is preferred_mode on AgentIdentity?

It controls the token-path decision: "auto" (default — delegation when a user_session is present, otherwise direct M2M), "direct-only" (never attempt delegation), "xaa-allowed" (delegation required; hard-error instead of silently falling back to a machine token if the decision endpoint is unreachable). The former Python-only "xaa-only" value was removed in v4.7 for TypeScript-SDK parity.


What changed in the Python package layout in v4.7?

The package is now organized by function: authsec_sdk.identity (agent side), authsec_sdk.runtime (server side), authsec_sdk.spiffe, authsec_sdk.integrations, authsec_sdk._legacy. Old flat paths (authsec_sdk.agent_identity, .core, .ciba_sdk, .delegation_sdk, .spire_sdk, .spiffe_workload_api) still work with a DeprecationWarning and disappear in v5. Top-level imports (from authsec_sdk import ...) are unaffected.


Can I have tools that don't require authentication?

Yes. In AuthSec, public tool status is an operator policy decision. Publish the tool manifest, mark the tool public in the UI, and the runtime policy will allow it for any valid token for the Application.


Workload Identity (SPIRE / SVID)

What is a SPIFFE ID and SVID?

  • SPIFFE ID — A URI that uniquely identifies a workload (e.g. spiffe://example.com/workload/api-service). It is the workload's cryptographic identity.
  • SVID (SPIFFE Verifiable Identity Document) — A short-lived X.509 certificate that proves a workload's SPIFFE ID. SVIDs are rotated automatically.

The AuthSec SDK's QuickStartSVID handles fetching and rotating X.509 SVIDs (mTLS) so your code only needs to call:

from authsec_sdk.spiffe import QuickStartSVID

svid = await QuickStartSVID.initialize()
print(svid.spiffe_id) # spiffe://...
print(svid.cert_file_path) # path to the certificate

For JWT-SVIDs exchanged into AuthSec Bearer tokens (calling a protected MCP server from a pod, no stored credentials), use SpiffeWorkloadIdentity instead — see M2M auth, Method C.


When should I use workload identity instead of OAuth?

ScenarioRecommended approach
A human user is authenticating via a client app or MCP serverOAuth / runtime SDK mount
A service or container needs to call another service with no human in the loopWorkload identity (SPIRE/SVID)
You need mTLS between microservicesWorkload identity (SPIRE/SVID)

Use workload identity for machine-to-machine (M2M) communication. Use OAuth for user-facing flows.


How does certificate auto-renewal work?

The ICP Agent running on your host maintains a live connection to the AuthSec SPIRE server. It automatically renews SVIDs before they expire (default renewal threshold is 6 hours before expiry). Your workload accesses the latest certificate through the SPIRE socket — no restart required.


Which deployment environments are supported for the ICP Agent?

The ICP Agent supports three deployment targets:

EnvironmentRecommended method
KubernetesHelm chart (DaemonSet)
Dockerdocker-compose with shared socket volume
VM (Linux)Quick-install script or manual systemd service

See Autonomous Workloads for step-by-step guides for each environment.


Why does the ICP Agent need SYS_PTRACE capability?

The SYS_PTRACE capability is required for process attestation — the agent inspects process metadata to cryptographically verify the identity of workloads running on the same host. This is how zero-trust attestation works without pre-shared secrets.


RBAC

What is the difference between a permission, a scope, and a role binding?

ConceptDescriptionExample
PermissionA resource + action pairinvoice:create, document:read
ScopeA named group of permissions for a set of resourcesapi.documents.write
Role bindingAssigns a role (which has permissions) to a userBinding editor role to user@example.com

Permissions are the atomic units. Scopes group permissions for OAuth token grants. Role bindings connect users to roles that carry permissions.


What's the difference between check_permission and check_permission_scoped?

  • check_permission(resource, action) — Checks whether the authenticated user has the permission for the current workspace context.
  • check_permission_scoped(resource, action, scope_type, scope_id) — Checks whether the user has the permission within a narrower application or resource scope.
# Global permission check
client.check_permission("document", "read")

# Project-scoped permission check
client.check_permission_scoped("document", "read", scope_type="project", scope_id="proj-123")

Use scoped checks when your application supports multiple applications or resources with isolated permissions.


Are permission checks performed locally or via an API call?

check_permission and check_permission_scoped perform local JWT checks — they decode and verify the user's JWT without making a network call. This makes permission enforcement fast and suitable for use in request handlers.


External Services & Secret Management

How does the SDK securely retrieve external service tokens?

The ServiceAccessSDK retrieves tokens from a secure vault managed by AuthSec. Your application never stores the external token directly — it requests it at runtime within an authenticated session:

services_sdk = ServiceAccessSDK(session)
github_token = await services_sdk.get_service_token("your_token")

This means external credentials are centrally managed and can be rotated without redeploying your application.


What external services can I integrate with?

Any external service that uses bearer token authentication (GitHub, Slack, Jira, etc.) can be integrated by storing that service's token in the AuthSec vault and retrieving it via ServiceAccessSDK.get_service_token(). The SDK acts as a secure credential broker between your workload and the external API.


Troubleshooting

QuickStartSVID.initialize() raises a RuntimeError

Cause: The SPIRE socket path is not configured or the ICP Agent is not running.

Solution:

  1. Verify the ICP Agent is healthy: curl http://localhost:8080/healthz
  2. Check the socket exists: ls -l /run/spire/sockets/agent.sock
  3. Pass the socket path explicitly:
svid = await QuickStartSVID.initialize(socket_path="/run/spire/sockets/agent.sock")

The ICP Agent pod keeps restarting on Kubernetes

Possible causes:

  1. workspaceId or icpServiceUrl are incorrect in values.yaml
  2. The pod cannot reach the AuthSec SPIRE service (network policy issue)
  3. Missing SYS_PTRACE capability in the security context

Diagnosis:

kubectl logs -n default -l app=icp-agent --tail=100
kubectl describe pod -n default -l app=icp-agent

check_permission always returns False

Possible causes:

  1. The AUTHSEC_API_URL environment variable is not set
  2. The user's JWT does not include the expected permission claim
  3. The permission was not created or assigned to the user's role

Solution: Confirm the permission exists and is bound to the correct role, then verify the user has that role assigned.


Support

Still have questions?


Next Steps