OAuth Endpoints
The Perspective API exposes four endpoints to support the MCP authorization flow. Two are standard OAuth2 discovery documents; one proxies the authorization redirect to Auth0; one handles dynamic client registration.
All endpoints are on the base URL https://api.perspective.co.
GET /.well-known/oauth-protected-resource
Returns the OAuth 2.0 Protected Resource Metadata document for the MCP endpoint. MCP clients fetch this after receiving a 401 response with a WWW-Authenticate: Bearer resource_metadata="..." header.
Response (200 application/json):
| Field | Value |
|---|---|
resource | The base URL of the protected resource (e.g. https://api.perspective.co) |
authorization_servers | Array containing the same base URL — indicates this server also hosts the authorization-server metadata |
scopes_supported | ["offline_access"] |
bearer_methods_supported | ["header"] |
Example response:
{
"resource": "https://api.perspective.co",
"authorization_servers": ["https://api.perspective.co"],
"scopes_supported": ["offline_access"],
"bearer_methods_supported": ["header"]
}
The resource and authorization_servers values are derived from the request host (or from the MCP_BASE_URL environment variable if set). In production this is https://api.perspective.co.
GET /.well-known/oauth-authorization-server
Returns the OAuth 2.0 Authorization Server Metadata document. MCP clients use this to discover all the endpoints they need for the authorization-code flow.
Response (200 application/json):
| Field | Value |
|---|---|
issuer | The Auth0 tenant domain (e.g. https://<auth0-tenant>.auth0.com/) |
authorization_endpoint | https://api.perspective.co/oauth/authorize |
token_endpoint | https://<auth0-tenant>.auth0.com/oauth/token |
jwks_uri | https://<auth0-tenant>.auth0.com/.well-known/jwks.json |
registration_endpoint | https://api.perspective.co/oauth/register |
response_types_supported | ["code"] |
grant_types_supported | ["authorization_code", "refresh_token"] |
token_endpoint_auth_methods_supported | ["none"] — public clients; no client secret required |
code_challenge_methods_supported | ["S256"] — PKCE required |
scopes_supported | ["offline_access"] |
Example response:
{
"issuer": "https://<auth0-tenant>.auth0.com/",
"authorization_endpoint": "https://api.perspective.co/oauth/authorize",
"token_endpoint": "https://<auth0-tenant>.auth0.com/oauth/token",
"jwks_uri": "https://<auth0-tenant>.auth0.com/.well-known/jwks.json",
"registration_endpoint": "https://api.perspective.co/oauth/register",
"response_types_supported": ["code"],
"grant_types_supported": ["authorization_code", "refresh_token"],
"token_endpoint_auth_methods_supported": ["none"],
"code_challenge_methods_supported": ["S256"],
"scopes_supported": ["offline_access"]
}
The token_endpoint and jwks_uri point directly to Auth0. The authorization_endpoint and registration_endpoint point to the Perspective API proxy (described below). The Auth0 tenant domain comes from the AUTH0_DOMAIN environment variable.
GET /oauth/authorize
Proxies the OAuth2 authorization redirect to Auth0. MCP clients redirect the user's browser here; the server appends the required Auth0 audience and connection parameters and issues a 302 redirect to the Auth0 /authorize endpoint.
Query parameters:
All standard OAuth2 authorization parameters are accepted and forwarded (client_id, redirect_uri, response_type, scope, state, code_challenge, code_challenge_method, etc.). The server adds:
| Parameter added by server | Source |
|---|---|
audience | AUTH0_AUDIENCE env var |
connection | AUTH0_CONNECTION env var |
Response: 302 redirect to https://<auth0-tenant>.auth0.com/authorize?<all-params>.
Purpose: MCP clients discover this endpoint from the authorization_endpoint field in the authorization-server metadata. By routing through the Perspective API rather than pointing directly at Auth0, the server can inject the correct audience and connection values that clients do not know.
POST /oauth/register
Implements OAuth 2.0 Dynamic Client Registration. MCP clients that do not have a pre-registered client_id call this endpoint to obtain one.
Request body (application/json):
| Field | Required | Description |
|---|---|---|
redirect_uris | Yes | Non-empty array of redirect URI strings |
Response (201 application/json):
| Field | Value |
|---|---|
client_id | The shared OAuth client ID (from OAUTH_CLIENT_ID env var) |
client_name | "Perspective MCP Client" |
redirect_uris | The redirect_uris array from the request, echoed back |
grant_types | ["authorization_code", "refresh_token"] |
response_types | ["code"] |
token_endpoint_auth_method | "none" — public client; no secret issued |
Error response (400 application/json):
If redirect_uris is missing or not a non-empty array:
{ "error": "redirect_uris must be a non-empty array" }
Example request:
{
"redirect_uris": ["http://localhost:8080/callback"]
}
Example response:
{
"client_id": "<oauth-client-id>",
"client_name": "Perspective MCP Client",
"redirect_uris": ["http://localhost:8080/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none"
}
All dynamic registrations receive the same client_id. This is a single public client registration rather than per-client issuance. No client_secret is returned because the client is public (token_endpoint_auth_method: "none").
401 behavior on the MCP endpoint
This is not itself an OAuth endpoint, but it is the entry point for the entire flow. When POST https://api.perspective.co/mcp receives a request with no token or an invalid token, it returns:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://api.perspective.co/.well-known/oauth-protected-resource"
If a token was present but failed validation the header also includes:
WWW-Authenticate: Bearer resource_metadata="...", error="invalid_token", error_description="Invalid token"
The resource_metadata URL is what triggers the MCP client to begin the discovery and authorization flow described in OAuth Overview.
Summary
| Method | Path | Purpose |
|---|---|---|
GET | /.well-known/oauth-protected-resource | Protected-resource metadata; entry point for client discovery |
GET | /.well-known/oauth-authorization-server | Authorization-server metadata; lists all OAuth endpoints |
GET | /oauth/authorize | Proxies authorization redirect to Auth0, injecting audience + connection |
POST | /oauth/register | Dynamic client registration; returns shared client_id |