Skip to main content

Authentication

The MCP server accepts a Bearer token in the Authorization header, and nothing else — no cookie, no client certificate.

:::warning Never in the URL A token in the query string (?access_token=…, or parameters such as token and api_key) does not authenticate, even next to a valid header: the request is answered 401 with error="invalid_request" in WWW-Authenticate. A token in the URL leaks into proxy and CDN logs, Referer and browser history — the MCP authorization spec and RFC 6750 forbid it. :::

That token is an OAuth 2.1 access token issued by the Kobana authorization server (https://account.kobana.com.br): an RS256-signed JWT issued for this resource, whose aud is https://mcp.dashboards.kobana.com.br. It arrives one of two ways — the OAuth flow, run by the client itself, or a personal token you create in your Kobana account — and it is verified the same way in both cases.

Authorization: Bearer eyJhbGciOiJSUzI1NiIs…

:::info Each surface has its own audience A token issued for the MCP server is not valid on the REST API (api.dashboards.*), and an API token is not valid here. That is what stops a token handed to an assistant from being reused against the API — and the other way round. :::

Two ways to connect​

OAuth flowPersonal token
How you get itPaste the URL into the client; it opens the Kobana sign-in and you authorizeCreate it at Kobana account → Tokens and Access → New Personal Token: app Magic Dashboard, usage MCP, resources and access, validity
How the client uses itOn its own, after you authorizeYou paste it into the client as Authorization: Bearer <token>
Validity30 minutes, renewed by the client7 days to 1 year, your choice
ScopeAccess level only — read, todayThe resources and access you selected
Good forClaude, ChatGPT, IDEs and any client with OAuthClients without OAuth support, scripts and automations

The personal token has to be created with the MCP usage. A token created for the REST API carries the API's audience and is refused here with 401 — and the reverse holds too.

The OAuth flow​

You run none of these steps: the MCP client (Claude, ChatGPT, an IDE) does all of it on its own, starting from the URL. They are here for when something fails halfway.

  1. Challenge. A request without a token gets 401 with the challenge every OAuth 2.1 resource server must send (RFC 9728):

    WWW-Authenticate: Bearer realm="kobana-dashboards-mcp",
    error="invalid_token",
    resource_metadata="https://mcp.dashboards.kobana.com.br/.well-known/oauth-protected-resource"
  2. Resource metadata. The client reads the document it points at. It is public and carries no secret — only pointers:

    curl https://mcp.dashboards.kobana.com.br/.well-known/oauth-protected-resource
    {
    "resource": "https://mcp.dashboards.kobana.com.br",
    "authorization_servers": ["https://account.kobana.com.br"],
    "bearer_methods_supported": ["header"],
    "resource_documentation": "https://docs.dashboards.kobana.com.br"
    }
  3. Authorization server metadata (RFC 8414), at https://account.kobana.com.br/.well-known/oauth-authorization-server.

  4. Dynamic client registration (RFC 7591). The client registers itself; the consent screen warns that it is not a verified app.

  5. Authorization with PKCE and resource (RFC 8707). You sign in to Kobana, pick the organization (if you have more than one) and authorize.

  6. Token. The client exchanges the code for a short-lived access token and sends it on every request, refreshing it when it expires.

The token carries who you are (sub) and the organization you authorized (org). org is what scopes the data — no tool takes an organization as an argument. A token whose organization does not exist in Magic Dashboard gets 403 unknown_organization.

Authorization: the permissions of whoever authorized​

What a caller sees is narrower than the catalog: tools are filtered by the dashboard permissions of the person who authorized the client, in that organization, resolved on every request. The ceiling is always what that person can do in the UI.

SituationResult
The person is not a member of the organizationDenies every tool (key_owner_not_member). Authorize again with an account that belongs to the organization.
Active membershipThe person's permissions and roles, applied tool by tool. owner and the * wildcard open everything; portal-users.* opens the family.
Membership suspended, removed, or with no roleDenies every tool (membership_inactive).
The permission lookup failsDenies every tool. Fail closed.

Permissions are read on every call, so revoking a role in the dashboard takes effect on the very next tool, without waiting for the token to expire.

A tool the caller cannot run is not listed by tools/list. When tools/call refuses, the code says who fixes it:

CodeWho fixes it
insufficient_scopeUsing a token that reaches the resource with the access requested — for example, a personal token with write access to it.
insufficient_permissionAn organization admin, granting the permission (the error names which).
membership_inactiveReinstating the person — no permission fixes a dead membership.
key_owner_not_memberAuthorizing again with an account that is a member of the organization.

:::tip Recommended posture for agents Authorize the client with an account that holds only the permissions the agent needs. A client authorized by a read-only analyst exposes only the read tools, whatever the model on the other end does. :::

Token scope​

On top of permissions, the MCP server applies the scope the token carries, in the scope claim. The two checks add up: a tool only shows up if both allow it. Reading is a read tool, a resource, a read prompt and a completion; writing is everything else, destructive tools included.

Token with resources — the personal-token case. The resources define how far the token reaches, and read/write apply only within them:

Token scopeResult
dashboards/users dashboards/members read writeReads and writes portal users and team members (with their roles) — and nothing else
dashboards/users readOnly reads portal users
dashboards/all readReads everything, writes nothing

A resource outside the ten groups is reachable only with dashboards/all. delete, import and export on their own do not count as writing.

Token without resources — the OAuth-flow case. Only the access level applies: reading with read, write or all; writing with write or all.

:::info Clients connected through the OAuth flow are read-only The authorization server grants only read to dynamically registered clients — Claude, ChatGPT, the MCP Inspector, IDEs. For them, the MCP server lists only the read tools, and a tool that writes returns insufficient_scope. For an agent to write today, use a personal token with write access to the resources it needs. :::

The same rule applies to the REST API, with the resource taken from the path: a token without write access to the resource gets 403 insufficient_scope on any method other than GET.

Personal token revocation​

Revoking a personal token in your Kobana account does not cut access right away: Magic Dashboard verifies the token on its own, without asking Kobana on every call, and it keeps being accepted until it expires. So:

  • pick the shortest validity the use allows;
  • select only the resources and access the agent needs;
  • to cut an agent off immediately, suspend or remove the person's membership in the organization — permissions are read on every call and take effect at once.

Failure modes​

HTTPcodeCause
400-32022 (JSON-RPC)Unsupported protocol version, in the MCP-Protocol-Version header or in _meta; data.supported lists the supported ones. See Transport.
401UNAUTHORIZEDToken missing, malformed, invalid, expired, or issued for another resource (for example, the REST API).
403unknown_organizationThe token is valid, but the organization it names does not exist in Magic Dashboard.
403FORBIDDENOrigin outside the allow-list (origin_not_allowed).
404NOT_FOUNDThe request arrived through a host that does not serve MCP.
429TOO_MANY_REQUESTSRate limit reached — see Rate limit.
503SERVICE_UNAVAILABLEWe could not reach the authorization server to verify the token. It is on our side: retry after Retry-After.

Every 401 carries the WWW-Authenticate challenge above, which sends the client back into the OAuth flow.

Permission denials are not HTTP errors: they come back as a tool result flagged isError, so the model can read them and react — see Errors.

Host and edge​

/mcp must be reachable only through mcp.dashboards.* — never through the app host, never through the API host, whose distributions point at the same origin. Any other path answers 404: the endpoint does not advertise that it exists somewhere else.

The OAuth resource identifier — and therefore the audience the token must carry — is derived from the server configuration, never from the request Host, so a forged Host cannot steer a client to a different identifier.