{
  "access": "public",
  "type": "reference",
  "format": "markdown",
  "title": "Authentication Guide",
  "chunked": true,
  "url": "https://library.datagrout.ai/authentication",
  "summary": "**How to authenticate connections to your DataGrout server**",
  "content_markdown": "# Authentication\n\n**How to authenticate connections to your DataGrout server**\n\nDataGrout supports three authentication methods: access tokens, mutual TLS, and OAuth 2.1. If you use the Conduit SDK, authentication is handled for you -- pass your credentials to the `ClientBuilder` and the SDK manages the rest.\n\n---\n\n## Conduit SDK (Recommended)\n\nThe Conduit SDK handles authentication automatically. You configure it once and never manage headers, tokens, or certificates manually.\n\n```python\nfrom datagrout_conduit import ClientBuilder\n\n# Bearer token\nclient = ClientBuilder() \\\n    .url(\"https://gateway.datagrout.ai/servers/YOUR_UUID/mcp\") \\\n    .auth_bearer(\"your-token\") \\\n    .build()\n\n# Mutual TLS\nclient = ClientBuilder() \\\n    .url(\"https://gateway.datagrout.ai/servers/YOUR_UUID/mcp\") \\\n    .auth_mtls(ClientCert.from_paths(\"client.crt\", \"client.key\", \"ca.crt\")) \\\n    .build()\n\n# OAuth 2.1\nclient = ClientBuilder() \\\n    .url(\"https://gateway.datagrout.ai/servers/YOUR_UUID/mcp\") \\\n    .auth_oauth(\"https://auth.example.com/.well-known/oauth-authorization-server\") \\\n    .build()\n```\n\nSee [Conduit SDK](conduit-sdk) for full setup.\n\n---\n\n## Access Tokens (Bearer)\n\nThe simplest method. Create a token in the UI, pass it in the `Authorization` header.\n\n### Create a Token\n\n1. Open the **server dropdown** and click the **Settings** icon\n2. Go to the **Authentication** tab\n3. Click **Create Access Token**\n4. Give it a name (optional)\n5. Copy the token immediately\n\n### Use with cURL\n\nUse the `/rpc` endpoint for stateless HTTP requests:\n\n```bash\ncurl -X POST https://gateway.datagrout.ai/servers/YOUR_UUID/rpc \\\n  -H \"Content-Type: application/json\" \\\n  -H \"Authorization: Bearer YOUR_TOKEN\" \\\n  -d '{\"jsonrpc\": \"2.0\", \"method\": \"tools/list\", \"params\": {}, \"id\": 1}'\n```\n\nThe MCP endpoint (`/mcp`) also accepts bearer tokens, but requires SSE initialization. Use `/rpc` for simple testing.\n\n### Token Management\n\n- Tokens are listed in **Settings > Authentication**\n- Click **Delete** to revoke a token immediately\n- Use separate tokens per agent or environment\n- Store tokens in environment variables, not code\n\n---\n\n## Mutual TLS (mTLS)\n\nCertificate-based authentication for production deployments. The client certificate is the credential -- no bearer token needed after the initial bootstrap.\n\n### Bootstrapping with the Conduit SDK\n\nThe Conduit SDK handles the entire mTLS bootstrap process automatically. You do not manage raw certificates — the SDK generates a key pair, calls the server-scoped DataGrout identity endpoint for the target MCP server, receives a DG-signed certificate, and stores everything in `~/.conduit/`. Subsequent connections use the stored identity with no credentials required.\n\n**Python**\n\n```python\nfrom datagrout.conduit import Client\n\n# First run: bootstrap with a token\nclient = await Client.bootstrap_identity(\n    url=\"https://gateway.datagrout.ai/servers/YOUR_UUID/mcp\",\n    auth_token=\"your-access-token\",\n    name=\"my-agent\",\n)\n\n# Or bootstrap with OAuth 2.1 client_credentials\nclient = await Client.bootstrap_identity_oauth(\n    url=\"https://gateway.datagrout.ai/servers/YOUR_UUID/mcp\",\n    client_id=\"my_client_id\",\n    client_secret=\"my_client_secret\",\n    name=\"my-agent\",\n)\n\n# All subsequent runs: identity auto-discovered from ~/.conduit/\n# and presented directly to /servers/YOUR_UUID/mcp over mTLS\nclient = Client(\"https://gateway.datagrout.ai/servers/YOUR_UUID/mcp\")\n```\n\n**TypeScript**\n\n```typescript\nimport { Client } from '@datagrout/conduit';\n\n// First run: bootstrap with a token\nconst client = await Client.bootstrapIdentity({\n    url: 'https://gateway.datagrout.ai/servers/YOUR_UUID/mcp',\n    authToken: 'your-access-token',\n    name: 'my-agent',\n});\n\n// Or bootstrap with OAuth 2.1 client_credentials\nconst client = await Client.bootstrapIdentityOAuth({\n    url: 'https://gateway.datagrout.ai/servers/YOUR_UUID/mcp',\n    clientId: 'my_client_id',\n    clientSecret: 'my_client_secret',\n    name: 'my-agent',\n});\n\n// All subsequent runs: identity auto-discovered from ~/.conduit/\nconst client = new Client('https://gateway.datagrout.ai/servers/YOUR_UUID/mcp');\nawait client.connect();\n```\n\n**Rust**\n\n```rust\n// First run: bootstrap\nlet client = ClientBuilder::new()\n    .url(\"https://gateway.datagrout.ai/servers/YOUR_UUID/mcp\")\n    .bootstrap_identity(\"your-access-token\", \"my-agent\")\n    .await?\n    .build()?;\n\n// Subsequent runs: auto-discovered from ~/.conduit/\nlet client = ClientBuilder::new()\n    .url(\"https://gateway.datagrout.ai/servers/YOUR_UUID/mcp\")\n    .build()?;\n```\n\n### Identity Auto-Discovery\n\nThe Conduit SDK searches for identity files automatically in this order:\n\n1. `CONDUIT_MTLS_CERT` + `CONDUIT_MTLS_KEY` environment variables (inline PEM strings)\n2. `CONDUIT_IDENTITY_DIR` environment variable (directory containing `identity.pem` + `identity_key.pem`)\n3. `~/.conduit/identity.pem` + `~/.conduit/identity_key.pem`\n4. `.conduit/` relative to the current working directory\n\nFor DataGrout URLs, auto-discovery runs silently. For other URLs, set `identity_auto=True` (Python) or `.with_identity_auto()` (Rust).\n\n### Global Arbiter Bootstrap\n\nThe legacy global substrate endpoints under `/api/v1/substrate/identity/*` still\nuse `ARBITER_API_KEY` for Bearer bootstrap before mTLS exists. DataGrout now\nauto-generates that key at runtime when it is missing:\n\n- if `DG_SECRETS_NAMESPACE` is configured, the generated key is stored in AWS Secrets Manager\n- otherwise, a local runtime fallback is generated for the current process only\n\nNormal Conduit and Invariant MCP bootstrap does not use this global Arbiter path anymore.\nIt uses the server-scoped `/servers/:server_id/identity/*` endpoints instead.\n\n### Multiple Agents on One Machine\n\nUse `identity_dir` to give each agent its own certificate:\n\n```python\nclient = Client(\n    \"https://gateway.datagrout.ai/servers/YOUR_UUID/mcp\",\n    identity_dir=\"/opt/agents/agent-a/.conduit\",\n    identity_auto=True,\n)\n```\n\nOr set the `CONDUIT_IDENTITY_DIR` environment variable per process.\n\n### Use with cURL\n\n```bash\ncurl -X POST https://gateway.datagrout.ai/servers/YOUR_UUID/rpc \\\n  --cert ~/.conduit/identity.pem \\\n  --key ~/.conduit/identity_key.pem \\\n  --cacert ~/.conduit/ca.pem \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"jsonrpc\": \"2.0\", \"method\": \"tools/list\", \"params\": {}, \"id\": 1}'\n```\n\n### Certificate Management\n\n- Certificates are stored in `~/.conduit/` by default (or the configured `identity_dir`)\n- The SDK checks expiry and warns when rotation is needed\n- Rotate certificates via `rotate_identity()` -- uses the existing cert for authentication (no token required)\n- Revoke certificates in **Settings > Authentication** when agents are decommissioned\n\n---\n\n## OAuth 2.1\n\nFor user-facing applications where users delegate access to your agent.\n\n### Grant Types\n\n- **Client Credentials**: Machine-to-machine, no user context\n- **Authorization Code + PKCE**: User delegates access to your app\n\n### Setup\n\n1. Go to **Settings > Authentication**\n2. Create an OAuth client with redirect URIs and scopes\n3. Save the client ID and secret\n\n### Client Credentials Flow\n\nRequest an access token:\n\n```bash\ncurl -X POST https://gateway.datagrout.ai/oauth/token \\\n  -H \"Content-Type: application/x-www-form-urlencoded\" \\\n  -d \"grant_type=client_credentials\" \\\n  -d \"client_id=YOUR_CLIENT_ID\" \\\n  -d \"client_secret=YOUR_CLIENT_SECRET\"\n```\n\nUse the returned access token as a bearer token. Tokens are short-lived and must be refreshed.\n\n### Authorization Code Flow\n\n1. Redirect the user to the DataGrout authorization endpoint\n2. User approves access\n3. Exchange the authorization code for an access token\n4. Use the access token as a bearer token\n\nThe Conduit SDK handles the full OAuth flow automatically when configured with `.auth_oauth()`.\n\n---\n\n## Which Method to Use\n\n| Method | Best For |\n|--------|----------|\n| **Access Tokens** | Development, scripts, internal agents |\n| **mTLS** | Production agents, enterprise deployments |\n| **OAuth 2.1** | User-facing apps, third-party integrations |\n\n---\n\n## Related\n\n- [Conduit SDK](conduit-sdk) -- Handles authentication automatically\n- [Quick Start](quick-start) -- Create your first token\n- [JSONRPC Transport](jsonrpc) -- Using the stateless `/rpc` endpoint\n"
}