Skip to main content

Authentication (OAuth 2.1 + DCR)

Shuuka MCP uses standard OAuth 2.1 with Dynamic Client Registration (RFC 7591). There is no manual platform whitelisting — any client that can complete DCR + PKCE can authenticate.

Discovery​

All endpoints are advertised at:

GET https://mcp.shuuka.com/.well-known/oauth-authorization-server
GET https://mcp.shuuka.com/.well-known/oauth-protected-resource
GET https://mcp.shuuka.com/.well-known/mcp

You should fetch the OAuth metadata document at startup and treat the URLs in it as the source of truth.

Dynamic Client Registration​

Register your client once. Re-register if your metadata changes.

POST /oauth/register
Content-Type: application/json

{
"client_name": "My MCP Client",
"redirect_uris": ["https://my-app.example/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "none",
"scope": "identity:read links:read links:write analytics:read"
}

Response (excerpted):

{
"client_id": "shk_client_...",
"client_id_issued_at": 1746230400,
"redirect_uris": ["https://my-app.example/callback"],
"token_endpoint_auth_method": "none",
"grant_types": ["authorization_code", "refresh_token"]
}

Public clients (CLI, desktop, mobile) use token_endpoint_auth_method: "none" and must use PKCE. Confidential clients (server-side web apps) receive a client_secret.

Verification status​

Newly registered clients are unverified by default. Unverified clients:

  • Can request read scopes.
  • Cannot request scopes flagged unverified_ok: false.
  • Are subject to the lower per-client rate limits.

To upgrade your client to verified, contact [email protected] with your client_id, your domain, and a brief description of the use case. Verification unlocks write scopes and higher rate limits.

Authorization code flow with PKCE​

Required for all clients (public and confidential).

1. Build the authorize URL​

https://mcp.shuuka.com/oauth/authorize
?response_type=code
&client_id={client_id}
&redirect_uri={url-encoded redirect}
&scope=identity%3Aread+links%3Aread+links%3Awrite
&state={random-csrf-token}
&code_challenge={base64url(sha256(code_verifier))}
&code_challenge_method=S256

The user lands on a Shuuka-branded consent screen showing exactly which scopes you requested and what your client name + URL are.

2. Receive the code​

After approval, Shuuka redirects to your redirect_uri:

https://my-app.example/callback?code=...&state=...

Verify state. Any mismatch is a CSRF attempt — abort.

3. Exchange code for tokens​

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&code={code}
&redirect_uri={redirect}
&client_id={client_id}
&code_verifier={original PKCE verifier}

Response:

{
"token_type": "Bearer",
"expires_in": 3600,
"access_token": "...",
"refresh_token": "...",
"scope": "identity:read links:read links:write"
}

4. Refresh​

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token
&refresh_token={refresh_token}
&client_id={client_id}

5. Revoke​

POST /oauth/revoke
Content-Type: application/x-www-form-urlencoded

token={access_token_or_refresh_token}
&client_id={client_id}

Users can also revoke any client at any time from Settings → Connected agents in their Shuuka account.

Scopes​

Scopes are per-tool-domain and follow the convention <domain>:<verb> (e.g. links:write, analytics:read).

DomainRead scopeWrite scopeMin plan for write
Identityidentity:read——
Linkslinks:readlinks:writePro
Smart routessmart_routes:readsmart_routes:writePro
Collab linkscollab_links:readcollab_links:writePro
Analyticsanalytics:readanalytics:exportPro
Appsapps:readapps:writePro
Themetheme:readtheme:writePro
SEOseo:readseo:writePro
Verificationverification:readverification:requestFree
Trusttrust:readtrust:report:write, trust:reports:manageFree
Webhookswebhooks:readwebhooks:writePro
Goalsgoals:readgoals:writePro
Planplan:read—Free
Vault export—vault:exportPro
Workspace (T3)workspace:read, workspace:analytics:read, workspace:trust:readworkspace:switchEnterprise

Request only the scopes you need. Users are more likely to approve a small, well-scoped client.

Step-up authentication​

A handful of high-impact tools require fresh authentication within a 5-minute window. If the user's last successful auth is older than that, the tool returns:

{
"error": {
"code": "step_up_required",
"data": {
"auth_url": "https://mcp.shuuka.com/oauth/step-up?...",
"expires_at": "..."
}
}
}

Send the user to auth_url. After they re-authenticate (password / passkey), retry the tool call within the window.

Tools that require step-up:

  • request_identity_export
  • request_verification
  • submit_fake_report
  • revert_theme

Token usage​

Send the access token on every JSON-RPC request:

POST / HTTP/1.1
Host: mcp.shuuka.com
Authorization: Bearer {access_token}
Content-Type: application/json

{"jsonrpc":"2.0","id":1,"method":"tools/list"}

If the token is expired or revoked, you receive invalid_token. Refresh and retry.

Idempotency for writes​

Every write tool must include an Idempotency-Key header (a UUID v4 you mint client-side). Server caches the result for 24 hours; replays return the original response.

Idempotency-Key: 7f3c1e2a-...

Omitting it on a write call returns validation_failed.

Next​