Environment: @1mcp/agent v0.34.4, Node v22.14.0, Windows 11
Summary: GET /.well-known/oauth-authorization-server advertises "grant_types_supported":["authorization_code","refresh_token"], and Dynamic Client Registration accepts clients that request refresh_token in their grant_types. But exchangeAuthorizationCode() (build/auth/sdkOAuthServerProvider.js:254-303) never includes a refresh_token field in its response, and exchangeRefreshToken() (same file, lines 304-309) is unconditional:
async exchangeRefreshToken(_client, _refreshToken, _scopes, _resource) {
throw new Error('Refresh tokens not supported');
}
This plain Error isn't one of the SDK's OAuthError subclasses, so it surfaces to clients as a raw 500 Internal Server Error instead of a spec-compliant 400 invalid_grant. Any OAuth client that follows the advertised metadata and later attempts a token refresh (which any client holding a token past its TTL will eventually need to do) gets an opaque server error instead of a clean re-auth signal.
Steps to reproduce (pure curl, no client library needed):
POST /register {token_endpoint_auth_method:"none", grant_types:["authorization_code","refresh_token"]}
→ 201, client_id issued (no client_secret, as expected for a public/PKCE client)
GET /authorize?client_id=...&code_challenge=...&code_challenge_method=S256&redirect_uri=...&scope=...
→ 200, consent page HTML
POST /oauth/consent auth_request_id=...&action=approve&scopes=...
→ 302 Location: <redirect_uri>?code=...&state=...
POST /token grant_type=authorization_code, code=..., code_verifier=..., client_id=... (no client_secret)
→ 200 OK, access_token issued — but no refresh_token field in the response at all
POST /token grant_type=refresh_token, refresh_token=<any value>, client_id=...
→ 500 Internal Server Error {"error":"server_error","error_description":"Internal Server Error"}
Suggested fix: Either implement exchangeRefreshToken properly (store/rotate a refresh token issued during exchangeAuthorizationCode, and throw the SDK's InvalidGrantError for bad/missing tokens so it maps to a proper 400 response), or if refresh is intentionally unsupported, remove refresh_token from grant_types_supported in the discovery metadata and from registration echoes, so clients don't rely on a capability that silently fails with an opaque 500.
Found while debugging why OpenAI Codex CLI's OAuth session against a local 1mcp instance stopped working shortly after initial authorization — its client library reported a generic "grant not found" style error on refresh, which traces back to this.
Environment: @1mcp/agent v0.34.4, Node v22.14.0, Windows 11
Summary:
GET /.well-known/oauth-authorization-serveradvertises"grant_types_supported":["authorization_code","refresh_token"], and Dynamic Client Registration accepts clients that requestrefresh_tokenin theirgrant_types. ButexchangeAuthorizationCode()(build/auth/sdkOAuthServerProvider.js:254-303) never includes arefresh_tokenfield in its response, andexchangeRefreshToken()(same file, lines 304-309) is unconditional:This plain
Errorisn't one of the SDK'sOAuthErrorsubclasses, so it surfaces to clients as a raw500 Internal Server Errorinstead of a spec-compliant400 invalid_grant. Any OAuth client that follows the advertised metadata and later attempts a token refresh (which any client holding a token past its TTL will eventually need to do) gets an opaque server error instead of a clean re-auth signal.Steps to reproduce (pure curl, no client library needed):
Suggested fix: Either implement
exchangeRefreshTokenproperly (store/rotate a refresh token issued duringexchangeAuthorizationCode, and throw the SDK'sInvalidGrantErrorfor bad/missing tokens so it maps to a proper 400 response), or if refresh is intentionally unsupported, removerefresh_tokenfromgrant_types_supportedin the discovery metadata and from registration echoes, so clients don't rely on a capability that silently fails with an opaque 500.Found while debugging why OpenAI Codex CLI's OAuth session against a local 1mcp instance stopped working shortly after initial authorization — its client library reported a generic "grant not found" style error on refresh, which traces back to this.