# AgentTwin API authentication

Use `https://api.agenttwin.si` for account resources. Public documentation MCP at `https://agenttwin.si/mcp/docs` needs no account and cannot execute tests. For machine integration, use a confidential OAuth client bound to one synced project and explicit permissions. Human website sign-in and terminal pairing remain separate.

## Discover

Read [OAuth protected-resource metadata](https://api.agenttwin.si/.well-known/oauth-protected-resource) (RFC 9728). Its `authorization_servers` points to the issuer `https://api.agenttwin.si`. Fetch [OAuth authorization-server metadata](https://api.agenttwin.si/.well-known/oauth-authorization-server) (RFC 8414) for `token_endpoint`, `revocation_endpoint`, supported grants and `scopes_supported`. A protected API request without credentials returns `WWW-Authenticate: Bearer resource_metadata="https://api.agenttwin.si/.well-known/oauth-protected-resource"`.

## Pick a method

Confidential server-side agents use OAuth 2.0 `client_credentials` with `client_secret_basic`. Supported scopes are `read:projects`, `read:discovery`, `read:runs`, `read:workflows`, `write:runs` and `write:workflows`. Select only necessary scopes. Every client belongs to one account and one synced project. A `write:runs` grant permits execution of reviewed uploaded code and may incur configured cloud-provider charges.

Interactive users sign in on the website and run `npx agenttwin login` or `npx agenttwin init` to pair a terminal. Approve only the displayed terminal code. The resulting legacy account token is full-account access, not a scoped agent token.

## Register

Sign in and sync a project first. Using your private owner account token or trusted browser session, call `POST /v1/oauth/clients` with JSON `{"label":"My test agent","project":"YOUR_SYNCED_PROJECT","scopes":["read:projects","read:runs"]}`. Only full account credentials can manage these grants. The response shows `client_id` and `client_secret` once. Store the secret privately outside repositories and browser storage. List existing grants with `GET /v1/oauth/clients`; secrets cannot be recovered.

This is authenticated owner-managed client creation, not RFC 7591 open dynamic registration. No WorkOS `agent_auth` extension, `identity_endpoint`, `identity_assertion`, `service_auth` identity registration, ID-JAG assertion exchange, claim endpoint or events endpoint is implemented or advertised. Do not send identity assertions or follow guessed registration URLs.

## Claim

The owner selects the project and explicit scopes when creating the client; there is no anonymous client claiming process. Anonymous agents cannot create accounts or inherit a user's session. Client credentials are for trusted server-side machines; browser-only and third-party interactive clients need a future authorization-code/PKCE integration.

## Exchange

Send the client ID and secret through HTTP Basic authentication to the published token endpoint, with `Content-Type: application/x-www-form-urlencoded`. Percent-encode the ID and secret before constructing Basic credentials as RFC 6749 specifies. Request body: `grant_type=client_credentials&scope=read%3Aprojects`. Omitting `scope` requests exactly the owner's granted scopes; supplying it may only narrow that grant. Optional `resource=https%3A%2F%2Fapi.agenttwin.si` selects this API. Access tokens expire after 3600 seconds. No refresh token is issued; exchange the client credential again when needed.

```sh
# Set CLIENT_ID and CLIENT_SECRET privately in your shell; never paste real values into logs.
curl --user "$CLIENT_ID:$CLIENT_SECRET" \
  --data-urlencode grant_type=client_credentials \
  --data-urlencode scope=read:projects \
  https://api.agenttwin.si/oauth/token
```

## Use the access_token

Send `Authorization: Bearer ACCESS_TOKEN` to the API. `GET /v1/projects` requires `read:projects` and returns only the granted project. Requests for another project are denied. `GET /v1/runs?limit=20` requires `read:runs`; follow `nextCursor` for more results. The [OpenAPI document](/openapi.json) declares each operation's required scope and typed inputs/results. Tokens cannot access account management, chat, source sync or unlisted operations.

## Errors

OAuth errors use RFC 6749 identifiers such as `invalid_client`, `invalid_scope`, `unsupported_grant_type` and `invalid_request`. The resource server uses 401 for expired/revoked/invalid tokens and 403 `insufficient_scope` for a missing permission. Keep unknown error values. A request for a different project returns 403 `project_not_authorized`. Rate limits return 429 with `Retry-After`; inspect `RateLimit` and `RateLimit-Policy` on responses. Never automatically retry a cloud execution submission without its documented idempotency key.

## Revocation

Call the metadata's `revocation_endpoint` with client Basic authentication and form `token=ACCESS_TOKEN` (RFC 7009). Unknown tokens return 200 without disclosing ownership. To invalidate a client and all its tokens, the owner calls `DELETE /v1/oauth/clients/CLIENT_ID`. Revoking the account also invalidates its machine tokens. Store contains hashes of secrets and tokens, never their plaintext values. Tokens and grants survive an ordinary API restart; token expiration still applies.

## Separate environments and sandbox

Local and production accounts remain separate. A website cannot inspect arbitrary terminal files: discovery must sync through the paired account. For a credential-free synthetic test, follow the [sandbox quickstart](/sandbox/). A local twin has host filesystem/network access; review its application files before execution. No provider production accounts are copied.
