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
- Check that the authorization server URL from the resource metadata is reachable and publishes its metadata well-known document.
- Verify the IdP issuer has not changed after an upgrade; if it has, re-run the OAuth authorize flow to store the new issuer.
- Retry on transient network errors — the credential remains stored and valid once the IdP is back.
- If the resource metadata lists multiple authorization servers, note only the first is tried; update server config to list the intended one first.
- 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
- Monitor IdP availability; revalidation depends on its well-known endpoint
- Pin and periodically verify the issuer URL against the IdP's published metadata
- Update resource metadata promptly when authorization servers migrate
- Keep only the intended authorization server first in the metadata list
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
- discover OAuth authorization server
- OAuth protected resource metadata not found
- validate OAuth protected resource
- OAuth authorization server metadata not found
- OAuth protected resource metadata has no authorization…
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)