Appearance
Authentication
Both the API and the MCP server use OAuth 2.0 with PKCE (S256) and dynamic client registration. The authorization server is the same host as the product.
text
https://app.intangia.coA token is bound to one resource. Ask for the resource you will call:
| Surface | Resource |
|---|---|
| API | https://app.intangia.co/api/v1 |
| MCP | https://app.intangia.co/mcp |
Send the access token as Authorization: Bearer. Access tokens last one hour (expires_in is 3600). Refresh tokens last 30 days.
Scopes
| Scope | What It Allows |
|---|---|
intangia:read | Keywords, projects, signals, opportunities, and assessments |
projects:write | Create and update projects, run setup, and create or list reports |
analyses:run | Start scoring |
The token response lists the scopes that were granted, space-separated.
Discovery
Clients that speak MCP OAuth can discover the server and skip the manual steps below.
text
GET /.well-known/oauth-authorization-server
GET /.well-known/oauth-protected-resource/api/v1
GET /.well-known/oauth-protected-resource/mcpThe authorization server document names these endpoints:
| Endpoint | Path |
|---|---|
| Authorize | /oauth/authorize |
| Token | /oauth/token |
| Register | /oauth/register |
| Revoke | /oauth/revoke |
Supported grant types are authorization_code and refresh_token. The only code challenge method is S256. The token endpoint accepts public clients (token_endpoint_auth_method is none).
Register a Client
POST /oauth/register with JSON.
json
{
"client_name": "Example",
"redirect_uris": ["http://127.0.0.1:8787/callback"]
}Redirect URIs must be https, or loopback HTTP (localhost, 127.0.0.1, [::1]). A 201 response includes client_id. There is no client secret.
Too many registrations from one address return 429 with error slow_down.
Authorize
Send the user to /oauth/authorize.
| Parameter | Value |
|---|---|
response_type | code |
client_id | From registration |
redirect_uri | One registered URI |
code_challenge | Base64url SHA-256 of the verifier |
code_challenge_method | S256 |
resource | The API or MCP resource |
scope | Space-separated scopes |
state | A value you check on return |
The user signs in and approves. The redirect carries code and state. Authorization codes last 60 seconds and can be used once.
Exchange the Code
POST /oauth/token with Content-Type: application/x-www-form-urlencoded.
text
grant_type=authorization_code
&code=...
&client_id=...
&redirect_uri=...
&code_verifier=...
&resource=https://app.intangia.co/api/v1resource must be exactly the API or MCP resource. A mismatch returns invalid_target.
json
{
"access_token": "...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "...",
"scope": "intangia:read projects:write analyses:run"
}The response is cache-control: no-store.
Refresh with grant_type=refresh_token, refresh_token, and client_id. You may send resource again. Each refresh rotates the refresh token.
Revoke
POST /oauth/revoke with the token to cancel. Revoking is how a user disconnects a client.
Call the API
bash
curl "https://app.intangia.co/api/v1/projects" \
-H "Authorization: Bearer $TOKEN"$TOKEN must have been issued for https://app.intangia.co/api/v1.
Errors
OAuth errors use error and error_description.
| Status | error | When |
|---|---|---|
| 400 | invalid_client_metadata | Registration body is not JSON, or no acceptable redirect URI |
| 400 | invalid_target | resource is not the API or MCP resource |
| 400 | invalid_grant | Code or refresh token is missing, expired, reused, or PKCE fails |
| 400 | unsupported_grant_type | grant_type is not authorization_code or refresh_token |
| 429 | slow_down | Too many registrations |
API and MCP HTTP errors use a different body. See the API overview.