---
title: "Authentication for agents at YouSpot"
description: "How an agent gets a credential here: OAuth 2.1 with PKCE, or a per-tool token the person mints."
canonical: https://youspot.com/auth.md
last-updated: 2026-09-04
---

# Authentication for agents at YouSpot

YouSpot is a personal CRM. Every tool call and every API read is scoped to
one person, so there is no anonymous data to hand out and no service
credential that stands in for a customer. An agent works here by being
delegated a person's access through OAuth 2.1.

Machine-readable truth: [`/.well-known/oauth-authorization-server`](https://youspot.com/.well-known/oauth-authorization-server)
and [`/.well-known/oauth-protected-resource`](https://youspot.com/.well-known/oauth-protected-resource).
This file explains them and hands over the requests.

## Discover

```bash
curl https://youspot.com/.well-known/oauth-authorization-server
curl https://youspot.com/.well-known/oauth-protected-resource
```

The protected resource is `https://youspot.com/mcp`. Its authorization server is
`https://youspot.com`. The only scope is `linkedin`.

`https://youspot.com/agent/identity` answers what identity you can hold. POST
`{"type":"anonymous"}` for the surfaces that need no credential, or
`{"type":"service_auth"}` with a bearer token to be told whose access you
are holding.

## Pick a method

| You are | Use |
| --- | --- |
| An MCP client acting for a signed-in person (Claude, ChatGPT, Claude Code) | OAuth 2.1 authorization code with PKCE S256 |
| A CLI or script the person runs themselves | A per-tool token from https://youspot.com/user/mcp |

There is no client credentials grant and no anonymous identity: a token that
belonged to no person would have nothing to read.

## Register

Dynamic client registration (RFC 7591) is open. No pre-approval, no key.

```bash
curl -X POST https://youspot.com/oauth/register \
  -H "Content-Type: application/json" \
  -d '{"client_name":"My agent","redirect_uris":["https://example.com/callback"],"grant_types":["authorization_code","refresh_token"],"response_types":["code"],"token_endpoint_auth_method":"none"}'
```

Returns `client_id`. Public clients are supported, so a `client_secret` is
optional. `redirect_uris` must be https, or http on localhost.

## Claim ceremony

There is none, and none is needed: the person is present. Send them to the
authorization endpoint, they sign in with the same login they use for the
app, and they approve your client on a consent screen naming the scope.

```
https://youspot.com/oauth/authorize
  ?response_type=code
  &client_id=<client_id>
  &redirect_uri=<your registered uri>
  &code_challenge=<S256 of your verifier>
  &code_challenge_method=S256
  &state=<opaque>
  &scope=linkedin
```

`code_challenge_method` must be `S256`. Plain PKCE and the implicit flow are
refused.

## Use the credential

```bash
curl -X POST https://youspot.com/oauth/token \
  -d grant_type=authorization_code \
  -d code=<code> \
  -d redirect_uri=<same uri> \
  -d client_id=<client_id> \
  -d code_verifier=<verifier>
```

Then call the MCP endpoint with the access token:

```bash
curl -X POST https://youspot.com/mcp/v1 \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```

`initialize`, `ping` and `tools/list` answer without a credential, so you can
handshake and read the tool list before you have one. `tools/call` needs the
token.

## Errors

| Status | Meaning |
| --- | --- |
| 401 | No token, or an expired or rotated one. The `WWW-Authenticate` header carries `resource_metadata` pointing at the RFC 9728 document. Refresh and retry once. |
| 400 `invalid_grant` | The authorization code was used, expired (60 seconds), or the `code_verifier` does not match the challenge. Start the flow again. |
| 400 `invalid_client` | The `client_id` is unknown. Register again; registrations are not shared across environments. |
| JSON-RPC `-32001` | Authenticated but the tool refused. Read the message; it is not a retry. |

## Revocation

Refresh tokens rotate: every refresh returns a new one and invalidates the
old. Reusing a spent refresh token invalidates the whole grant chain, which
is the intended response to a stolen token, so store only the newest one.

Drop a grant yourself with RFC 7009. Revoking either token kills the pair,
and the response is 200 whether or not the token was live.

```bash
curl -X POST https://youspot.com/oauth/revoke \
  -d token=<access or refresh token> \
  -d client_id=<client_id>
```

A person revokes an agent at https://youspot.com/user/mcp, which kills its grants
immediately.

## Appendix: notes

- Tokens are bearer tokens in the `Authorization` header. Query-string
  credentials are not accepted anywhere.
- The access token is bound to the person who approved it and to the scope
  they approved. It does not widen when they upgrade their plan.
- Tool calls are metered against that person's credit balance. An out of
  credits refusal comes back as a tool error, not an HTTP error, because the
  request was well-formed.
- MCP protocol versions: `2025-06-18` (default) and `2025-03-26`. JSON-RPC
  batching is refused, per the 2025-06-18 spec.
- Human documentation: https://youspot.com/docs/mcp. Site index for agents: https://youspot.com/llms.txt.
