# AstraRad auth.md: Agent Authentication and Registration

This document tells automated clients how to obtain credentials for the AstraRad
MCP server at `https://astrarad.com/mcp` without scraping human-facing login pages.

AstraRad is a subspecialist teleradiology provider. The MCP server exposes public
commercial information: service lines, modality coverage, turnaround SLAs and
pricing rules, plus a write path for requesting a per-report rate card. It exposes
no patient data, no imaging studies and no clinical reports, and no credential
issued through this document grants access to any of those.

## Audience

Automated agents acting for hospitals, imaging centres, integrators and referral
partners that want to evaluate AstraRad's coverage, turnaround commitments and
per-report pricing, or to request a rate card on behalf of a named human.

## Discover

1. Fetch OAuth Protected Resource Metadata at
   `https://astrarad.com/.well-known/oauth-protected-resource`.
   It names the resource (`https://astrarad.com/mcp`), the authorization server
   (`https://astrarad.com`), the supported scopes and the bearer method (`header`).
2. Fetch OAuth 2.0 Authorization Server Metadata at
   `https://astrarad.com/.well-known/oauth-authorization-server`
   (OpenID Connect metadata is also published at
   `https://astrarad.com/.well-known/openid-configuration`).
   The `issuer` in both documents is `https://astrarad.com` and matches the
   `authorization_servers` entry in the Protected Resource Metadata.
3. Read the MCP Server Card at
   `https://astrarad.com/.well-known/mcp/server-card.json` for the tool list.

## Register

Dynamic Client Registration (RFC 7591) is open: no pre-approval, no human step.

```http
POST /oauth/register HTTP/1.1
Host: astrarad.com
Content-Type: application/json

{
  "client_name": "your-agent",
  "grant_types": ["client_credentials"],
  "token_endpoint_auth_method": "client_secret_post",
  "scope": "mcp:read"
}
```

The response returns `client_id` and `client_secret`. Client secrets do not expire
(`client_secret_expires_at: 0`). Store them as secrets; do not embed them in
client-side code.

## Agent Auth Metadata

```json
{
  "agent_auth": {
    "skill": "astrarad-mcp-access",
    "register_uri": "https://astrarad.com/oauth/register",
    "identity_types_supported": ["anonymous"],
    "anonymous": {
      "credential_types_supported": ["oauth_client_credentials"],
      "claim_uri": "https://astrarad.com/contact"
    },
    "methods": [
      {
        "type": "oauth2_dynamic_client_registration",
        "register_uri": "https://astrarad.com/oauth/register",
        "token_uri": "https://astrarad.com/oauth/token",
        "grant_types": ["client_credentials"],
        "token_endpoint_auth_methods": [
          "client_secret_post",
          "client_secret_basic"
        ],
        "credential_types_supported": ["oauth_client_credentials"],
        "scopes_supported": ["mcp:read", "mcp:write"],
        "resource": "https://astrarad.com/mcp",
        "human_approval_required": false
      }
    ],
    "contact": "https://astrarad.com/contact"
  }
}
```

## Get a Token

```http
POST /oauth/token HTTP/1.1
Host: astrarad.com
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&client_id=<client_id>&client_secret=<client_secret>&scope=mcp:read
```

The response is a JSON object with `access_token`, `token_type: "Bearer"`,
`expires_in: 3600` and the granted `scope`. Access tokens are HS256 JWTs issued by
`https://astrarad.com` with the audience set to `https://astrarad.com/mcp`.

## Use the Credential

```http
Authorization: Bearer <access_token>
```

Scopes:

- `mcp:read`: read published service, modality, turnaround and pricing information.
- `mcp:write`: submit a rate-card request through the `request_quote` tool.

Read tools are also reachable without a token, so a scanning or evaluation agent can
call them anonymously. Present a token when you want the request attributed, when
you call `request_quote`, or when a future scope requires it.

On `401 Unauthorized` the response carries a `WWW-Authenticate` header with a
`resource_metadata` parameter. Re-fetch the Protected Resource Metadata from that
URL, request a fresh token, and retry once.

## Rate Limits, Errors and Revocation

Handle `invalid_request`, `invalid_client`, `unsupported_grant_type`,
`invalid_token` and `insufficient_scope`. Tokens are short-lived (1 hour); request a
new one rather than caching indefinitely. To have a client revoked, submit the
`client_id` through https://astrarad.com/contact?ask=compliance.

Request the least-privileged scope that completes your task. Do not use
`request_quote` to submit contact details for a human who has not asked you to.

## Contact

- Contact form: https://astrarad.com/contact
- Machine-readable overview: https://astrarad.com/llms.txt
