# Authentication at vote.direct

Last updated: 2026-09-30

## Summary

| Surface | URL | Auth |
| --- | --- | --- |
| MCP server, open tools | https://vote.direct/api/mcp | None |
| MCP server, account tools | https://vote.direct/api/mcp | OAuth 2.1 sign-in, or an agent key (`Authorization: Bearer vd_agent_…`) |
| A2A agent (read-only) | https://vote.direct/api/a2a | None |
| Site summary | https://vote.direct/llms.txt | None |
| Paying, sending invitations, results | https://vote.direct/dashboard | The person, signed in |

## Without a credential

- `get_price_quote`: Exact election price quote
- `get_state_hoa_rules`: HOA voting rules for a US state
- `compare_platforms`: Compare vote.direct with a competitor
- `get_review_record`: Every third-party review, verbatim
- `get_platform_overview`: What vote.direct is and does
- `get_governance_center_overview`: What governance.center is and what it costs
- `start_election_draft`: Start an election for someone without an account

`start_election_draft` builds a complete election for someone with no
account and returns a link: they open it, create an account, and the election
is theirs to review and publish. Nothing is charged and no voter is contacted
until they do.

## Signing in (OAuth 2.1)

Sign-in is lazy. `initialize`, `tools/list` and the open tools never need
a token. The first call to an account tool without one gets HTTP 401 with:

`WWW-Authenticate: Bearer error="invalid_token", resource_metadata="https://vote.direct/.well-known/oauth-protected-resource/api/mcp", scope="agent:read agent:draft"`

A spec-following client signs the person in from that and retries the call.
ChatGPT receives the same challenge in the tool result's
`_meta["mcp/www_authenticate"]` instead.

- Protected resource metadata (RFC 9728): https://vote.direct/.well-known/oauth-protected-resource/api/mcp
- Authorization server metadata (RFC 8414): https://vote.direct/.well-known/oauth-authorization-server
- Issuer: `https://vote.direct`; authorization: https://vote.direct/api/oauth/authorize; token: https://vote.direct/api/oauth/token
- Client registration: a Client ID Metadata Document (the `client_id` is the
  https URL of your client's JSON), or Dynamic Client Registration (RFC 7591)
  at https://vote.direct/api/oauth/register
- Authorization code with PKCE (S256 only). Send `resource=https://vote.direct/api/mcp`;
  a token is valid only there. Authorization responses carry `iss` (RFC 9207).
- Public clients (`none`) and confidential ones (`client_secret_post`,
  `client_secret_basic`). Loopback redirect URIs match on any port.
- Access tokens last 60 minutes. Refresh tokens last 90 days from last use
  and rotate on every refresh; a dead one gets `invalid_grant`.
- Revocation (RFC 7009): https://vote.direct/api/oauth/revoke

The person approves each connection on a consent page that names the app and
where it returns to. Publishing is off unless they tick it there. They can
disconnect any app at https://vote.direct/settings/agents.

## With an agent key

For assistants that take a pasted bearer token rather than a sign-in (Meta's
Muse, Manus, Poke). The account owner creates a key at
https://vote.direct/settings/agents, names it after the assistant, and pastes it
in as a Bearer token. The key acts as that person, only on elections they
created, and they can revoke it there at any time. Only its hash is stored; it
is shown once.

## Account tools

- `list_elections`: List this account's elections and surveys (`agent:read`)
- `get_election`: Status of one election or survey (`agent:read`)
- `create_election_draft`: Draft an election (`agent:draft`)
- `add_voters`: Add voters to a draft election (`agent:draft`)
- `create_survey`: Create a survey (`agent:draft`)
- `publish_election`: Publish a draft election (`agent:publish`)

Scopes, the same for OAuth and agent keys:

- `agent:read`: list elections and surveys; read status, voters and turnout
- `agent:draft`: create and edit drafts, add voters to drafts, create surveys
- `agent:publish`: publish a draft, which can spend the owner's prepaid
  balance. Opt-in: the person ticks it when they approve the connection or
  make the key. Without it they publish from the finish link the tools return.

A connection or key is limited to 60 calls a minute. Send the token on every
request; there is no session.

## What still needs the person

Paying by card, sending invitations and reminders, texting voters (a consent
attestation only the organizer can give), and anything on a published
election's roster. Every tool that stops short of these returns the link where
the person finishes.

## Not offered (do not probe for these)

- No client_credentials grant: every token acts for a person who approved it.
- No password, session or cookie access for agents.

## Asking for more

Building something that needs more than this: write to hello@vote.direct.
