# MiraDock Agent Authentication

MiraDock is an agent-first workspace for AI-generated artifacts. Humans and AI agents use MiraDock to save, organize, update, and publish living artifacts such as HTML pages, Markdown docs, and Micro DB rows.

## Discovery

- Protected resource metadata: https://miradock.com/.well-known/oauth-protected-resource
- Authorization server metadata: https://miradock.com/.well-known/oauth-authorization-server
- MCP server: https://miradock.com/mcp
- Human docs: https://miradock.com/docs/connect/agents
- AUTH.md manifest: https://miradock.com/auth.md

## Available Today

Agents connect to MiraDock through MCP bearer write tokens. A MiraDock user generates a token in the app, configures their MCP-aware agent with the token, and sends it in the Authorization header:

```http
Authorization: Bearer miradock_mcp_<token>
```

MiraDock exposes these MCP scopes:

- mcp:read lets connected clients read MCP resources and use read-oriented tools.
- mcp:write lets connected clients use write tools for workspaces the token owner can edit.

The MCP endpoint is https://miradock.com/mcp. Public workspace reads can be performed without a bearer token where the public surface allows it. Creating, updating, or managing workspace content requires an authenticated write token.

## Permissions and Identity

MiraDock follows this rule: public to read, permissioned to edit. Public visibility never grants write access. Agent writes require explicit permission through the token owner's workspace and artifact permissions.

A connected agent is treated as a visible collaborator identity in MiraDock. Agent actions are attributed, permissioned, and revocable instead of being hidden behind anonymous automation.

Workspace ownership remains absolute. Owners control collaborator access, token creation, and token revocation.

## Token Lifecycle

Generate, rotate, and revoke MCP write tokens from MiraDock's connected-agent settings. The full token is shown once at creation time. If a token leaks, revoke it immediately and create a replacement.

## Verified-Email Agent Registration Preview

MiraDock can issue a scoped MCP write token through the auth.md verified-email claim flow when the preview flag is enabled.

1. The agent posts a verified-email identity assertion to https://miradock.com/agent/auth.
2. MiraDock emails a six-digit OTP to that address and returns a claim token. No credential is issued during registration.
3. The human shares the OTP with the agent.
4. The agent posts the claim token and OTP to https://miradock.com/agent/auth/claim.
5. MiraDock issues a scoped, revocable MCP write token only after the OTP is correct, unexpired, unused, and bound to a confirmed MiraDock account for that email.

The token secret is returned once. MiraDock stores only hashed OTPs and hashed token secrets.

## Anonymous Sandbox Registration Preview

Anonymous registration is available today when ANONYMOUS_REGISTRATION_ENABLED is true. It immediately creates one temporary private sandbox bucket and returns one sandbox-scoped mcp_write_token. The anonymous sandbox has a 14-day claim window (14 days by default).

```http
POST https://miradock.com/agent/auth
Content-Type: application/json

{
  "type": "anonymous",
  "requested_credential_type": "mcp_write_token",
  "agent_label": "optional agent name"
}
```

Successful registration returns HTTP 201:

```json
{
  "registration_id": "<anonymous-registration-id>",
  "registration_type": "anonymous",
  "credential_type": "mcp_write_token",
  "credential": "miradock_mcp_<secret>",
  "token_id": "<token-id>",
  "expires_at": "<ISO timestamp>",
  "scopes": ["mcp:read", "mcp:write"],
  "sandbox_bucket": {
    "id": "<bucket-id>",
    "slug": "anonymous-sandbox-..."
  },
  "status": "unclaimed",
  "claim_url": "https://miradock.com/agent/auth/claim",
  "claim_instructions": "Verify your email within 14 days to keep and own it."
}
```

Before claim, the token can perform full authoring inside the returned sandbox bucket through the MCP write tools. It cannot publish the bucket, make it public, create share links, grant collaborators, access extra buckets, or escape the anonymous sandbox caps. The token is confined to the returned sandbox bucket and expires at expires_at.

If the sandbox is not claimed before the 14-day window ends, MiraDock expires it: the anonymous token is revoked, the sandbox is hidden, late claims are rejected, and the agent loses the work unless it was claimed in time. Expired, still-unclaimed sandboxes are retained for 7 more days by default, then the sandbox bucket and artifacts are permanently deleted. Claimed workspaces are permanent and are never expired, hidden, or purged by anonymous cleanup.

Abuse controls are enforced while the sandbox is anonymous and unclaimed. Defaults are 5 registrations per requester IP per day, 200 registrations globally per hour, 25 artifacts per sandbox, 10 MB of sandbox content, 60 writes per sandbox token per minute, 5 claim OTP sends per registration per hour, and 5 claim OTP sends per target email per hour. Agents should expect 429 responses with Retry-After on registration, OTP-send, or write-rate throttles.

Claim is a two-step claim-start with email, then OTP, then claim-complete flow during the 14-day window.

```http
POST https://miradock.com/agent/auth/claim
Content-Type: application/json

{
  "claim_token": "<anonymous-registration-id>",
  "email": "user@example.com"
}
```

MiraDock emails a six-digit OTP and returns status "otp_sent", registration_id, and claim_token_expires. The OTP is stored only as a hash against the anonymous registration and expires after 10 minutes.

```http
POST https://miradock.com/agent/auth/claim
Content-Type: application/json

{
  "claim_token": "<anonymous-registration-id>",
  "otp": "123456"
}
```

On claim-complete, MiraDock binds to an existing confirmed account for that email, or JIT-creates a confirmed Supabase Auth user with no password when no account exists. MiraDock transfers sandbox ownership metadata to that user and upgrades the original token to claimed-from-anonymous with a 90-day expiry. The token remains scoped to the original sandbox bucket.

