# auth.md

Midkernel uses Google sign-in and explicit human consent to connect an agent to an existing account and workspace. Registration alone grants no access and creates no account, workspace, credits, or scans.

## Discovery

- OAuth issuer: https://www.midkernel.com/security/app
- Authorization server metadata: https://www.midkernel.com/security/app/.well-known/oauth-authorization-server
- Default service resource: https://www.midkernel.com
- Canonical MCP resource: https://www.midkernel.com/security/app/mcp
- MCP protected-resource metadata: https://www.midkernel.com/security/app/.well-known/oauth-protected-resource
- Registration: POST https://www.midkernel.com/security/app/api/agent/identity
- Claim ceremony renewal: POST https://www.midkernel.com/security/app/api/agent/identity/claim
- Token exchange: POST https://www.midkernel.com/security/app/api/oauth/token
- Human consent: https://www.midkernel.com/security/app/oauth/claim
- Manage and revoke agent access: https://www.midkernel.com/security/app/oauth/agents

Select exactly one resource per grant. The default agent registration resource is the origin service, which includes protected Scan REST, Threat Intel REST, and MCP endpoints under https://www.midkernel.com/security/app. Existing OAuth clients default to the canonical MCP resource. These identifiers are exact and cannot be exchanged or refreshed into one another. Validate the exact issuer and selected resource; an HTTP referral does not change either identity.

## Register a service agent

Send application/json:

```json
{"type":"service_auth","login_hint":"person@example.com","client_name":"My research agent","scope":"threat-intel:read","resource":"https://www.midkernel.com"}
```

The verified_email compatibility request is also supported:

```json
{"type":"identity_assertion","assertion_type":"verified_email","assertion":"person@example.com","client_name":"My research agent"}
```

Both request formats start the same Google consent ceremony. An email hint is never identity proof. There is no email OTP endpoint. The signed-in Google account must have that verified email and an active Midkernel membership. Anonymous credentials, JWT-bearer assertion exchange, and provider-event registration are unsupported.

The response contains registration_id, registration_type service_auth, a private claim_token and its expiration, post_claim_scopes, the selected resource, and a claim object containing user_code, verification_uri, expires_in, and interval. The pending ceremony lasts ten minutes. Keep claim_token private; never send it to the human or place it in a URL. Open verification_uri for the human and show user_code separately. The URL contains an opaque claim-attempt token and never the code. The human signs in, checks the workspace, agent name and scopes, enters the separate code, then explicitly approves or denies.

## Obtain the approved credential

Poll the token endpoint using application/x-www-form-urlencoded, at most once every five seconds:

```text
grant_type=urn:workos:agent-auth:grant-type:claim&claim_token=PRIVATE_CLAIM_TOKEN&resource=https%3A%2F%2Fwww.midkernel.com
```

Before approval the response is authorization_pending. Excessive polling returns slow_down; denial returns access_denied; an expired ceremony returns expired_token. After approval a single successful exchange returns access_token, token_type Bearer, expires_in 3600, and the approved scope. Claim exchange is single use. This profile issues an access token directly; it issues neither an identity assertion nor a refresh token. Re-register and obtain fresh human consent when access expires.

If a pending ceremony needs a new human link or code, POST application/json containing claim_token and email to the claim renewal endpoint. The same private claim token and email hint are required. Renewal invalidates the previous link and code and never extends the original expiration. At most three renewals are allowed, separated by thirty seconds after the first. A new expired request requires registration again.

## Permissions and revocation

- threat-intel:read is the default. It permits read-only Threat Intel REST and the corresponding authenticated MCP tools. It spends no Scan credits.
- scan must be requested and explicitly approved. It permits starting scans and reading run reports; normal workspace permissions, billing, and credit limits apply. Consent itself never starts a scan.

These agent permissions exclude organization credential management, invitations, and platform administration, including when the approving account is an administrator.

Send Authorization: Bearer ACCESS_TOKEN to the protected service endpoints, including https://www.midkernel.com/security/app/api/threat-intel/evidence, https://www.midkernel.com/security/app/api/scans/start for approved scan access, or https://www.midkernel.com/security/app/mcp. Public Threat Intel MCP at https://www.midkernel.com/security/app/mcp/threat-intel remains available without registration.

The account holder can revoke access at https://www.midkernel.com/security/app/oauth/agents. Every authenticated agent request checks the stored grant, issuer, audience, scope, expiry, authority epoch and live membership. Revoked grants, removed membership and disabled accounts fail closed. Never paste access tokens, claim tokens, or claim URLs into logs, issues, or chat.
