siyuan-note/siyuan · error

validate OAuth issuer

Error message

validate OAuth issuer: %w

What it means

validateCredentialIssuer wraps a failure from auth.GetAuthServerMetadata (fetching the authorization server's RFC 8414 metadata) with the 'validate OAuth issuer' prefix. The protected resource metadata was fetched fine, but its first listed authorization server's metadata could not be retrieved, so the stored issuer/token endpoint could not be compared.

Solutions

  1. Check that the authorization server URL from the resource metadata is reachable and publishes its metadata well-known document.
  2. Verify the IdP issuer has not changed after an upgrade; if it has, re-run the OAuth authorize flow to store the new issuer.
  3. Retry on transient network errors — the credential remains stored and valid once the IdP is back.
  4. If the resource metadata lists multiple authorization servers, note only the first is tried; update server config to list the intended one first.
  5. Inspect the wrapped error for the underlying HTTP/TLS cause.

Example fix

// before: metadata lists stale IdP
{"authorization_servers": ["https://old-idp.example.com"]}
// after: update resource metadata to current issuer
{"authorization_servers": ["https://auth.example.com"]}
Defensive patterns

Strategy: retry

Validate before calling

asm, err := auth.GetAuthServerMetadata(ctx, authServerURL, client)
if err != nil {
    // authorization server unreachable; check IdP health before revalidation
}

Try / catch

asm, err := auth.GetAuthServerMetadata(ctx, prm.AuthorizationServers[0], h.client)
if err != nil {
    log.Warn("issuer revalidation deferred", "err", err)
    return true, nil // keep credential, revalidate later
}

Prevention

When it happens

Trigger: TokenSource -> validateCredentialIssuer. Thrown when GetAuthServerMetadata against prm.AuthorizationServers[0] errors: the authorization server's /.well-known/oauth-authorization-server endpoint is unreachable, 404s, returns malformed JSON, or TLS fails.

Common situations: The authorization server (IdP) is down or migrated to a new issuer URL; the resource metadata lists a stale authorization-server URL; corporate proxy blocks the IdP domain; IdP disabled its well-known discovery endpoint.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/aecc6af639ce4400. Report an issue: GitHub.

Appendix: source

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

}

func (h *mcpOAuthHandler) validateCredentialIssuer(ctx context.Context, credential oauthCredential) (bool, error) {
	var challenges []oauthex.Challenge
	resource := h.server.URL
	if credential.ResourceMetadataURL != "" {
		challenges = []oauthex.Challenge{{Scheme: "bearer", Params: map[string]string{"resource_metadata": credential.ResourceMetadataURL}}}
		resource = credential.Resource
	}
	prm, err := discoverProtectedResource(ctx, challenges, resource, h.client)
	if err != nil {
		return false, fmt.Errorf("validate OAuth protected resource: %w", err)
	}
	if prm.Resource != credential.Resource || len(prm.AuthorizationServers) == 0 {
		return false, nil
	}
	asm, err := auth.GetAuthServerMetadata(ctx, prm.AuthorizationServers[0], h.client)
	if err != nil {
		return false, fmt.Errorf("validate OAuth issuer: %w", err)
	}
	return asm != nil && asm.Issuer == credential.Issuer && asm.TokenEndpoint == credential.TokenEndpoint, nil
}

func protectedResourceURLs(metadataURL, resource string) []protectedResourceURL {
	var result []protectedResourceURL
	if metadataURL != "" {
		result = append(result, protectedResourceURL{URL: metadataURL, Resource: resource})
	}
	resourceURL, err := url.Parse(resource)
	if err != nil {
		return result
	}
	metadata := *resourceURL
	metadata.RawPath = ""
	metadata.RawQuery = ""
	metadata.Fragment = ""
	metadata.Path = "/.well-known/oauth-protected-resource/" + strings.TrimLeft(resourceURL.Path, "/")

View on GitHub (pinned to 9f775e8a12)