siyuan-note/siyuan · error

OAuth token endpoint returned unsupported token type %q

Error message

OAuth token endpoint returned unsupported token type %q

What it means

Returned at oauth.go:402-403 when the token exchange succeeded but token.TokenType is non-empty and not 'Bearer' (case-insensitive). SiYuan's storedOAuthTokenSource produces Bearer-bearing requests, so non-Bearer token types (DPoP, mac, N_A) cannot be used.

Source

Thrown at kernel/mcp/client/oauth.go:403

	if callback.Error != "" {
		return fmt.Errorf("OAuth authorization failed: %s", callback.Error)
	}
	if callback.State != state {
		return fmt.Errorf("OAuth state mismatch")
	}
	if callback.Code == "" {
		return fmt.Errorf("OAuth callback did not include an authorization code")
	}

	exchangeCtx := context.WithValue(ctx, oauth2.HTTPClient, h.client)
	token, err := config.Exchange(exchangeCtx, callback.Code,
		oauth2.VerifierOption(verifier),
		oauth2.SetAuthURLParam("resource", prm.Resource))
	if err != nil {
		return fmt.Errorf("exchange OAuth authorization code: %w", err)
	}
	if token.TokenType != "" && !strings.EqualFold(token.TokenType, "Bearer") {
		return fmt.Errorf("OAuth token endpoint returned unsupported token type %q", token.TokenType)
	}
	credential = registrationCredential
	credential.TokenAuthMethod = authMethod
	credential.AccessToken = token.AccessToken
	credential.RefreshToken = token.RefreshToken
	credential.TokenType = token.TokenType
	credential.Expiry = token.Expiry
	credential.Scopes = scopes
	credential.Rejected = false
	if err = putOAuthCredential(credential); err != nil {
		return fmt.Errorf("save OAuth credentials: %w", err)
	}
	h.sourceMu.Lock()
	h.source = &storedOAuthTokenSource{credential: credential, client: h.client}
	h.sourceMu.Unlock()
	setMCPRuntimeStateForContext(ctx, h.server.ID, "oauth_retrying", 0, "", "")
	return nil
}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Configure the AS to issue Bearer tokens (token_type='Bearer') for this client.
  2. If sender-constrained tokens are mandatory, use a different AS or a proxy that terminates the constraint and re-issues Bearer tokens.
  3. Verify the registration requested a compatible token_endpoint_auth_method (none/client_secret_post/client_secret_basic).
Defensive patterns

Strategy: validation

Try / catch

if token.TokenType != "" && !strings.EqualFold(token.TokenType, "Bearer") {
    // Non-retriable: AS issues sender-constrained tokens. Surface and stop.
    return fmt.Errorf("OAuth token endpoint returned unsupported token type %q", token.TokenType)
}

Prevention

When it happens

Trigger: The token endpoint's JSON response has "token_type":"DPoP" or similar. SiYuan checks token.TokenType != "" && !EqualFold(...,"Bearer") and rejects it before saving.

Common situations: AS enforces sender-constrained tokens (DPoP, mTLS-bound); AS returns a non-standard token_type string; AS bug returning the wrong type for the requested method.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/466d789b14739c2d. Report an issue: GitHub.