OAuth 2.1 client for Model Context Protocol servers (spec 2025-06-18).
Flow — on HTTP 401 from an MCP server, we:
WWW-Authenticate: Bearer resource_metadata="..." (RFC 9728),
fall back to ${origin}/.well-known/oauth-protected-resource;authorization_servers[0];.well-known/oauth-authorization-server (RFC 8414) or
.well-known/openid-configuration for endpoints + capabilities;client_id;http://127.0.0.1:<ephemeral>/mcp-callback) — spawn a one-shot
com.sun.net.httpserver.HttpServer, print the URL, best-effort open
it in the user's browser, wait for ?code=;~/.vis/mcp-tokens/<server>.edn;com.blockether.vis.internal.oauth/make-file-refresher.The returned bearer-fn is a 0/1-arg function: 0-arg yields the current
bearer token (running the auth flow on first use); 1-arg (with the token the
server just rejected) forces a refresh.
OAuth 2.1 client for Model Context Protocol servers (spec `2025-06-18`).
Flow — on HTTP 401 from an MCP server, we:
1. read `WWW-Authenticate: Bearer resource_metadata="..."` (RFC 9728),
fall back to `${origin}/.well-known/oauth-protected-resource`;
2. GET the resource-metadata JSON → pick an `authorization_servers[0]`;
3. GET its `.well-known/oauth-authorization-server` (RFC 8414) or
`.well-known/openid-configuration` for endpoints + capabilities;
4. dynamic-client-register (RFC 7591) if the AS supports it, or use
the caller-supplied `client_id`;
5. run PKCE S256 authorization-code with a loopback redirect
(`http://127.0.0.1:<ephemeral>/mcp-callback`) — spawn a one-shot
`com.sun.net.httpserver.HttpServer`, print the URL, best-effort open
it in the user's browser, wait for `?code=`;
6. exchange code → access + refresh tokens; persist to
`~/.vis/mcp-tokens/<server>.edn`;
7. on later expiry / 401, refresh the token single-flight through
`com.blockether.vis.internal.oauth/make-file-refresher`.
The returned `bearer-fn` is a 0/1-arg function: 0-arg yields the current
bearer token (running the auth flow on first use); 1-arg (with the token the
server just rejected) forces a refresh.(forget! server-name)Drop persisted tokens for server-name (e.g. on mcp__disconnect, or when a
401 recurs after refresh).
Drop persisted tokens for `server-name` (e.g. on `mcp__disconnect`, or when a 401 recurs after refresh).
(make-bearer-fn server-name server-url www-auth-atom auth-hint)Build a 0/1-arg fn returning the current Bearer token string for server-name.
On first use (no cached tokens) OR when called with the just-rejected token,
it runs the OAuth flow / refresh under a single-flight lock and persists the
new tokens. server-url is the MCP endpoint. www-auth-atom is an atom the
HTTP transport keeps updated with the latest WWW-Authenticate header (so we
discover from the LIVE 401). auth-hint is user config from :mcp :servers <name> :auth.
Build a 0/1-arg fn returning the current Bearer token string for `server-name`. On first use (no cached tokens) OR when called with the just-rejected token, it runs the OAuth flow / refresh under a single-flight lock and persists the new tokens. `server-url` is the MCP endpoint. `www-auth-atom` is an atom the HTTP transport keeps updated with the latest `WWW-Authenticate` header (so we discover from the LIVE 401). `auth-hint` is user config from `:mcp :servers <name> :auth`.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |