Authentication
OAuth 2.1 with PKCE and dynamic client registration, organization-scoped tokens, roles, scopes, lifetimes, and revocation.
The Vidext Operator MCP server authenticates with OAuth 2.1: authorization code with PKCE, plus dynamic client registration. There are no long-lived API keys. Clients register themselves, a person authorizes in the browser, and tokens are short-lived and bound to one organization.
The OAuth issuer is:
https://app.vidext.com/api/authThe flow (what your client does for you)
Challenge
The first request without a valid token gets HTTP 401 with a WWW-Authenticate: Bearer challenge. Its resource_metadata points at the protected-resource document for this endpoint, /.well-known/oauth-protected-resource/api/mcp/operator.
Discovery
The protected-resource document names the authorization server. Its metadata is one document served at several paths (see the table below), so a client that starts from the issuer and one that reads the root path get the same answer.
Registration
A client without credentials registers itself at /api/auth/oauth2/register. Registration needs no prior account. A client can instead use an HTTPS URL that serves its client metadata document as its client_id.
Authorization
The browser opens /api/auth/oauth2/authorize. The person signs in, reviews the consent screen, and, if they are an admin or member in more than one organization, chooses one. The choice is bound to this authorization.
Tokens
The client exchanges the code and its PKCE verifier at /api/auth/oauth2/token. Refreshed tokens keep the same organization.
Endpoint reference
| Endpoint | Path |
|---|---|
| Authorization server metadata | /.well-known/oauth-authorization-server, also at /.well-known/oauth-authorization-server/api/auth (derived from the issuer, RFC 8414) and /api/auth/.well-known/oauth-authorization-server |
| OpenID configuration | /.well-known/openid-configuration, also at /.well-known/openid-configuration/api/auth and /api/auth/.well-known/openid-configuration |
| Protected resource metadata | /.well-known/oauth-protected-resource/api/mcp/operator (the one the challenge names) and /.well-known/oauth-protected-resource |
| Dynamic client registration | /api/auth/oauth2/register |
| Authorize | /api/auth/oauth2/authorize |
| Token | /api/auth/oauth2/token |
| Revocation | /api/auth/oauth2/revoke |
| User info | /api/auth/oauth2/userinfo |
| JWKS (OAuth issuer) | /api/auth/jwks |
Two JWKS endpoints exist
/api/auth/jwks is the OAuth issuer's key set. The separate /.well-known/jwks.json serves the LMS (LTI) integration. Do not confuse them.
Who can connect
Only organization admins and members can use the server.
- At authorization, the organization chooser lists only organizations where the person is an admin or member. Someone with neither role anywhere is refused with
403. - On every tool call, the server checks the role again. A person who is removed from the organization, or whose role changes to learner, gets the tool error
forbiddenfrom their next call, and their next token refresh is refused. - Learners and requesters (people whose request to join is still pending) cannot connect.
Admins and members see the same data over MCP: every module in the organization and the organization's processed sources. There is no per-team filtering for these two roles. See roles and permissions.
Organization scoping
A token is bound to one person in one organization, fixed at authorization. It stays bound if the person later switches workspace in the app. To work in another organization, authorize again.
Every tool accepts optional organizationSlug and organizationId arguments. Leave them out and the call uses the token's organization. Passing a different organization is refused with organization_scope_mismatch; passing an id and a slug that name different organizations is refused with invalid_organization_selector.
Scopes
| Scope | What it grants |
|---|---|
mcp:operator.read | Every tool the server exposes. All of them are reads. Request this one. |
mcp:operator.write | Accepted for compatibility. It grants the same read tools; no tool needs it. |
A token with neither scope is refused with 403 and insufficient_scope. The server also supports the standard openid, profile, email, and offline_access scopes for sign-in and refresh.
Tokens
- Access tokens are signed JWTs (
typ: at+jwt) that last one hour. Their audience is the MCP endpoint URL, so a token minted for one origin is not accepted on another. - Refresh tokens last 30 days. Each refresh issues a new pair bound to the same organization, after checking the person still holds an admin or member role there.
- Sender-constrained (DPoP) tokens are not accepted.
- Web app session cookies are not accepted as bearer tokens. Only the OAuth flow, or the headless path below, mints a valid token.
Revocation
- From your client. Remove the connection in your AI client. A client can also revoke its refresh token at
/api/auth/oauth2/revoke, which stops further refreshes. - From Vidext. There is no "disconnect" control in Vidext's settings today. Removing the person from the organization, or changing their role to learner, stops their tool calls on the next call and blocks the next refresh.
- An access token that was already issued stays cryptographically valid until it expires (at most one hour), but every call re-checks the person's role.
When a token expires or is refused, the server answers 401 again and well-behaved clients re-run the flow.
Headless agents
For an agent with no browser, /auth.md describes an email-verified registration on behalf of an existing Vidext user:
POST /api/agent/authwith the user's email. Vidext emails them a six-digit code, valid for 10 minutes, and returns a claim token.POST /api/agent/auth/claim/completewith the claim token and the code (five attempts). If the user is in more than one organization, the response asks the agent to retry with anorganization_id.- The response carries an access token valid for 7 days, with both operator scopes. There is no refresh token: when it expires or a call returns
401, register again.
Both POST endpoints accept an Idempotency-Key header (kept 24 hours) and are rate-limited per IP: 60 registrations and 30 completions per hour. The same role rule applies on every tool call. Interactive OAuth is the recommended path; this one exists for agents that cannot open a browser.
Last updated on