siyuan-note/siyuan · error

OAuth authorization failed

Error message

OAuth authorization failed: %s

What it means

The OAuth redirect back to the local callback endpoint may carry an error parameter (per RFC 6749 section 4.1.2.1, e.g. access_denied, invalid_scope). When the browser callback reports such an error, the flow surfaces it verbatim as 'OAuth authorization failed: <server error>'.

Solutions

  1. Read the error text after the colon to identify the IdP's reason (e.g. access_denied, invalid_scope)
  2. Retry and approve the consent request in the browser
  3. If invalid_scope, align the server's advertised scopes with what the client requests, or grant the client those scopes
  4. If the IdP rejects PKCE or the resource parameter, update/fix the authorization server configuration
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check that requested scopes are within what the resource metadata advertises
for _, s := range requestedScopes {
    if !slices.Contains(prm.ScopesSupported, s) { /* scope will likely be denied */ }
}

Try / catch

if err := h.Authorize(ctx, true); err != nil {
    if strings.HasPrefix(err.Error(), "OAuth authorization failed:") {
        idpErr := strings.TrimPrefix(err.Error(), "OAuth authorization failed: ")
        // branch on access_denied / invalid_scope etc.
    }
}

Prevention

When it happens

Trigger: User completes the authorization redirect but the IdP redirected to the callback with error=... (plus optional error_description), e.g. after the user denied consent or the request was rejected (invalid_scope, access_denied, server_error).

Common situations: User clicked 'Deny'/'Cancel' on the consent screen; the requested scopes are not grantable for this client; the IdP rejected PKCE or the resource parameter; account restrictions on the chosen user.

Related errors


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

Appendix: source

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

	}
	oauthFlows.Lock()
	oauthFlows.items[flowID] = flow
	oauthFlows.Unlock()
	defer removeOAuthFlow(flowID, flow)
	setMCPRuntimeStateForContext(ctx, h.server.ID, "authorizing", 0, "", authorizationURL)

	var callback oauthCallbackResult
	timer := time.NewTimer(oauthAuthorizationTimeout)
	defer timer.Stop()
	select {
	case callback = <-flow.Result:
	case <-ctx.Done():
		return ctx.Err()
	case <-timer.C:
		return fmt.Errorf("OAuth authorization timed out")
	}
	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)
	}

View on GitHub (pinned to 9f775e8a12)